使用Selenium进行网络爬虫:初学者的指南
现代社交媒体等网站依赖JavaScript。然而,传统的脚本在提取动态元素方面存在不足,因为您需要JavaScript在获取数据之前先渲染整个页面。Selenium因其处理异步加载或无限滚动等问题的能力而受到欢迎。
本文将解释为什么您应该选择Selenium进行网络爬虫,并如何增加成功请求的机会。您还将找到一个逐步教程,教您如何使用Python构建一个Selenium网络爬虫。
Python与Selenium的网络爬虫是什么?
Selenium是一个通过编程控制无头浏览器的网络爬虫库。它允许您打开网站,浏览网页,与嵌入在JavaScript中的元素进行交互,并将它们提取出来供进一步使用。
如今,网站被设计为在笔记本电脑、平板电脑或智能手机等设备上运行。这些网站通过JavaScript进行客户端渲染,以响应用户的鼠标点击和键盘输入等操作。然而,这对于网络爬虫来说也带来了坏消息 — — 您必须处理懒加载或浏览器指纹技术。
使用常规的HTML提取工具如Requests来爬取动态网站变得非常困难。相反,Selenium模拟人类行为,因此您成功提取数据的机会增加了。
为什么选择Selenium进行网络爬虫?
Selenium之所以成为流行的网络爬虫选择,有多个原因:
- 支持JavaScript渲染:Selenium主要用于浏览器自动化,因此非常适合爬取依赖JavaScript的网站。它能够完全渲染目标网站并提取数据。
- 跨浏览器支持:Selenium最好的一点是它可以模拟主流浏览器,如Chrome、Firefox和Microsoft Edge。
- 支持多种编程语言:Selenium在编程语言方面也很灵活,您可以使用Python、Java、Ruby和C#等进行开发。
- 模拟用户行为:通过Selenium,您可以模仿人类的行为与网页进行交互,包括点击按钮、填写表单、提交数据、滚动页面以及浏览网页。
- 处理验证码:有些网站使用验证码来防止类似机器人的活动。Selenium可以处理这些测试,通过在浏览器中显示验证码,让您解决验证码或与第三方服务集成来自动化此过程。
- 防止指纹检测:Selenium具有类似selenium-stealth这样的包,可以隐藏您的数字指纹。正确配置后,它可以防止登录问题或通过reCAPTCHA。
- 大型社区:Selenium拥有活跃的社区,这意味着有许多资源、教程和插件可供使用,为您提供更好的体验。
尽管Selenium是强大的网络爬虫工具,在某些情况下可能并不是最高效的选择。对于简单的爬取任务或处理静态网站,其他库如BeautifulSoup或Requests可能是更好的选择。此外,您还可以选择使用其他无界面库,如Puppeteer,它使用更少的资源。然而,当处理复杂的动态网站时,Selenium的功能使其成为可靠的选择。
准备构建Selenium网络爬虫
1.选择项目想法和确定项目参数
构建Selenium网络爬虫的第一步是确定项目参数。
在使用Selenium进行网络爬虫时,有几种编程语言可供选择。但是决定使用哪种语言可能会有些困难,因此我们比较了适用于爬取任务的流行语言(*并非所有语言都受到Selenium的支持)。如果您仍然不能决定,可以选择Python — — 它是最容易使用的语言之一,并且适用于大多数项目需求。
您不需要额外的库来获取或解析数据,因为Selenium具有其自己的包和模块,涵盖了所有网络爬取阶段。例如,如果您需要清理数据,可以安装selenium.by模块。否则,Selenium可以很好地与其他强大的解析器(如Beautiful Soup)配合使用。
现在,让我们转向项目本身。您可以选择爬取像亚马逊这样的真实目标网站,或者在特意为爬取而创建的网站上练习您的技能。这样,您可以在一个安全的环境中探索不同的技术、语言和工具。在我们的网络爬取沙箱列表中,您可以找到一些建议的网站。
当您掌握了Selenium后,可能想要将您的技能投入实际应用。比如说,您想要获取最佳的航班优惠,您可以构建一个爬虫来每日收集价格并下载结果。如果您还没有任何使用案例,请查阅我们的指南中为初学者和高级用户提供的一系列创意想法。
2. 考虑网络抓取指南
虽然网络爬虫可以为许多目的服务,但在道德和法律层面上,有一些准则需要遵循。
首先,尊重网站的服务条款,不要在登录后进行数据爬取。这样做可能会导致您陷入法律纠纷。在我们的网络爬虫最佳实践文章中,您可以找到更多建议。
此外,如果您对网站可能带来的所有挑战不了解,网络爬虫可能会变得繁重。从验证码和IP地址封禁到网站结构变化,这些障碍可能会干扰您的Selenium网络爬虫。
3. 使用代理服务器
为了爬取网站,您将需要多个IP地址。因此,考虑在Selenium中设置代理。这样,当您向目标网站发送连接请求时,每次都会以新访客的身份出现。
您很可能会被诱惑使用免费的代理列表,但如果您不希望有人滥用您的个人信息,请选择付费的服务提供商。一个小建议:您应该检查提供商是否为Selenium代理设置提供了广泛的技术文档。
有几种类型的代理可供选择,但我们建议使用住宅地址代理。这些代理来自真实用户的设备,它们不可避免地会轮换,而且大多数服务提供长时间的粘性会话。
如何使用 Selenium 进行网络抓取?分步教程
在本教程中,我们将逐步从 quotes.toscrape.com 抓取两个 URL:

这两个链接都包含由JavaScript生成的内容,而第二个页面会延迟渲染。为什么需要学习如何处理延迟加载的内容呢?有时候,页面加载需要一段时间,或者在提取数据之前需要等待特定元素(或条件)满足。
有些网页加载需要一段时间,或者在提取数据之前需要等待特定元素(或条件)满足。因此,您需要学习如何处理延迟加载的内容。
必备条件
- Python 3:请确保您的系统已安装最新的 Python。您可以从 Python.org 官方网站下载。
- Selenium:使用 pip 安装 Selenium 软件包。打开命令提示符或终端,运行以下命令: pip install selenium。
- Chrome WebDriver: 下载与 Chrome 浏览器对应的 Chrome WebDriver。
导入程序库
步骤1:按照以下指示编写您的第一个Selenium脚本。
备注:我们将使用Python和Chrome浏览器。因此,您需要将Chrome WebDriver添加到系统路径中,以便浏览器可以与Selenium正常工作。
步骤2:接着,安装Selenium。
1) 首先,从 Selenium 模块导入 Webdriver。
from selenium import webdriver
2) 然后使用 Selenium 的 By selector 模块导入网络驱动程序,以简化元素选择。
from selenium.webdriver.common.by import By
3) 在进入下一步之前,确保具备暂停爬虫的所有要素。
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions
4) 由于我们将使用 CSV 模块,因此也需要导入该模块。
import csv
设置全局变量和查找所需元素
步骤1. 现在,让我们设置全局变量,以便可以存储这些值:
- url — 你将要爬取的页面链接;
- timeout — 如果页面加载时间超过了设定的timeout,你的爬取将失败。所以,在解决错误之前,你需要指定一个等待时间,以等待元素出现;
- output — 这是一个列表,你将在其中写入爬取到的引用语句。
url = 'http://quotes.toscrape.com/js/'
#url = 'http://quotes.toscrape.com/js-delayed/'
timeout = 10 #seconds
output = []
步骤 2. 然后,右键单击页面上的任意位置,检查 quotes.toscrape.com/js 的页面源。

步骤3.你需要选择所有的引用类对象,并在其中找到以下类别的文本内容:引用语句(quote)、作者(author)和标签(tag)。你可以使用Selenium的By模块来找到所有这些元素。
quotes = driver.find_elements(By.CLASS_NAME, 'quote')
步骤4.对于引用语句和作者,使用find_element()函数通过它们的类名来找到这些元素。然后提取文本并将其保存在一个变量中。
for quote in quotes:
text = quote.find_element(By.CLASS_NAME, 'text').text
print (f'Text: {text}')
author = quote.find_element(By.CLASS_NAME, 'author').text
print (f'Author: {author}')
步骤5.由于每个引用语句可能有多个标签,你需要使用find_elements()函数来找到所有这些标签。然后,遍历每个标签,并将其文本追加到标签列表(tags list)中。
tags = []
for tag in quote.find_elements(By.CLASS_NAME, 'tag'):
tags.append(tag.text)
print (tags)
最后,你可以将这些变量放入一个字典中,然后将该字典追加到你创建的输出列表(output list)中。
output.append({
'author': author,
'text': text,
'tags': tags,
})
使用 Python Selenium 抓取动态网页
步骤1.首先,你需要使用 Selenium 设置一个浏览器。在本例中,我们将使用 Chromium。
def prepare_browser():
#Initializing Chrome options
chrome_options = webdriver.ChromeOptions()
driver = webdriver.Chrome(options= chrome_options)
return driver
备注:如果你需要添加selenium_stealth来掩盖你的数字指纹,或者设置代理来避免速率限制,那么这就是可以这么做的地方。如果你不知道如何在Python中使用Selenium设置代理,可以参考我们的指南,其中会详细解释一切。
步骤2.接下来,编写main()函数。通过调用prepare_browser()函数创建一个新的Webdriver,并将它与URL(http://quotes.toscrape.com/js/)一起传递给一个新的scrape()函数。在函数结束后,驱动程序将退出,然后你可以打印出整个输出结果。
def main():
driver = prepare_browser()
scrape(url, driver)
driver.quit()
print (output)
if __name__ == '__main__':
main()
步骤3.现在,让我们开始爬取数据。通过driver.get(url)函数,我们告诉Selenium打开浏览器并访问该URL。由于选择器已经准备好了,只需粘贴代码即可。
def scrape(url, driver):
driver.get(url)
quotes = driver.find_elements(By.CLASS_NAME, 'quote')
for quote in quotes:
text = quote.find_element(By.CLASS_NAME, 'text').text
print (f'Text: {text}')
author = quote.find_element(By.CLASS_NAME, 'author').text
print (f'Author: {author}')
tags = []
for tag in quote.find_elements(By.CLASS_NAME, 'tag'):
tags.append(tag.text)
print (tags)
output.append({
'author': author,
'text': text,
'tags': tags,
})
这将会打开浏览器窗口,爬取一个页面,并将爬取到的文本打印到控制台,待脚本运行结束后,将输出整个结果。
控制台输出示例:
Opened: http://quotes.toscrape.com/js/
Text: “The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”
Author: Albert Einstein
['change', 'deep-thoughts', 'thinking', 'world']
Text: “It is our choices, Harry, that show what we truly are, far more than our abilities.”
Author: J.K. Rowling
['abilities', 'choices']
Text: “There are only two ways to live your life. One is as though nothing is a miracle. The other is as though everything is a
miracle.”
Author: Albert Einstein
['inspirational', 'life', 'live', 'miracle', 'miracles']
Text: “The person, be it gentleman or lady, who has not pleasure in a good novel, must be intolerably stupid.”
Author: Jane Austen
['aliteracy', 'books', 'classic', 'humor']
Text: “Imperfection is beauty, madness is genius and it's better to be absolutely ridiculous than absolutely boring.”
Author: Marilyn Monroe
['be-yourself', 'inspirational']
Text: “Try not to become a man of success. Rather become a man of value.”
Author: Albert Einstein
['adulthood', 'success', 'value']
列表输出示例:
[{'author': 'Albert Einstein', 'text': '“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”', 'tags': ['change', 'deep-thoughts', 'thinking', 'world']}, {'author': 'J.K. Rowling', 'text': '“It is our choices, Harry, that show what we truly are, far more than our abilities.”', 'tags': ['abilities', 'choices']}, {'author': 'Albert Einstein', 'text': '“There are only two ways to live your life. One is as though nothing is a miracle. The other is as though everything is a miracle.”', 'tags': ['inspirational', 'life', 'live', 'miracle', 'miracles']}, {'author': 'Jane Austen', 'text': '“The person, be it gentleman or lady, who has not pleasure in a good novel, must be intolerably stupid.”', 'tags': ['aliteracy', 'books', 'classic', 'humor']}, {'author': 'Marilyn Monroe', 'text': "“Imperfection is beauty, madness is genius and it's better to be absolutely ridiculous than absolutely boring.”", 'tags': ['be-yourself', 'inspirational']}, {'author': 'Albert Einstein', 'text': '“Try not to become a man of success. Rather become a man of value.”', 'tags': ['adulthood', 'success', 'value']}
抓取多个页面
步骤1.首先,找到带你前往下一页的链接。检查HTML代码;该链接将位于一个带有’class’属性为’next’的列表项下面。在该元素内部寻找<a>标签。
然后,在第二行中,从该元素中找到href属性,以获取下一页的URL,并将其赋值给next_url变量。
最后,再次调用scrape()函数,并将新的URL与Webdriver一起传递给它进行爬取。
elem_next = driver.find_element(By.CLASS_NAME, 'next').find_element(By.TAG_NAME,'a')
next_url = elem_next.get_attribute("href")
scrape(next_url, driver)

步骤2.现在脚本已经能够处理分页并爬取整个类别的数据了。然而,它仍然不知道何时停止,在最后一页上会发生错误,因为没有带有’class’属性为’next’的元素。
你可以将代码放在try except块中,以防止崩溃,并在到达最后一页后执行其他操作(如果需要的话)。
<try:
elem_next = driver.find_element(By.CLASS_NAME, 'next').find_element(By.TAG_NAME,'a')
next_url = elem_next.get_attribute("href")
scrape(next_url, driver)
except:
print('Next button not found. Quitting.')
等待页面加载
有时候,元素加载或由JavaScript生成可能需要一些时间。在这种情况下,你不希望在元素加载完成之前开始解析输出。例如,http://quotes.toscrape.com/js-delayed/ 页面会延迟10秒。如果你要搜索的元素尚未加载完成,脚本将会失败。
为了解决这个问题,你可以告诉Webdriver等待直到元素出现。最简单的方法是使用Selenium的WebDriverWait类。
步骤1.首先,你需要传递Webdriver和最开始创建的timeout变量,然后等待页面上带有’class’属性为’quote’的可见元素出现。然后你可以开始解析。
你还可以使用更多的条件进行等待。
WebDriverWait(driver, timeout).until(
expected_conditions.presence_of_element_located((By.CLASS_NAME, 'quote'))
)
步骤2.你也可以将上面的代码放在try except块中。这样,如果代码超时或页面上没有引用类的元素出现,你可以重试相同的请求。
现在,你的爬取函数已经完成了:
def scrape(url, driver):
driver.get(url)
print (f"Opened: {driver.current_url}")
try:
WebDriverWait(driver, timeout).until(
expected_conditions.presence_of_element_located((By.CLASS_NAME, 'quote'))
)
# Finding all elements with a class of 'quote' in the page
quotes = driver.find_elements(By.CLASS_NAME, 'quote')
for quote in quotes:
text = quote.find_element(By.CLASS_NAME, 'text').text
print (f'Text: {text}')
author = quote.find_element(By.CLASS_NAME, 'author').text
print (f'Author: {author}')
tags = []
for tag in quote.find_elements(By.CLASS_NAME, 'tag'):
tags.append(tag.text)
print (tags)
output.append({
'author': author,
'text': text,
'tags': tags,
})
try:
elem_next = driver.find_element(By.CLASS_NAME, 'next').find_element(By.TAG_NAME,'a')
next_url = elem_next.get_attribute("href")
scrape(next_url, driver)
except:
print('Next button not found. Quitting.')
except:
print ('Timed out.')
将输出保存到CSV文件中
最后,您可以在 main() 函数中添加几行,将输出写入 CSV 文件(使用 csv 库)。为此,我们需要一个名为 output_filename 的新变量。
field_names = ['author', 'text', 'tags']
output_filename = 'quotes.csv'
with open (output_filename, 'w', newline='', encoding='utf-8') as f_out:
writer = csv.DictWriter(f_out, fieldnames = field_names)
writer.writeheader()
writer.writerows(output)
上面的代码会创建一个文件,并将field_names列表作为CSV文件的表头写入。然后,它会使用输出列表中的字典对象来填充文件。

这是完整的脚本:
from selenium import webdriver
# Using By to simplify selection
from selenium.webdriver.common.by import By
# The latter two will be used to make sure that needed elements are present
# Before we begin scraping
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions
# For writing output to a CSV file
import csv
url = 'http://quotes.toscrape.com/js/' #url = 'http://quotes.toscrape.com/js-delayed/' timeout = 20 #secondsoutput = []def prepare_browser() -> webdriver: # Initializing Chrome options chrome_options = webdriver.ChromeOptions() driver = webdriver.Chrome(options= chrome_options) return driverdef scrape(url: str, driver: webdriver) -> None: driver.get(url) print (f"Opened: {driver.current_url}") try: WebDriverWait(driver, timeout).until( expected_conditions.presence_of_element_located((By.CLASS_NAME, 'quote')) ) # Finding all elements with a class of 'quote' in the page quotes = driver.find_elements(By.CLASS_NAME, 'quote') for quote in quotes: text = quote.find_element(By.CLASS_NAME, 'text').text print (f'Text: {text}') author = quote.find_element(By.CLASS_NAME, 'author').text print (f'Author: {author}') tags = [] for tag in quote.find_elements(By.CLASS_NAME, 'tag'): tags.append(tag.text) print (tags) output.append({ 'author': author, 'text': text, 'tags': tags, }) try: elem_next = driver.find_element(By.CLASS_NAME, 'next').find_element(By.TAG_NAME,'a') next_url = elem_next.get_attribute("href") scrape(next_url, driver) except: print('Next button not found. Quitting.') except: print ('Timed out.')def main() -> None: driver = prepare_browser() scrape(url, driver) driver.quit() print (output) # CSV field_names = ['author', 'text', 'tags'] output_filename = 'quotes.csv' with open (output_filename, 'w', newline='', encoding='utf-8') as f_out: writer = csv.DictWriter(f_out, fieldnames = field_names) writer.writeheader() writer.writerows(output)if __name__ == '__main__': main()