使用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将多个文本文件合并为一个文本的代码(便于搜索)
Mar 13 Python
Python 的 with 语句详解
Jun 13 Python
python利用paramiko连接远程服务器执行命令的方法
Oct 16 Python
Python绘制KS曲线的实现方法
Aug 13 Python
浅谈python图片处理Image和skimage的区别
Aug 04 Python
python hashlib加密实现代码
Oct 17 Python
Python 将json序列化后的字符串转换成字典(推荐)
Jan 06 Python
python3下pygame如何实现显示中文
Jan 11 Python
python如何解析复杂sql,实现数据库和表的提取的实例剖析
May 15 Python
Python学习之路之pycharm的第一个项目搭建过程
Jun 18 Python
Python中常用的os操作汇总
Nov 05 Python
Python接口自动化测试框架运行原理及流程
Nov 30 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验证码实现代码
2014/05/10 PHP
PHP APC配置文件2套和参数详解
2014/06/11 PHP
PHP实现获取域名的方法小结
2014/11/05 PHP
PHP生成各种常见验证码和Ajax验证过程
2016/01/10 PHP
将nodejs打包工具整合到鼠标右键的方法
2013/05/11 NodeJs
JS 屏蔽键盘不可用与鼠标右键不可用的方法
2013/11/18 Javascript
JS全局变量和局部变量最新解析
2016/06/24 Javascript
javascript简单实现跟随滚动条漂浮的返回顶部按钮效果
2016/08/19 Javascript
Javascript中作用域的详细介绍
2016/10/06 Javascript
javascript实现动态显示颜色块的报表效果
2017/04/10 Javascript
详解创建自定义的Angular Schematics
2018/06/06 Javascript
JavaScript作用域、闭包、对象与原型链概念及用法实例总结
2018/08/20 Javascript
Vue项目自动转换 px 为 rem的实现方法
2018/10/29 Javascript
用node.js写一个jenkins发版脚本
2019/05/21 Javascript
Javascript异步编程async实现过程详解
2020/04/02 Javascript
Python SQLAlchemy基本操作和常用技巧(包含大量实例,非常好)
2014/05/06 Python
Python中defaultdict与lambda表达式用法实例小结
2018/04/09 Python
基于python 处理中文路径的终极解决方法
2018/04/12 Python
win10下python3.5.2和tensorflow安装环境搭建教程
2018/09/19 Python
Python实现DDos攻击实例详解
2019/02/02 Python
python爬虫之爬取百度音乐的实现方法
2019/08/24 Python
Python+OpenCV图像处理——图像二值化的实现
2020/10/24 Python
纯css3实现效果超级炫的checkbox复选框和radio单选框
2014/09/01 HTML / CSS
如何在网站上添加谷歌定位信息
2016/04/16 HTML / CSS
使用css创建三角形 使用CSS3创建3d四面体原理及代码(html5实践)
2013/01/06 HTML / CSS
美国大城市最热门旅游景点门票:CityPASS
2016/12/16 全球购物
I.T中国官网:精选时尚设计师单品网购平台
2018/03/26 全球购物
7 For All Mankind官网:美国加州洛杉矶的高级牛仔服装品牌
2018/12/20 全球购物
马耳他航空公司官方网站:Air Malta
2019/05/15 全球购物
请写出char *p与"零值"比较的if语句
2014/09/24 面试题
简述网络文件系统NFS,并说明其作用
2016/10/19 面试题
应届生英语教师求职信
2013/11/05 职场文书
信息专业大学生自我评价分享
2014/01/17 职场文书
公司联欢晚会主持词
2014/03/22 职场文书
乌镇导游词
2015/02/02 职场文书
Python序列化模块JSON与Pickle
2022/06/05 Python