使用selenium和pyquery爬取京东商品列表过程解析


Posted in Python onAugust 15, 2019

今天一起学起使用selenium和pyquery爬取京东的商品列表。本文的所有代码是在pycharm IDE中完成的,操作系统window 10。

1、准备工作

安装pyquery和selenium类库。依次点击file->settings,会弹出如下的界面:

使用selenium和pyquery爬取京东商品列表过程解析

然后依次点击:project->project Interpreter->"+",,如上图的红色框所示。然后会弹出下面的界面:

使用selenium和pyquery爬取京东商品列表过程解析

输入selenium,在结果列表中选中“selenium”,点击“install package”按钮安装selenium类库。pyquery也是一样的安装方法。

安装chrome和chrome driver插件。chrome dirver插件下载地址:http://npm.taobao.org/mirrors/chromedriver/。 切记chrome和chrome dirver的版本要一致。我的chrome版本是70,对应chrome driver是2.44,2.43,2.42。

下载chrome driver解压后,将exe文件拷贝到pycharm开发空间的Scripts文件夹中:

使用selenium和pyquery爬取京东商品列表过程解析

2、分析要爬取的页面

这次是爬取京东图书中计算机书籍类书籍的信息。

打开chrome,打开开发者工具,输入www.jd.com,分析查询输入框和查询按钮的css代码:

使用selenium和pyquery爬取京东商品列表过程解析

通过分析发现,搜索框的css代码是id=“key”,查询按钮的css代码是class=“button”。下面是使用selenium调用chrome浏览器在搜索框输入关键词“计算机书籍”并点击查询按钮出发查询请求的代码:

from selenium import webdriver
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from pyquery import PyQuery as pq

#通过Chrome()方法打开chrome浏览器
browser = webdriver.Chrome()
#访问京东网站
browser.get("https://www.jd.com")
#等待50秒
wait = WebDriverWait(browser, 50)
#通过css选择器的id属性获得输入框
input = browser.find_element_by_id('key')
#在输入框中写入要查询的信息
input.send_keys('计算机书籍')
#获取查询按钮
submit_button = browser.find_element_by_class_name('button')
#点击查询按钮
submit_button.click()

上面代码成功启动chrome浏览器,自动完成在搜索框中输入关键词并点击查询按钮的操作。

点击完查询按钮之后,会加载出符合条件的书籍,如下图所示:

使用selenium和pyquery爬取京东商品列表过程解析

鼠标往下滚动到达网页底部时,会看到分页的界面:

使用selenium和pyquery爬取京东商品列表过程解析

下一步要做的工作就是分析商品列表页和分页的css代码。

我们要爬去图书的书名、图片、价格、出版社、评价数量信息。下图是商品列表也的界面,

使用selenium和pyquery爬取京东商品列表过程解析

通过开发者工具可知class="gl-item"的li节点是一条商品的信息,上图这个的红色框。

  • 绿色框是商品的图片信息。对应的是class=“p-img”的div节点。
  • 蓝色框是商品的价格信息,对应的是class="p-price"的div节点。
  • 黑色框是商品的名称信息,对应的是class="p-name"的div节点。
  • 紫色狂是商品的评价信息,对应的是class="p-commit"的div节点。
  • 褐色框是商品的出版社信息,对应的是class=“p-shopnum”的div节点。

我们使用pyquery解析商品的信息,使用selenium打开一个页面时,通过page_source属性就可以得到页面的源码。

这里有个坑需要注意:京东的商品列表页是显示固定数量的商品,当加载新的商品页的时候,并不是一下子把该页的商品都加载出来,而是鼠标向下滚动时才会动态加载新的商品。因此我们在使用selenium时,要将鼠标设置自动滚动到商品列表页的底部,这样就会把该页的所有商品都显示出现,爬取的数据才能完整,否则会出现丢失。

下面给出解析一个商品的代码:

from selenium import webdriver
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from pyquery import PyQuery as pq
import time
#通过Chrome()方法打开chrome浏览器
browser = webdriver.Chrome()
#访问京东网站
browser.get("https://www.jd.com")
#等待50秒
wait = WebDriverWait(browser, 50)
#通过css选择器的id属性获得输入框
input = browser.find_element_by_id('key')
#在输入框中写入要查询的信息
input.send_keys('计算机书籍')
#获取查询按钮
submit_button = browser.find_element_by_class_name('button')
#点击查询按钮
submit_button.click()

# 模拟下滑到底部操作
for i in range(1, 5):
  browser.execute_script("window.scrollTo(0, document.body.scrollHeight);")
  time.sleep(1)

#商品列表的总页数
total = wait.until(
  EC.presence_of_all_elements_located(
    (By.CSS_SELECTOR, '#J_bottomPage > span.p-skip > em:nth-child(1) > b')
  )
)

html = browser.page_source.replace('xmlns', 'another_attr')

doc = pq(html)
#一个商品信息是存放在class=“gl-item”的li节点内,items()方法是获取所有的商品列表。
li_list = doc('.gl-item').items()
#循环解析每个商品的信息
for item in li_list:
  image_html = item('.gl-i-wrap .p-img')
  book_img_url = item.find('img').attr('data-lazy-img')
  if book_img_url == "done":
    book_img_url = item.find('img').attr('src')
  print('图片地址:' + book_img_url)
  item('.p-name').find('font').remove()
  book_name = item('.p-name').find('em').text()
  print('书名:' + book_name)
  price = item('.p-price').find('em').text() + str(item('.p-price').find('i').text())
  print('价格:' + price)
  commit = item('.p-commit').find('strong').text()
  print('评价数量:' + commit)
  shopnum = item('.p-shopnum').find('a').text()
  print('出版社:' + shopnum)
  print('++++++++++++++++++++++++++++++++++++++++++++')

对于有分页的情况,需要一页一页的解析商品,我们可以通过selenium调用“下一页”按钮来获取下一页的源代码。我们来分析下一页的css代码,滚动鼠标到网页的底部,会看到分页的情况:

使用selenium和pyquery爬取京东商品列表过程解析

通过上图可知,需要获取到“下一页”按钮,然后调用click方法。相应的代码为:

next_page_button = wait.until(
    EC.element_to_be_clickable((By.CSS_SELECTOR, '#J_bottomPage > span.p-num > a.pn-next > em'))
  )
  next_page_button.click()

  #滑动到页面底部,用于加载数据
  for i in range(0,3):
    browser.execute_script("window.scrollTo(0, document.body.scrollHeight);")
    time.sleep(10)

  #一页显示60个商品,"#J_goodsList > ul > li:nth-child(60)确保60个商品都正常加载出来。
  wait.until(
    EC.presence_of_all_elements_located((By.CSS_SELECTOR, "#J_goodsList > ul > li:nth-child(60)"))
  )
  # 判断翻页成功,当底部的分页界面上显示第几页时,就显示翻页成功。
  wait.until(
    EC.text_to_be_present_in_element((By.CSS_SELECTOR, "#J_bottomPage > span.p-num > a.curr"), str(page_num))
  )

下面给出完整代码:

from selenium import webdriver
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from pyquery import PyQuery as pq
import time
#打开不同的浏览器实例
def openBrower(brower_type):
  if brower_type == 'chrome':
    return webdriver.Chrome()
  elif brower_type == 'firefox':
    return webdriver.Firefox()
  elif brower_type == 'safari':
    return webdriver.Safari()
  elif brower_type == 'PhantomJS':
    return webdriver.PhantomJS()
  else :
    return webdriver.Ie()
def parse_website():
  # 通过Chrome()方法打开chrome浏览器
  browser = openBrower('chrome')
  # 访问京东网站
  browser.get("https://www.jd.com")
  # 等待50秒
  wait = WebDriverWait(browser, 50)
  # 通过css选择器的id属性获得输入框。until方法表示浏览器完全加载到对应的节点,才返回相应的对象。presence_of_all_elements_located是通过css选择器加载节点
  input = wait.until(
    EC.presence_of_all_elements_located((By.CSS_SELECTOR, '#key'))
  )

  # input = browser.find_element_by_id('key')
  # 在输入框中写入要查询的信息
  input[0].send_keys('计算机书籍')
  # 查询按钮完全加载完毕,返回查询按钮对象
  submit_button = wait.until(
    EC.element_to_be_clickable((By.CSS_SELECTOR, '.button'))
  )
  # 点击查询按钮
  submit_button.click()

  # 模拟下滑到底部操作
  for i in range(0,3):
    browser.execute_script("window.scrollTo(0, document.body.scrollHeight);")
    time.sleep(3)

  # 商品列表的总页数
  total = wait.until(
    EC.presence_of_all_elements_located(
      (By.CSS_SELECTOR, '#J_bottomPage > span.p-skip > em:nth-child(1) > b')
    )
  )
  html = browser.page_source.replace('xmlns', 'another_attr')
  parse_book(1,html)

  for page_num in range(2,int(total[0].text) + 1):
    parse_next_page(page_num,browser,wait)

##解析下一页
def parse_next_page(page_num,browser,wait):

  next_page_button = wait.until(
    EC.element_to_be_clickable((By.CSS_SELECTOR, '#J_bottomPage > span.p-num > a.pn-next > em'))
  )
  next_page_button.click()

  #滑动到页面底部,用于加载数据
  for i in range(0,3):
    browser.execute_script("window.scrollTo(0, document.body.scrollHeight);")
    time.sleep(10)

  #一页显示60个商品,"#J_goodsList > ul > li:nth-child(60)确保60个商品都正常加载出来。
  wait.until(
    EC.presence_of_all_elements_located((By.CSS_SELECTOR, "#J_goodsList > ul > li:nth-child(60)"))
  )
  # 判断翻页成功,当底部的分页界面上显示第几页时,就显示翻页成功。
  wait.until(
    EC.text_to_be_present_in_element((By.CSS_SELECTOR, "#J_bottomPage > span.p-num > a.curr"), str(page_num))
  )

  html = browser.page_source.replace('xmlns', 'another_attr')
  parse_book(page_num, html)

def parse_book(page,html):
  doc = pq(html)
  li_list = doc('.gl-item').items()
  print('-------------------第' + str(page) + '页的图书信息---------------------')
  for item in li_list:
    image_html = item('.gl-i-wrap .p-img')
    book_img_url = item.find('img').attr('data-lazy-img')
    if book_img_url == "done":
      book_img_url = item.find('img').attr('src')
    print('图片地址:' + book_img_url)
    item('.p-name').find('font').remove()
    book_name = item('.p-name').find('em').text()
    print('书名:' + book_name)
    price = item('.p-price').find('em').text() + str(item('.p-price').find('i').text())
    print('价格:' + price)
    commit = item('.p-commit').find('strong').text()
    print('评价数量:' + commit)
    shopnum = item('.p-shopnum').find('a').text()
    print('出版社:' + shopnum)
    print('++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++')

def main():
  parse_website()
if __name__ == "__main__":
  main()

3、总结

(1)要记得调用 browser.execute_script("window.scrollTo(0, document.body.scrollHeight);")方法模拟鼠标向下滚动的操作加载数据,否则数据会不完整。

(2)在通过page_source获取网页源码时,如果有xmlns命名空间,则要将该命名空间空其他的字段代替,否则使用pyquery解析网页时,会解析不出数据。pyquery解析xmlns命名空间时,会自动隐藏掉某些属性。导致无法征程解析网页,原因不详,如果有人知道原因请告知。

(3)尽量用wait.until(EC.presence_of_all_elements_located())方法,这样可以避免网页无法正常加载而提前返回网页信息的情况。保证数据的准确。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python简单实现socket信息发送与监听功能示例
Jan 03 Python
Django实现组合搜索的方法示例
Jan 23 Python
python图书管理系统
Apr 05 Python
Python简单实现的代理服务器端口映射功能示例
Apr 08 Python
Python实现的根据IP地址计算子网掩码位数功能示例
May 23 Python
Python基于jieba库进行简单分词及词云功能实现方法
Jun 16 Python
python调用staf自动化框架的方法
Dec 26 Python
Python中的字符串切片(截取字符串)的详解
May 15 Python
python进程和线程用法知识点总结
May 28 Python
Python3中urlencode和urldecode的用法详解
Jul 23 Python
Python字符串大小写转换拼接删除空白
Sep 19 Python
pytorch实现加载保存查看checkpoint文件
Jul 15 Python
如何爬取通过ajax加载数据的网站
Aug 15 #Python
Python K最近邻从原理到实现的方法
Aug 15 #Python
Python数据可视化 pyecharts实现各种统计图表过程详解
Aug 15 #Python
浅谈Python 敏感词过滤的实现
Aug 15 #Python
pycharm创建scrapy项目教程及遇到的坑解析
Aug 15 #Python
通过selenium抓取某东的TT购买记录并分析趋势过程解析
Aug 15 #Python
Python依赖包整体迁移方法详解
Aug 15 #Python
You might like
PHP 使用MySQL管理Session的回调函数详解
2013/06/21 PHP
PHP程序漏洞产生的原因分析与防范方法说明
2014/03/06 PHP
CI框架中zip类应用示例
2014/06/17 PHP
浅谈COOKIE和SESSION区别
2015/07/19 PHP
PHP爬虫之百万级别知乎用户数据爬取与分析
2016/01/22 PHP
PHP内存缓存功能memcached示例
2016/10/19 PHP
PHP实现一个按钮点击上传多个图片操作示例
2020/01/23 PHP
javascript 兼容FF的onmouseenter和onmouseleave的代码
2008/07/19 Javascript
基于jquery ajax 用户无刷新登录方法详解
2012/04/28 Javascript
jquery实现图片左右间隔滚动特效(可自动播放)
2013/05/08 Javascript
jQuery获得页面元素的绝对/相对位置即绝对X,Y坐标
2014/03/06 Javascript
深入了解Node.js中的一些特性
2014/09/25 Javascript
JavaScript学习笔记之数组的增、删、改、查
2016/03/23 Javascript
详解jQuery选择器
2016/12/21 Javascript
如何优雅的在一台vps(云主机)上面部署vue+mongodb+express项目
2019/01/20 Javascript
JS实现的字符串数组去重功能小结
2019/06/17 Javascript
JS实现扫码枪扫描二维码功能
2020/01/03 Javascript
[00:12]2018DOTA2亚洲邀请赛 Sccc亮相SOLO赛,今年他又会有什么样的战绩?
2018/04/06 DOTA
[37:21]完美世界DOTA2联赛PWL S2 Inki vs Magma 第二场 11.22
2020/11/24 DOTA
Python中title()方法的使用简介
2015/05/20 Python
Python判断字符串与大小写转换
2015/06/08 Python
关于Python中Inf与Nan的判断问题详解
2017/02/08 Python
基于DataFrame筛选数据与loc的用法详解
2018/05/18 Python
Python内置方法实现字符串的秘钥加解密(推荐)
2019/12/09 Python
Python动态声明变量赋值代码实例
2019/12/30 Python
浅谈基于Canvas的手绘风格图形库Rough.js
2018/03/19 HTML / CSS
HEMA英国:荷兰原创设计
2018/08/28 全球购物
澳大利亚最大的在线美发和美容零售商之一:My Hair Care & Beauty
2019/08/24 全球购物
日本即尚网:JSHOPPERS.com(支持中文)
2019/12/03 全球购物
介绍一下如何优化MySql
2016/12/20 面试题
英语师范专业毕业生自荐信
2013/09/21 职场文书
中西医专业毕业生职业规划书
2014/02/24 职场文书
库房保管员岗位职责
2014/04/07 职场文书
婚礼嘉宾致辞
2015/07/28 职场文书
2016年小学生教师节广播稿
2015/12/18 职场文书
Selenium浏览器自动化如何上传文件
2022/04/06 Python