作为"数据玩家",如果手头上没有数据怎么办?当然是用代码让程序自动化采集数据,但是现在"爬虫"不是那么容易,其中最困难的即是突破网站各种反爬机制。本系列将全面讲解 Python 中一个非常成熟的库 —— selenium,并教会你如何使用它爬取网络上所需的数据
自动化爬虫虽然方便,但希望大家能顾及网站服务器的承受能力,不要高频率访问网站。并且千万不要采集敏感数据!!否则很容易"从入门到入狱"
本系列大部分案例同时采用 selenium 与 pyppeteer 库讲解,并且有 Python 和 C# 2门语言的实现文章,详细请到公众号目录中找到。
学习任何一个库,必须先了解这个库的机制与流程,今天先从一个小例子开始我们的学习之旅。
需求如下:
本系列始终围绕一点开展:"用代码操作浏览器",下面看看整个流程:
但是,市面上存在各种浏览器,而且就算只是一个厂商的浏览器也有不同的版本。怎么能保证我们的代码只需要写一次,就能控制不同的浏览器?
深入一点的流程图如下:
"怎么案例都没开始,就在说 selenium 的不是呢?我到底还学不学?"
他有如下优点:
缺点:
如果你认为无法接受 selenium 的缺点,可以查看 pyppeteer 的相关文章(公众号:数据大宇宙 > py爬虫 > pyppeteer)
现在让我们来开始使用 selenium 解决我们的需求。
首先,使用 pip 安装 selenium
!pip install selenium
由于我本机安装了 Google Chrome 浏览器,打开浏览器,看看浏览器的版本:
接着到相关网站(公众号发送"爬虫")下载对应的驱动:
看过我的相关教学文章的小伙伴都知道,我很喜欢从语义角度去理解学习一个库。
selenium 本质上是控制浏览器,因此当我们使用它的时候,代码的语义应该与手工操作浏览器的过程大同小异才合理。
首先导入一些包:
from selenium import webdriver
import selenium.webdriver.support.wait as WA
下面来看看怎么用代码来描述我们的手工操作。
打开浏览器:
wd = webdriver.Chrome()
的确,刚刚我们把驱动下载下来,但是 Python 怎么可能会知道去哪里找到那个驱动程序呢。
我们可以在实例化浏览器对象时,传入一个文件路径,告诉他程序的具体位置:
输入百度搜索的网址:
wd = webdriver.Chrome()
wd.get('https://www.baidu.com/')
鼠标移到输入框,点击一下,然后输入内容"爬虫":
这里的问题是,怎么用代码表达"鼠标移到输入框,点击一下"?
事实上,selenium 真可以模拟鼠标移动等操作(有些网站的登录验证码需要用鼠标拉动拼图都可以模拟),但是现在的情况我们不应该模拟鼠标,而是根据 html 标签定位即可。
此时我们使用浏览器的"开发者功能",进行定位即可。
由于篇幅关系,本文不详细讲解"开发者功能"的所有操作,详细讲解将放在公众号目录:数据大宇宙 > 爬虫工具 > 系列文章
下面用一个动态图展示操作过程:
看看代码:
wd = webdriver.Chrome()
wd.get('https://www.baidu.com/')
input_box = wd.find_element_by_css_selector('#kw')
接着,输入内容"爬虫":
wd = webdriver.Chrome()
wd.get('https://www.baidu.com/')
input_box = wd.find_element_by_css_selector('#kw')
input_box.send_keys('爬虫')
我们继续模拟点击输入框右边的"百度一下"这个按钮。
同样用"开发者功能",定位该元素,并复制 css 选择器表达字符串:
wd = webdriver.Chrome()
wd.get('https://www.baidu.com/')
# 输入框
input_box = wd.find_element_by_css_selector('#kw')
input_box.send_keys('爬虫')
#百度一下按钮
act_btn = wd.find_element_by_css_selector('#su')
act_btn.click()
所有结果的主标题:
这个可能对初学者有点难度,因为我们这次需要一次选择多个元素(多个搜索结果的主标题),看看定位到的标签:
进一步看看我们需要的主标题在哪里:
那么,现在我们要用 css 选择器表达以下语义:在一个div(id=content_left)里面,h3 标签里面的 a 标签的文本。div 与 h3 之间可能嵌套了多层。
得到的选择器表达式如下:
调用代码如下:
wd = webdriver.Chrome()
wd.get('https://www.baidu.com/')
# 输入框
input_box = wd.find_element_by_css_selector('#kw')
input_box.send_keys('爬虫')
#百度一下按钮
act_btn = wd.find_element_by_css_selector('#su')
act_btn.click()
#
titles = wd.find_elements_by_css_selector('div[id=content_left] h3 > a')
titles = [t.text for t in titles]
titles
上面的代码之所以拿不到任何结果,是因为当执行到第10行的代码时,页面上还没有加载任何的结果。
如果是一个人在操作浏览器,那么你应该跟他说:嘿,一直到你看到那些结果,你再去提取主标题啊。
怎么表达"一直到你看到那些结果"?,selenium 有专门用于等待元素出现的机制,代码如下:
wd = webdriver.Chrome()
wd.get('https://www.baidu.com/')
# 输入框
input_box = wd.find_element_by_css_selector('#kw')
input_box.send_keys('爬虫')
#百度一下按钮
act_btn = wd.find_element_by_css_selector('#su')
act_btn.click()
# 等待对象
wait = WA.WebDriverWait(wd, timeout=3)
titles =wait.until(lambda w:w.find_elements_by_css_selector('div[id=content_left] h3 > a'))
titles = [t.text for t in titles]
titles
加上关闭浏览器的控制,完整代码如下:
with webdriver.Chrome() as wd:
wd.get('https://www.baidu.com/')
# 输入框
input_box = wd.find_element_by_css_selector('#kw')
input_box.send_keys('爬虫')
#百度一下按钮
act_btn = wd.find_element_by_css_selector('#su')
act_btn.click()
# 等待对象
wait = WA.WebDriverWait(wd, timeout=3)
titles =wait.until(lambda w:w.find_elements_by_css_selector('div[id=content_left] h3 > a'))
titles = [t.text for t in titles]
titles
用代码控制 selenium 基本与人工操作一致,一般的流程:
下一节,将介绍更多 selenium 的技巧,敬请关注!!
觉得写得不错,点击右下方"在看"
公众号发送"爬虫",获取本系列文章所有相关资料和源码