Posted on 

Python爬虫利器——Selenium教程(入门篇)

Python虽然有十分强大的requests 库,但是如今对爬虫的限制让requests库想要顺利爬取网站内容,需要很复杂的手段来将自己伪装成正常的浏览器。相比之下,selenium提供了一个更加简单,成熟的方案,是Python爬虫的利器。

专业度警告

这是一篇面向零基础小白的教程,有些概念我也很模糊所以难免出现一些描述不精准的地方,切勿钻文字牛角尖。

初始配置

首先,selenium 需要一个 webdriver,来模拟浏览器的行为——和requests 库单单修改User-Agent 等值相比,webdriver 是运行一个真正的浏览器。因此,我们需要下载 webdriver 并且安装对应的浏览器。

Windows下的selenium总会有些奇奇怪怪的问题,如果有条件建议使用Linux进行开发。本文也将以Ubuntu作为环境进行开发。

以Chrome为例,首先在系统中安装Chrome:

1
2
wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
sudo apt install ./google-chrome-stable_current_amd64.deb

安装完成后,查看一下安装了哪个版本:

1
google-chrome --version

进入 Chromedriver下载页面 找到对应版本,下载 chromedriver_linux64.zip ,解压后放置到代码目录下,最后记得给予运行权限:

1
chmod +x chromedriver

开始使用

启动一个浏览器:

1
2
3
4
from selenium import webdriver


driver = webdriver.Chrome(executive_path="./chromedriver") # 初始化浏览器

还可以添加一些额外选项来配置浏览器:

1
2
3
4
5
6
from selenium import webdriver

ops = webdriver.ChromeOptions()
ops.add_argument("--headless") # “无头”浏览器 不显示图形窗口
ops.add_argument("--no-sandbox") # 禁用沙箱 可以解决一些错误
driver = webdriver.Chrome(executive_path="./chromedriver", options=ops)

完成后,使用.get()打开一个页面:

1
driver.get("https://www.baidu.com")

更多操作?

1
driver.find_element_by_xpath("//*[@id="form"]/span[2]").send_keys("Python")

这个语句的含义后续会再介绍(实际上它已经过时了,因此无需在意)。只需要看到,后续操作只需要通过调用driver.xxx 就可以在之前的浏览器对象上加以操作,如查找元素,保存网页截图等等。

查找元素

爬虫的要务自然是查找和收集信息。selenium 提供了 find_element 方法来查找元素。在最新版本中,杂乱的find_element_by_XXX 被整合为 find_element,只需要导入 selenium.webdriver.common.by.By 即可。

1
2
3
4
5
from selenium import webdriver
from selenium.webdriver.common.by import By


driver.find_element(by=By.XPATH, value='...')

获取XPath

尽管有些晦涩难懂,但XPath 确实是最实用的方法。如果你担心无法掌握语法,也无妨——Chrome 控制台可以帮到你。

找到你需要选择的元素,右键点击复制,就能复制XPath了。

如果你希望详细了解XPath 语法,请参考 XPath语法

当然,通过class_name 等等也可以用来查找元素,不过出于作者对XPath 的情有独钟,就不过多介绍了,有兴趣请参见文档 Locating Elements

对元素使用方法

查找到元素以后,我们需要对它做些什么:对于文本框,我们或许需要获取它的内容;对于图片,我们或许需要希望”看到“它,或是获取它的URL;对于输入框,我们或许需要键入一些内容。

.text

这个方法获取查找到的元素的”文本“内容(不包括html 标签)

1
2
3
<p id="hello">
This is text!
</p>
1
print(driver.find_element(by=By.XPath, value='//*[@id=hello]').text) # This is text!

.get_attribute()

这个方法获取查找到的元素的其他属性。

1
2
3
<p id="hello" type="big">
This is text!
</p>
1
print(driver.find_element(by=By.XPath, value='//*[@id=hello]').get_attribute("type")) # big

.send_keys()

这个方法在查找的元素中键入数据。

1
2
3
<input id="1">
// ...
</input>
1
driver.find_element(by=By.XPath, value='//*[@id=1]').send_keys("Hello!") # 输入框中输入 Hello!

.click()

这个方法使浏览器点击查找到的元素——在上一步输入之后,我们通常需要点击一个按钮来提交它!

1
2
3
<btn id="2">
提交
</btn>
1
driver.find_element(by=By.XPath, value='//*[@id=2]').click()  # 提交!
到这里你可能也发现了——使用XPath似乎有一个问题,就像前面两个例子,如果它们的id都是1该怎么办呢?

实际上,除了find_element,还有find_elements ——查找到的元素本就不一定是唯一的。如果你嫌太麻烦,有个很简单的解决方法,那就是在前面提到的Chrome控制台复制XPath的步骤中改为复制”完整“XPath——对于那些单个元素是很好的,除了使得代码变得冗长和难懂之外,它保证在网页没有出现修改的情况下能精准定位到你想要的元素上——但一些情况下这是致命的,这是后话。

截图

如果你使用了--headless 选项,那么浏览器只会默默运行,此时如果遇到了问题,比如显示查找不到元素,那么我们就需要通过截图的方式来排查,究竟发生了什么。

1
driver.save_screenshot("debug.jpg")

当然,截图的作用不仅限于debug。你可以对一个元素截图:

1
driver.find_element(...).save_screenshot("element.jpg")

举个栗子吧

登陆页面时常会有验证码。我们假设已经有一个 captcha() 方法可以识别验证码,并返回识别结果。

这时候有两个做法:

  1. 通过.get_attribute("src") 方法获取图片的URL。但由于captcha图片的URL更像一个API,而非静态图像,因此这样获取到的验证码并非打开登陆页面时所“看”到的验证码。

    不过有趣的是,其实这个方法有时是可行的。网站不严格的情况下,这样的行为只等同于你刷新了一次验证码。但是这样太不优雅了,不推荐。

    另外,如果获取到的src是base64格式的,那自然不必截图。

  2. 截图。

很显然,通过截图是最接近”真人“行为的——selenium 的一切都应该建立在模仿真实用户的行为的基础上。

未完待续…

开往-友链接力
A member of 开往-友链接力

This site was deployed by @OasisLee using Stellar.

本站由Vercel提供托管与Serverless支持 | PlanetScale提供数据库支持