[Python3爬虫]selenium+chromdriver可见即可爬

动态加载页面信息的提取[二]

上一遍博客介绍了Ajax的分析和抓取方式,这只是JavaScript动态渲染的页面的一种情形。JavaScript动态渲染的页面不止Ajax这一种。比如中国青年网 http://news.youth.cn/gn/
,它的分页部分是由JavaScript生成的,并非原始HTML代码,这其中并不包含Ajax请求。还有淘宝的页面,它即使通过Ajax获取数据,但是其Ajax接口含有很多加密参数,我们难以直接找出其规律,也很难直接分析Ajax来抓取。

为了解决这些问题,我们可以直接使用模拟浏览器运行的方式来实现,这样就可以做到在浏览器中看到是什么样,抓取的源码就是什么样。这样我们就不用再去管网页内部的JavaScript如何渲染页面,不用管网页后台的Ajax接口到底有哪些参数。

环境配置

1.selenium安装

Selenium是一个自动化测试工具,利用它可以驱动浏览器执行特定的动作,如点击、下拉等操作,同时还可以获取浏览器当前呈现的页面的源代码,做到可见即可爬。对于一些JavaScript动态渲染的页面来说,此种抓取方式非常有效

pip3 install selenium

#因为chrome驱动的原因,今天用的是win10,装的时候报错了,加个
python -m 就好
>>>Fatal error in launcher: Unable to create process using '"'

python -m pip install 库名
2.chromdriver版本的正确下载

成功安装好了Selenium库,但是它是一个自动化测试工具,需要浏览器来配合使用
只有安装ChromeDriver,才能驱动Chrome浏览器完成相应的操作

  • 下载

查看当前你的chrome版本,这里有与之对应的chromedriver版本对照表
https://blog.csdn.net/cz9025/article/details/70160273 ;
找到对应的版本之后到这个镜像站下载就好
http://npm.taobao.org/mirrors/chromedriver/
凭直觉也应该能推算出肯定要下载2018年4或5月的版本;解压出来添加至环境变量

  • 测试
>>> from selenium import webdriver
>>> automation = webdriver.Chrome()

如果这时候Chrome浏览器自动弹出

pic1.PNG

selenium用法

1.访问网页

通过 get() 方法来请求网页,参数传入链接URL即可

#声明浏览器对象
automation = webdriver.Chrome()
automation.get('https://www.jd.com')

运行程序,程序为我们打开浏览器,并访问京东网

2.查找节点

Selenium可以驱动浏览器完成各种操作,比如填充表单、模拟点击等。Selenium提供了一系列查找节点的方法,可以用这些方法来获取想要的节点,以便下一步执行一些动作或者提取信息。

  • 单个节点

比如,想要从淘宝页面中提取搜索框这个节点,首先要观察它的源代码

pic2.PNG

可以发现,它的id是key。此外,还有许多其他属性,此时我们就可以用多种方式获取它了。比如,find_element_by_name()是根据name值获取,find_element_by_id()是根据id获取。另外,还有根据XPath、CSS选择器等获取的方式。

automation = webdriver.Chrome()
automation.get('https://www.jd.com')
input_one = automation.find_element_by_id('key')
input_two = automation.find_element_by_class_name('text')
print(input_one,input_two)

#通过ID,和CSS选择器获取的是同一节点
>>>
<selenium.webdriver.remote.webelement.WebElement (session="4228ee4243c8dc7a0a09da4180542f62", element="0.47532329905849524-1")> <selenium.webdriver.remote.webelement.WebElement (session="4228ee4243c8dc7a0a09da4180542f62", element="0.47532329905849524-1")>

获取京东网的商品搜索框

另外,Selenium还提供了通用方法find_element(),它需要传入两个参数:查找方式By和值。实际上,它就是find_element_by_id()这种方法的通用函数版本,比如find_element_by_id(id)就等价于find_element(By.ID, id),二者得到的结果完全一致。我们用代码实现一下:

  • 多个节点

如果查找的目标在网页中只有一个,那么完全可以用find_element()方法。但如果有多个节点,再用find_element()方法查找,就只能得到第一个节点了。如果要查找所有满足条件的节点,需要用find_elements()这样的方法。注意,在这个方法的名称中,element多了一个s。

例如要获取京东左侧物品分类栏的所有节点

pic3.PNG

分析一波,发现它们的样式都是cate_menu_item

automation.get('https://www.jd.com')
input_three = browser.find_elements_by_class_name('cate_menu_item')
print(input_three)

>>> 
[<selenium.webdriver.remote.webelement.WebElement (session="5a8dfa1f4fc6aa6dd388f158c821b4c1", element="0.9897114676335383-1")>, <selenium.webdriver.remote.webelement.WebElement (session="5a8dfa1f4fc6aa6dd388f158c821b4c1", element="0.9897114676335383-2")>, <selenium.webdriver.remote.webelement.WebElement (session="5a8dfa1f4fc6aa6dd388f158c821b4c1", element="0.9897114676335383-3")>, <selenium.webdriver.remote.webelement.WebElement (session="5a8dfa1f4fc6aa6dd388f158c821b4c1", element="0.9897114676335383-4")>,...]

发现输出的是一个列表

3.节点交互

Selenium可以让浏览器模拟执行一些动作。比较常见的用法有:输入文字时用send_keys()方法,清空文字时用clear()方法,点击按钮时用click()方法。示例如下:

automation = webdriver.Chrome()
input = automation.find_element_by_id('key')
input.send_keys('小米8')
input.send_keys(Keys.ENTER)

程序会打开浏览器,访问京东网,在自动在搜索框输入小米8 ,并自动搜索

  • 以下程序和上面程序等价,需要获取到搜索按钮的节点,但更容易理解
automation = webdriver.Chrome()
automation.get('https://www.jd.com')
input = automation.find_element_by_id('key')
input.send_keys('小米8')
button = automation.find_element_by_class_name('button')
button.click()

其实模拟的就是鼠标点击事件

4.执行javascript

对于某些操作,Selenium API并没有提供。比如,下拉进度条,它可以直接模拟运行JavaScript,此时使用execute_script()方法即可实现,代码如下:

from selenium import webdriver
automation = webdriver.Chrome()
automation.get('https://www.zhihu.com/explore')
automation.execute_script('window.scrollTo(0, document.body.scrollHeight)')
automation.execute_script('alert("杨浩成")')

这里就利用execute_script()方法将进度条下拉到最底部,然后弹出alert提示框。
所以说有了这个方法,基本上API没有提供的所有功能都可以用执行JavaScript的方式来实现了。

5.获取节点信息
  • 获取属性
    过get_attribute()方法,然后传入想要获取的属性名,就可以得到它的值了
<img src="//img10.360buyimg.com/babel/s340x420_jfs/t21340/352/1759188507/80113/cb9969ae/5b336ba5Na3de776c.jpg!q90!cc_340x420" data-lazy-src="//img10.360buyimg.com/babel/s340x420_jfs/t21340/352/1759188507/80113/cb9969ae/5b336ba5Na3de776c.jpg!q90!cc_340x420" class="lazyimg_img">


from selenium import webdriver
automation = webdriver.Chrome()
automation.get('https://www.jd.com')
div = automation.find_element_by_class_name('lazyimg_img')
print(div.get_attribute('src'))

>>>https://img12.360buyimg.com/babel/s380x300_jfs/t21358/107/1797333452/29670/280abb3c/5b35c51bN0004362d.jpg!q90!cc_190x150

跟据class获取图片,通过src属性获取图片链接

  • 获取文本值

每个WebElement节点都有text属性,直接调用这个属性就可以得到节点内部的文本信息,这相当于Beautiful Soup的get_text()方法、pyquery的text()方法,示例如下:

from selenium import webdriver
automation = webdriver.Chrome()
automation.get('https://www.jd.com')

li_list = automation.find_elements_by_class_name('cate_menu_item')
for iterm in li_list:
    print(iterm.text)

运行效果:

pic4.PNG
  • 获取id、位置、标签名和大小

另外,WebElement节点还有一些其他属性,比如id属性可以获取节点id,location属性可以获取该节点在页面中的相对位置,tag_name属性可以获取标签名称,size属性可以获取节点的大小,也就是宽高。方法都是一样的,这里就不做赘述了。

6.延时等待

在Selenium中,get()方法会在网页框架加载结束后结束执行,此时如果获取page_source,可能并不是浏览器完全加载完成的页面,如果某些页面有额外的Ajax请求,我们在网页源代码中也不一定能成功获取到。所以,这里需要延时等待一定时间,确保节点已经加载出来。

这里等待的方式有两种:一种是隐式等待,一种是显式等待。

1.隐式等待

当使用隐式等待执行测试的时候,如果Selenium没有在DOM中找到节点,将继续等待,超出设定时间后,则抛出找不到节点的异常。换句话说,当查找节点而节点并没有立即出现的时候,隐式等待将等待一段时间再查找DOM,默认的时间是0。示例如下:

from selenium import webdriver
automation = webdriver.Chrome()
automation.implicitly_wait(0.1)
automation.get('https://www.jd.com')
li_list = automation.find_elements_by_class_name('cate_menu_item')
for iterm in li_list:
    print(iterm.text)

用implicitly_wait()方法实现隐式等待。

2.显示等待

显式等待方法,它指定要查找的节点,然后指定一个最长等待时间。如果在规定时间内加载出来了这个节点,就返回查找的节点;如果到了规定时间依然没有加载出该节点,则抛出超时异常。这里就不在赘述了

小结

通过selenium对chromedriver的自动化控制,有以下优点:

  • 动态加载的网页数据也能够爬取;
  • 速度快,通过爬虫来实现抢课,抢票已经见怪不怪了,下篇博客将介绍一下实现12306订票系统的抢票程序,用到本篇的知识结合Xpath技术实现

关于作者

个人博客: http://yhch.xyz

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,366评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,521评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,689评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,925评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,942评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,727评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,447评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,349评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,820评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,990评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,127评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,812评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,471评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,017评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,142评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,388评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,066评论 2 355

推荐阅读更多精彩内容

  • Selenium是一款强大的基于浏览器的开源自动化测试工具,最初由 Jason Huggins 于 2004 年在...
    FifiZhuang阅读 7,615评论 5 71
  • 这篇文章在介绍官网的同时使用了比较多的脚本示例,示例里遇到的问题有部分在本篇文章进行了解释,还有一篇文章专门记录了...
    顾顾314阅读 12,929评论 3 32
  • 洞见SELENIUM自动化测试 写在最前面:目前自动化测试并不属于新鲜的事物,或者说自动化测试的各种方法论已经层出...
    厲铆兄阅读 6,730评论 3 47
  • 三月十八日 星期日 小雨 因为最近我要考驾考,所以基本上礼拜天都没有时间陪宝贝!上午带着宝贝一起...
    赵羽斐阅读 113评论 0 2
  • 根据你的身体情况和工作等实际,制定出此方案。 中速方案 【方案说明】 一个中等代谢水平的减脂者,用此方案一个月可减...
    So大江哥阅读 443评论 0 0