侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

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

Python  /  管理员 发布于 5年前   182

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

1、准备工作

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


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

输入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文件夹中:

2、分析要爬取的页面

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

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


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

from selenium import webdriverfrom selenium.webdriver.support import expected_conditions as ECfrom selenium.webdriver.common.by import Byfrom selenium.webdriver.support.ui import WebDriverWaitfrom 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浏览器,自动完成在搜索框中输入关键词并点击查询按钮的操作。

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

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

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

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

通过开发者工具可知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 webdriverfrom selenium.webdriver.support import expected_conditions as ECfrom selenium.webdriver.common.by import Byfrom selenium.webdriver.support.ui import WebDriverWaitfrom pyquery import PyQuery as pqimport 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代码,滚动鼠标到网页的底部,会看到分页的情况:

通过上图可知,需要获取到“下一页”按钮,然后调用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 webdriverfrom selenium.webdriver.support import expected_conditions as ECfrom selenium.webdriver.common.by import Byfrom selenium.webdriver.support.ui import WebDriverWaitfrom pyquery import PyQuery as pqimport 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())方法,这样可以避免网页无法正常加载而提前返回网页信息的情况。保证数据的准确。

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


  • 上一条:
    使用pyecharts生成Echarts网页的实例
    下一条:
    pycharm创建scrapy项目教程及遇到的坑解析
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 在python语言中Flask框架的学习及简单功能示例(0个评论)
    • 在Python语言中实现GUI全屏倒计时代码示例(0个评论)
    • Python + zipfile库实现zip文件解压自动化脚本示例(0个评论)
    • python爬虫BeautifulSoup快速抓取网站图片(1个评论)
    • vscode 配置 python3开发环境的方法(0个评论)
    • 近期文章
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • 在go + gin中gorm实现指定搜索/区间搜索分页列表功能接口实例(0个评论)
    • 在go语言中实现IP/CIDR的ip和netmask互转及IP段形式互转及ip是否存在IP/CIDR(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2016-11
    • 2018-04
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2022-01
    • 2023-07
    • 2023-10
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客