Selenium 概述
正如 Selenium 官方网站所述,Selenium 是一套用于自动化控制网页浏览器的工具集,最初作为跨浏览器测试工具推出。
Selenium 团队开发的 API 采用 WebDriver 协议来控制 Chrome 或 Firefox 等网页浏览器,并执行各种任务,例如:
- 填写表单
- 滚动
- 截屏
- 点击按钮
现在你可能在想,这一切如何应用到网页抓取中。其实很简单。
数据提取有时确实让人头疼。如今,即使没有必要,网站也常被建造成单页应用。它们弹出验证码的频率远超必要,甚至会封禁普通用户的IP地址。
简而言之,机器人检测功能令人沮丧,简直就像一个漏洞。
Selenium 能够通过解析并执行 JavaScript 代码,自动化处理网页抓取中的许多繁琐流程,例如滚动页面、抓取 HTML 元素或导出获取的数据,从而在这些情况下提供帮助。
安装
为了展示 Selenium 和 Python 的真正实力,我们将从 /r/learnprogramming 子版块抓取一些信息。除了数据抓取,我还将向您展示如何实现登录功能。既然我们已经了解了主要工具和即将使用的网站,接下来看看还需要安装哪些其他必要组件:
1. Python。我们将使用 Python 3.0。不过,只需稍作调整,您也可以使用 Python 2.0。您可以从这里下载并安装。
2. Selenium 包。你可以使用以下命令安装 Selenium 包:
pip3 install selenium
3. Pandas 包。它将用于提取数据并将抓取到的数据存储在 .csv 文件中。请运行以下命令在您的设备上安装它。
pip3 install pandas
4. BeautifulSoup 包。用于解析 HTML 和 XML 文档。只需运行以下命令:
pip3 install beautifulsoup
5. Google Chrome。点击此链接了解如何下载和安装。
6. Chrome 驱动程序。它将帮助我们配置 Selenium 的 Web 驱动程序。请点击此链接下载并安装最新版本的 chromedriver。请务必记下安装路径。
启动浏览器
让我们开始吧。创建一个新的 scraper.py 文件,并通过复制以下代码行导入 Selenium 包:
from selenium import webdriver
现在,我们将通过以下代码创建一个新的 Google Chrome 实例:
driver = webdriver.Chrome(LOCATION)
请将 LOCATION 替换为您计算机上 Chrome 驱动程序的实际路径。请查阅 Selenium 文档,根据您使用的操作系统查找 Web 驱动程序的最准确路径。
最后一步是访问我们要抓取数据的网站。在本例中,网址为 https://www.reddit.com/r/learnprogramming/top/?t=month。将以下代码行复制到新创建的 Python 文件中:
driver.get("https://www.reddit.com/r/learnprogramming/top/?t=month")
在终端窗口中运行以下命令:
python3 scraper.py
此时应会打开一个新的 Google Chrome 实例,页面顶部会显示“Chrome 正由自动化测试软件控制”。
定位特定数据
想必您已经猜到了,本教程我们将抓取 /r/learnprogramming 子版块。我们将保存帖子的标题、作者、赞数,并将其存储在一个新的 .csv 文件中。让我们看看这些信息在 HTML 页面上的位置,以及如何提取它们。
当 Google Chrome 最终加载完页面后,右键点击任意一篇帖子并选择“检查”。我们可以在 _1oQyIsiPHYt6nx7VOmd1sz 类名下找到该帖子的 HTML 容器。
您也可以在不显示图形用户界面的情况下运行 Google Chrome,并通过添加几行代码来记录页面的 HTML 内容。我们将为 Chrome 驱动程序设置 headless 选项为 true(以移除图形界面),并将窗口大小设为 1080 像素(以便获取适用于我们用例的正确 HTML 代码)。
最后两行代码会在完成页面 HTML 记录后立即退出 Chrome。
新的 scraper.py 文件将如下所示:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
options = Options()
options.headless = True
options.add_argument("--window-size=1920,1080")
driver = webdriver.Chrome("./chromedriver")
driver.get("https://www.reddit.com/r/learnprogramming/top/?t=month")
print(driver.page_source)
driver.quit()WebElement
WebElement 是一个 Selenium 对象,用于表示 HTML 元素。正如您将在后续教程中看到的,我们可以对这些元素执行多种操作,其中包括:
- 使用 .click() 方法点击该元素
- 通过调用 .send_keys() 方法向特定输入元素输入文本
- 使用 element.text 读取元素的文本
- 通过调用 .is_displayed() 方法检查元素是否显示在页面上
Selenium 实战示例
现在项目已搭建完成,我们可以开始进行网页抓取了。
登录
我们将通过登录 Reddit 账户并抓取之前展示的数据,来展示 Selenium 的强大功能。首先,让我们让 Selenium 点击页面顶部的登录按钮。检查页面 HTML 后,我们可以发现登录按钮的类名是 _2tU8R9NTqhvBrhoNAXWWcP。
login_button = driver.find_element_by_class_name('_2tU8R9NTqhvBrhoNAXWWcP')
login_button.click()
这将打开登录弹窗,其中可见需要填写的用户名和密码输入框。接下来继续执行以下代码:
driver.switch_to_frame(driver.find_element_by_class_name('_25r3t_lrPF3M6zD2YkWvZU'))
driver.find_element_by_id("loginUsername").send_keys('USERNAME')
driver.find_element_by_id("loginPassword").send_keys('PASSWORD')
driver.find_element_by_xpath("//button[@type='submit']").click()
如果检查该模态框元素,我们会发现其容器是一个 iframe。这就是为什么我们在代码开头需要切换到 frame 模式,因为如果不这样做,选择输入框会导致错误。
接下来,我们获取输入字段并输入正确的凭据,然后点击提交按钮。这将带我们返回 /r/learnprogramming 页面,但此时我们已登录并准备好点赞!
截取屏幕截图
使用 Selenium 和 Python 截屏非常简单。你只需在声明 WebDriver 之后,在 scraper.py 文件中编写以下命令即可。
driver.save_screenshot('screenshot.png')
值得注意的是,您可以通过添加以下代码行来设置 Google Chrome 窗口的大小:
from selenium.webdriver.chrome.options import Options
options = Options()
options.add_argument("--window-size=1920,1080")
在我们的示例中,截图效果如下:

提取数据
如前所述,我们需要获取帖子的标题、作者以及赞数。首先导入 BeautifulSoup 和 Pandas 包,并为每种所需信息类型创建三个空数组。
from bs4 import BeautifulSoup
import pandas as pd
titles = []
upvotes=[]
authors = []
我们将使用 BeautifulSoup 解析 HTML 文档,编写以下代码:
content = driver.page_source
soup = BeautifulSoup(content, features="html.parser")
成功解析 HTML 文档并选择正确的选择器后,我们将提取标题、赞数和作者信息,并将其赋值给相应的数组:
for element in soup.findAll('div', attrs={'class': '_1oQyIsiPHYt6nx7VOmd1sz'}):
title = element.find('h3', attrs={'class': '_eYtD2XCVieq6emjKBH3m'})
upvote = element.find('div', attrs={'class': '_3a2ZHWaih05DgAOtvu6cIo'})
author = element.find('a', attrs={'class': '_23wugcdiaj44hdfugIAlnX'})
titles.append(title.text)
upvotes.append(upvote.text)
authors.append(author.text)
最后,我们将使用之前导入的 Pandas 包,将这些信息存储到 CSV 文件中。
df = pd.DataFrame({'Post title': titles, 'Author': authors, 'Number of upvotes': upvotes})
df.to_csv('posts.csv', index=False, encoding='utf-8')
就这样!让我们来看看导出的文件:
看起来包含我们所需的所有信息。
额外提示:有时,网站在首次加载时提供的数据并不完整。大多数情况下,数据加载操作会在用户向下滚动时触发。如果您需要向下滚动以获取更多数据,可以使用 .execute_script() 方法,如下所示:
scrollDown = "window.scrollBy(0,2000);"
driver.execute_script(scrollDown)
结语
希望你和我一样享受制作这个网页抓取工具的过程。编程并非总是充满乐趣,但编写这样的小脚本让我回想起初学编程时的时光,也让整个过程变得更有趣。
不过,本教程中构建的脚本尚无法胜任繁重的工作。它缺少几项关键功能,而这些功能正是让网页抓取体验流畅无瑕的关键。例如通过移动或住宅代理连接,以及破解验证码等。
如果您正在寻找更专业的数据提取方案,不妨了解一下 WebScrapingAPI 的功能,亲自验证它是否符合您的需求。该服务提供免费套餐,您只需投入 30 分钟的时间即可体验。
感谢您抽出时间阅读本文。祝您爬取顺利!




