本节讲解 Python Selenium 爬虫实战案例,通过对实战案例的讲解让您进一步认识 Selenium 框架。
实战案例目标:抓取京东商城(https://www.jd.com/)商品名称、商品价格、评论数量,以及商铺名称。比如输入搜索“Python书籍”,则抓取如下数据:
Selenium 框架的学习重点在于定位元素节点,关于如何定位,我们已经介绍了 8 种方法,其中 Xpath 表达式适用性强,并且便捷。因此,建议大家多多熟悉 Xpath 表达式的相关语法规则。本节案例中很大一部分采用了 Xpath 表达式定位元素,希望帮助您温故知新。
本节案例中涉及了几个技术难点:第一,如何下拉滚动条下载商品,第二,如何实现翻页,也就是抓取下一页的内容,第三,如何判断数据已经抓取完毕,即终止页。下面我们逐步讲解。
实现自动输出、自动搜索是最基础的一步。首先定位输入框的的节点,其次定位搜索按钮节点,这与实现百度自动搜索思路一致,最关键就是要正确定位元素节点。
通过开发者调试工具检查相应的的位置,可得如下 Xpath 表达式:
代码如下所示:
from selenium import webdriver
broswer=webdriver.Chrome()
broswer.get('https://www.jd.com/')
broswer.find_element_by_xpath('//*[@id="key"]').send_keys("python书籍")
broswer.find_element_by_xpath("//*[@class='form']/button").click()
实现了自动搜索后,接下来就是要抓取页面中的商品信息,而您会发现只有将滑动条滚动至底部,商品才会全部加载完毕。滚动滑轮操作的代码如下:
# scrollTo(xpos,ypos)
# execute_script()执行js语句,拉动进度条件
#scrollHeight属性,表示可滚动内容的高度
self.browser.execute_script(
'window.scrollTo(0,document.body.scrollHeight)'#拉动进度条至底部
)
之后在通过 Xpath 表达式匹配所有商品,并将它们放入一个大列表中,通过循环列表取出每个商品,最后提取出想要的信息。
li_list=self.browser.find_elements_by_xpath('//*[@id="J_goodsList"]/ul/li')
for li in li_list:
item={}
# 提取商品名
item['name']=li.find_element_by_xpath('.//div[@class="p-name"]/a/em').text.strip()
# 提取价格
item['price']=li.find_element_by_xpath('.//div[@class="p-price"]').text.strip()
# 提取评论数量
item['count']=li.find_element_by_xpath('.//div[@class="p-commit"]/strong').text.strip()
# 提取商家店铺
item['shop']=li.find_element_by_xpath('.//div[@class="p-shopnum"]').text.strip()
如何实现翻页抓取数据,并判断数据数据已经抓取完毕呢?这其实并不难想到,我们可以先跳至终止页(即最后一页)。此时最后一页的“下一页”处于不可用状态,其元素节点如下:
如果页面源码中有上述代码存在,则证明此页是最后一页,若没有则不是。因此通过 if ...else 语句即可实现上述需求,如下所示:
#-1说明没找到,不是最后一页,执行点击 “下一页” 操作
if self.browser.page_source.find('pn-next disabled')==-1:
browser.find_element_by_class_name('pn-next').click()
完整程序代码如下所示:
#coding:utf8
from selenium import webdriver
import time
import pymongo
class JdSpider(object):
def __init__(self):
self.url='http://www.jd.com/'
self.options=webdriver.ChromeOptions() # 无头模式
self.options.add_argument('--headless')
self.browser=webdriver.Chrome(options=self.options) # 创建无界面参数的浏览器对象
self.i=0 #计数,一共有多少件商品
#输入地址+输入商品+点击按钮,切记这里元素节点是京东首页的输入栏、搜索按钮
def get_html(self):
self.browser.get(self.url)
self.browser.find_element_by_xpath('//*[@id="key"]').send_keys('python书籍')
self.browser.find_element_by_xpath("//*[@class='form']/button").click()
#把进度条件拉倒最底部+提取商品信息
def get_data(self):
# 执行js语句,拉动进度条件
self.browser.execute_script(
'window.scrollTo(0,document.body.scrollHeight)'
)
# 给页面元素加载时预留时间
time.sleep(2)
#用 xpath 提取每页中所有商品,最终形成一个大列表
li_list=self.browser.find_elements_by_xpath('//*[@id="J_goodsList"]/ul/li')
for li in li_list:
#构建空字典
item={}
item['name']=li.find_element_by_xpath('.//div[@class="p-name"]/a/em').text.strip()
item['price']=li.find_element_by_xpath('.//div[@class="p-price"]').text.strip()
item['count']=li.find_element_by_xpath('.//div[@class="p-commit"]/strong').text.strip()
item['shop']=li.find_element_by_xpath('.//div[@class="p-shopnum"]').text.strip()
print(item)
self.i+=1
def run(self):
#搜索出想要抓取商品的页面
self.get_html()
#循环执行点击“下一页”操作
while True:
#获取每一页要抓取的数据
self.get_data()
#判断是否是最一页
if self.browser.page_source.find('pn-next disabled')==-1:
self.browser.find_element_by_class_name('pn-next').click()
#预留元素加载时间
time.sleep(1)
else:
print('数量',self.i)
break
if __name__ == '__main__':
spider=JdSpider()
spider.run()
输出结果如下:
Selenium 自动化爬虫让你无须关心网站的类型(静态或者动态),只需您按部就班的寻找元素节点,并依此点击,即可实现数据抓取。不过 Selenium 最大的缺点就是效率低,因此它只适合做小规模的数据采集工作。