使用 Selenium 进行网络爬虫指南

这是唯一的逐步指南,您只需按照它即可在10分钟内开始从目标网站收集网页数据,并将其保存为CSV文件。
7 min read
使用Selenium进行网络爬虫指南

网络爬虫是一个自动化过程,用于从网站上收集大量以不同格式(如文本、数字、图像、音频或视频等)呈现的 HTML 数据。大多数网站(包括 YouTube 或 eBay)通过根据用户交互显示动态内容。

如果你对网络爬虫感兴趣,可能听说过 Selenium。它是一个开源的网络爬虫工具,提供了从动态网站抓取数据的高级技术。它可以通过执行各种操作模拟用户交互,如填写表单、导航网页和选择由 JavaScript 渲染的特定内容。

本教程将教你如何使用 Selenium Python 包开始抓取数据。

设置 Selenium 和 Python 环境

在使用 Selenium 进行网络爬虫之前,你需要设置 Python 环境并安装 Selenium Python 包webdriver_manager Python 包。webdriver_manager 是一个 Python 包,用于下载和管理不同浏览器(包括 Chrome、Firefox 和 Edge)的二进制驱动程序。

安装这些包后,还需要在环境中 配置环境变量和代理服务器。安装所有需要的包后,你就可以启动浏览器并开始抓取数据了。

要自动启动 Chrome 浏览器并访问特定 URL 的网页,请在终端中的 Python 脚本文件(如 web_scrape.py)中运行以下代码:

# import module
from selenium import webdriver

#setup chrome webdriver
driver = webdriver.Chrome()

#load the web page
driver.get('https://yourwebsite.com')

# print page source
print(driver.page_source)

# close the driver
driver.quit()

要运行上述代码,请在终端中使用以下命令:

python web_scrape.py

该代码将启动 Chrome 浏览器,访问提供的 URL 的网页,显示加载的网页的 HTML,并关闭 Chrome 驱动实例。

理解 HTML 和定位元素

HTML 使用标签包围的元素来结构化网页内容(如 <h1>内容</h1>)。这些元素将内容组织成层次结构,定义网页的布局、格式和交互性。

要在浏览器中定位网页上的 HTML 标签,可以右键单击要查找的元素并选择检查(或类似的选项,具体取决于你的浏览器)。这将打开浏览器的开发者工具,你可以在其中查看 HTML 代码并定位特定标签:

检查页面并查看特定标签

定位到元素后,可以在检查器中右键单击该元素并复制其标签、类、CSS 选择器或绝对 XPath 表达式。

Selenium 提供了两种定位网页 HTML 元素的方法:find_elementfind_elementsfind_element 方法查找网页上的特定单个元素,而 find_elements 方法则检索包含网页上发现的所有元素的列表。

这些方法兼容 Selenium 定义的各种定位器,包括以下内容:

  • By.Name 根据名称属性定位元素。
  • By.ID 根据 ID 定位元素。
  • By.XPATH 根据 XPath 表达式定位元素。
  • By.TAG_NAME 根据标签名称定位元素。
  • By.CLASS_NAME 根据类定位元素。
  • By.CSS_SELECTOR 根据 CSS 选择器定位元素。

假设你想根据可用的 HTML 元素收集数据,并且有一个这样的 HTML 文档:

<!DOCTYPE html>
<html>
<head>
    <title>Sample HTML Page</title>
</head>
<body>
    <div id="content">
        <h1 class="heading">Welcome to my website!</h1>
        <p>This is a sample paragraph.</p>
    </div>
</body>
</html>

你可以使用 Selenium 的 By.Name 定位器来定位 h1 标签:

h1 = driver.find_element(By.NAME, 'h1')

要从 HTML 文档中定位 ID,可以使用 By.ID 定位器:

content = driver.find_element(By.ID, 'content')

你还可以使用 By.CLASS_NAME 来定位所有类为 "heading" 的 HTML 元素:

classes = driver.find_elements(By.CLASS_NAME, 'heading')

使用 Selenium 进行网络爬虫

在定位到 HTML 标签后,Selenium 提供了不同的提取方法,你可以使用这些方法从网站收集数据。最常用的方法如下:

  • text 从 HTML 标签中提取文本。
  • get_attributes() 提取 HTML 标签中的属性值。

以下示例演示了如何使用定位器(如 ID、CSS 选择器和标签名称)和提取方法与页面交互并从以下Amazon 页面抓取页面标题和其他详细信息:

基础款亚马逊产品页面

要抓取页面,首先需要创建一个新的 Python 脚本文件(如 selenium_scraping.py)来编写抓取代码。接下来,导入 Python 包并实例化 WebDriver。

导入 Python 包并实例化 WebDriver

要导入所需模块,请在 selenium_scraping.py 顶部添加以下代码:

# import libraries
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
from selenium.webdriver.chrome.options import Options

此代码导入了 Selenium 和 WebDriver 所需的不同模块以抓取数据。

要自动浏览 Amazon URL 并抓取数据,需要实例化与 Selenium 交互的Chrome WebDriver

粘贴以下代码,它会安装 ChromeDriver 二进制文件(如果尚未安装),然后实例化它:

driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()))

注意:如果不想使用 Chrome,Selenium 还支持其他浏览器的驱动程序

定义 URL 并抓取产品标题

要自动加载网页,需要在 Python 变量(如 url)中定义 Amazon URL,然后传递给驱动程序的 get() 方法:

#Define the URL
url = "https://www.amazon.com/AmazonBasics-Matte-Keyboard-QWERTY-Layout/dp/B07WJ5D3H4/"

#load the web page
driver.get(url)

#set the maximum time to load the web page in seconds
driver.implicitly_wait(10)

运行此代码时,Selenium 会自动在 ChromeDriver 中加载 Amazon 页面链接。指定的时间范围确保网页上的所有内容和 HTML 元素完全加载。

要从 Amazon 链接中抓取产品标题,需要使用网页上显示的 ID。为此,请在浏览器中打开 Amazon URL,然后右键单击并选择检查以识别包含产品标题的 ID(如 productTitle):

检查书籍网页

接下来,调用 Selenium 的 find_element() 方法查找具有已识别 ID 值的 HTML 元素。需要传递 By.ID 作为第一个参数,ID 作为第二个参数,因为这是 find_element() 方法接受的参数:

# collect data that are within the ID of contents
title_element = driver.find_element(By.ID, "productTitle")

# extract the title
title = title_element.text

# show the title of the product
print(title)

此代码块收集 ID 属性为 productTitle 的数据,然后使用 text 属性提取产品标题。最后显示产品标题。

在终端中运行以下 Python 脚本文件以抓取产品标题:

python selenium_scraping.py

提取的标题如下所示:

Amazon Basics Low-Profile Wired USB Keyboard with US Layout (QWERTY), Matte Black

使用 CSS 选择器和标签名称抓取产品详细信息

现在你知道如何抓取标题,让我们使用 CSS 选择器和 HTML 标签从名为 About this item 的部分抓取其他详细信息:

抓取 About this item 部分

要提取产品详细信息,需要收集 Amazon 链接上具有名为 li.a-spacing-mini 的 CSS 选择器的所有 HTML 元素,然后从具有 <span> 标签名称的 HTML 元素中收集数据:

# Locate the outer span by using css selector
details_elements = driver.find_elements(By.CSS_SELECTOR, 'li.a-spacing-mini')

# Loop through all located details elements
for detail_element in details_elements:
    try:
        # Extract the detail from the inner span
        detail = detail_element.find_element(By.TAG_NAME, 'span')
        print(detail.text)
    except Exception as e:
        print("Could not extract detail:", e)

此代码从 WebElement contents 对象中收集所有具有名为 li.a-spacing-mini 的 CSS 选择器的 HTML 元素,并将元素存储在 details_elements 列表中。然后循环遍历 detail_elements 中的所有元素,使用 find_element 方法查找标签名称为 span 的 HTML 元素,使用 text 属性提取 span HTML 元素中的文本数据。

以下是从 span HTML 元素中提取的数据:

Keyboard with QWERTY layout and low-profile keys for a comfortable, quiet typing experience
Hot keys enable easy access to Media, My Computer, Mute, Volume up/down, and Calculator; 4 function keys control Previous Track, Stop, Play/Pause, and Next Track on a media player
USB wired connection
Compatible with Windows 2000, XP, Vista, 7, 8, and 10
Product Dimensions: 17.4 x 5 x 1.1 inches (LxWxH)

执行 JavaScript 代码

如果你想在动态网站的当前窗口中执行 JavaScript 代码,可以使用 execute_script() 函数。例如,你可以执行以下 JavaScript 代码来返回 https://quotes.toscrape.com/ 页面上提供的所有链接:

# import libraries
from selenium import webdriver
from pprint import pprint

# Setup Chrome WebDriver
driver = webdriver.Chrome()

# Define the URL
url = "https://quotes.toscrape.com/"

# load the web page
driver.get(url)

# set maximum time to load the web page in seconds
driver.implicitly_wait(10)

# Execute JavaScript to collect all links
javascript_code = "return Array.from(document.getElementsByTagName('a'), a => a.href);"
links = driver.execute_script(javascript_code)

print(links)

# Close the WebDriver
driver.quit()

此代码导入所需库,初始化 Chrome WebDriver 实例,并导航到指定的 URL。然后执行 JavaScript 代码,使用 execute_script() 函数收集页面上的所有链接。最后,它将链接保存在 links 变量中,打印收集到的链接,并关闭 WebDriver 实例。

输出如下所示:

['https://quotes.toscrape.com/',
'https://quotes.toscrape.com/login',
'https://quotes.toscrape.com/author/Albert-Einstein',
'https://quotes.toscrape.com/tag/change/page/1/',
'https://quotes.toscrape.com/tag/deep-thoughts/page/1/',
'https://quotes.toscrape.com/tag/thinking/page/1/',
'https://quotes.toscrape.com/tag/world/page/1/',
'https://quotes.toscrape.com/author/J-K-Rowling',
.....
]

注意:如果你打算异步执行 JavaScript 代码,请改用 execute_async_script() 函数

使用 Selenium 处理挑战和高级爬虫技术

从动态网站抓取数据通常会遇到各种挑战,包括处理分页、身份验证或 CAPTCHA。

分页需要浏览网站的多个页面以收集所有所需数据。然而,处理分页可能很困难,因为不同的网站使用不同的分页技术。你需要处理转到下一页的逻辑,并处理没有更多页面的情况。此外,有些网站有登录表单,需要身份验证才能访问受限内容,然后你才能执行任何网络爬虫任务。

如果你不熟悉 CAPTCHA,它们是一种挑战响应测试,旨在确定用户是人类还是机器人。这种安全措施通常用于防止自动化程序(机器人)访问网站或执行某些操作。然而,如果 CAPTCHA 未能自动处理,它们可能会阻止你从动态网站抓取所需的数据。

幸运的是,Selenium 提供了高级技术,可以帮助你克服这些挑战。

从多个页面提取数据

电子商务网站的各种产品详细信息,包括产品信息、价格、评论或库存情况,通常分页显示在多个产品列表页面上。

在以下示例中,你将从 books.toscrape.com 抓取书籍的标题和价格。该网站在五十个网页上列出了许多书籍:

爬取书籍的标题和价格
爬取书籍的标题和价格

要从多个页面提取数据,需要在 Python 变量中定义网站 URL,并使用 driver 对象的 get() 方法加载网页:

# Define the URL
url = "https://books.toscrape.com/"

# load the web page
driver.get(url)

要抓取数据,需要使用CSS 选择器查找包含每本书标题和价格的 HTML 标签。定位书籍标题的 CSS 选择器是 h3 > a,而查找书籍价格的 CSS 选择器是 price_color

price_color 作为价格选择器
书籍标题的 CSS 选择器 h3 a

以下是抓取每本书标题和价格的代码:

# Initialize empty list to store scraped data
books_results = []

while True:
    # Extract data
    for selector in driver.find_elements(By.CSS_SELECTOR, "article.product_pod"):
        try:
            title_element = selector.find_element(By.CSS_SELECTOR, "h3 > a")
            title = title_element.get_attribute("title")
            price_element = selector.find_element(By.CSS_SELECTOR, ".price_color")
            price = price_element.text
            books_results.append({"title": title, "price": price})
        except NoSuchElementException:
            # Handle the case where either title or price element is not found
            print("Title or price element not found.")
            continue

    # Check for next page link
    try:
        next_page_link_element = driver.find_element(By.CSS_SELECTOR, "li.next a")
        next_page_link = next_page_link_element.get_attribute("href")
        if next_page_link == "https://books.toscrape.com/catalogue/page-50.html":
            print("Reached the last page. Scraping process terminated.")
            break
        else:
            driver.get(next_page_link)
    except NoSuchElementException:
        # Handle the case where the next page link element is not found
        print("Next page link element not found.")
        break

# Close WebDriver
driver.quit()

print(books_results)

此代码使用一个名为 books_results 的空列表存储抓取的数据。它进入一个循环,从当前网页上显示的每本书提取标题和价格。循环遍历 CSS 选择器 article.product_pod 中的元素以定位每本书条目。在每本书条目中,使用 CSS 选择器 "h3 > a" 查找标题,使用 ".price_color" 查找价格。如果未找到标题或价格元素,则处理异常并继续。

在抓取完页面上的所有书籍后,检查指向下一页的链接是否存在,使用 CSS 选择器 li.next a。如果找到,则导航到下一页并继续抓取。如果没有下一页或到达最后一页(第 50 页),则抓取过程终止。最后,使用 pprint 打印存储在 books_results 列表中的抓取数据,并关闭 WebDriver。

从五十个网页上提取的数据如下所示:

[{'title': 'A Light in the Attic', 'price': '£51.77'},
{'title': 'Tipping the Velvet', 'price': '£53.74'},
{'title': 'Soumission', 'price': '£50.10'},
{'title': 'Sharp Objects', 'price': '£47.82'},
{'title': 'Sapiens: A Brief History of Humankind', 'price': '£54.23'},
{'title': 'The Requiem Red', 'price': '£22.65'},
{'title': 'The Dirty Little Secrets of Getting Your Dream Job', 'price': '£33.34'},
{'title': 'The Coming Woman: A Novel Based on the Life of the Infamous Feminist, Victoria Woodhull', 'price': '£17.93'},
{'title': 'The Boys in the Boat: Nine Americans and Their Epic Quest for Gold at the 1936 Berlin Olympics', 'price': '£22.60'}
.....
]

自动处理登录表单

许多网站,包括社交媒体平台,需要登录或用户身份验证才能访问某些数据。幸运的是,Selenium 可以自动化登录过程,使你能够访问和抓取身份验证墙后的数据。

在以下示例中,你将使用 Selenium 自动登录Quotes to Scrape 网站(一个沙盒网站),该网站列出各种名人名言。

要登录 Quotes to Scrape 网站,需要在 Python 变量中定义网站 URL,并使用 driver 对象的 get() 方法加载网页。等待十秒钟以确保页面完全加载,然后提取数据:

# Define the URL
url = "https://quotes.toscrape.com/login"

# load the web page
driver.get(url)

# set maximum time to load the web page in seconds
driver.implicitly_wait(10)

接下来,使用 XPath 查找并输入用户名和密码到登录表单中。在网页的检查页面中,用户名的输入字段名为 username,密码的输入字段名为 password

检查沙盒网站的登录页面

从此截图中可以看到用户名和密码的输入字段代码。以下是查找并填写用户名和密码,然后点击提交按钮提交表单的代码:

# Find the username field
username_field = driver.find_element(By.XPATH, "//input[@name='username']")

# Enter username
username_field.send_keys("[email protected]")

# Find the password field
password_field = driver.find_element(By.XPATH, "//input[@name='password']")

# Enter password
password_field.send_keys("secret1234")

# Submit the form
submit_button = driver.find_element(By.XPATH, "//input[@type='submit']")
submit_button.click()

# Wait for the logout link to appear
try:
    logout_link = WebDriverWait(driver, 15).until(
        EC.visibility_of_element_located((By.XPATH, "//a[contains(text(), 'Logout')]"))
    )
    print("Login successful! Logout link was found.")
except:
    print("Login failed or logout link was not found.")

# Close the browser
driver.quit()

此代码使用带有 name='username' 属性的 XPath 查找网页上的用户名输入字段://input[@name='username']。使用 send_keys() 方法将用户名 [email protected] 输入到定位的用户名字段中。然后使用带有 name='password' 属性的 XPath 查找网页上的密码输入字段://input[@name='password']

使用 send_keys() 方法将密码 secret1234 输入到定位的密码字段中。然后查找并点击登录表单的提交按钮,使用带有 type='submit' 属性的 XPath://input[@type='submit']

在成功登录后,等待最多十五秒钟以等待注销链接出现。然后使用 WebDriverWait 等待由包含“Logout”文本的 XPath 定位的元素的可见性://a[contains(text(), 'Logout')]。如果注销链接在指定时间内出现,则打印 "登录成功!找到了注销链接。"。如果注销链接未出现或登录失败,则打印 "登录失败或未找到注销链接。"

在登录过程完成后关闭浏览器会话。

输出如下所示:

登录成功!找到了注销链接。

处理 CAPTCHA

一些网站添加了 CAPTCHA,以在访问内容之前验证你是人类还是机器人。为了在抓取动态网站的数据时避免与 CAPTCHA 交互,可以实现Selenium 的无头模式。无头模式允许你在不显示浏览器的情况下运行浏览器实例。这意味着浏览器在后台运行,你可以使用 Python 脚本与其进行编程交互:

from selenium.webdriver.chrome.options import Options

# Set Chrome options for headless mode
chrome_options = Options()
chrome_options.add_argument("--headless")

# Setup Chrome WebDriver
driver = webdriver.Chrome(options=chrome_options)

此代码从 selenium.webdriver.chrome.options 导入 Options。然后配置 Chrome 选项以无头模式运行,并初始化带有这些选项的 Chrome WebDriver 实例 driver。它使你能够在不显示浏览器界面的情况下执行网络爬虫任务。

使用 Cookie

Cookie 是从你访问的网站传输并存储在你计算机上的一段数据。它包含名称、值、过期时间和路径,用于识别用户身份并加载存储的信息,包括你的登录和搜索历史。

Cookie 可以通过维护会话状态增强你的爬虫能力,这对于导航经过身份验证或个性化的部分网站至关重要。应用 Cookie 可以避免重复登录并继续抓取,从而自动减少执行时间。

网站也经常将 Cookie 作为其反爬虫机制的一部分。当你保留并使用合法浏览会话中的 Cookie 时,可以使你的请求看起来更像是普通用户的请求,并减少被屏蔽的风险。

你可以使用 WebDriver API 提供的内置方法与 Cookie 进行交互。

要将 Cookie 添加到当前浏览上下文中,请使用 add_cookie() 方法,并以字典格式提供名称和值:

# Import package
from selenium import webdriver

# Initialize the WebDriver
driver = webdriver.Chrome()

# Navigate to the base URL
driver.get("http://www.example.com")

# Adds the cookie into the WebDriver Session
driver.add_cookie({'name': 'session_id', 'value': 'abc123', 'domain': 'example.com', 'path': '/', 'expiry': None})

# Refresh the page to apply the cookies
driver.refresh()

# Wait for a few seconds to ensure cookies are applied and the page is loaded
time.sleep(5)

# Now you can proceed with any scraping task that require the cookies to be set

在这里,你使用 add_cookie() 方法将 Cookie 添加到你的网络爬虫任务中。然后使用 refresh() 方法刷新页面以应用 Cookie,并等待五秒钟以确保应用 Cookie,然后再继续任何需要设置 Cookie 的爬虫任务。

可以使用 get_cookies() 方法返回所有可用的 Cookie。如果你想返回特定 Cookie 的详细信息,需要传递 Cookie 的名称,如下所示:

# import package
from selenium import webdriver

# Initialize the WebDriver
driver = webdriver.Chrome()

# Navigate to url
driver.get("http://www.example.com")

# Adds the cookie into current browser context
driver.add_cookie({"name": "foo", "value": "bar"})

# Get cookie details with named cookie 'foo'
print(driver.get_cookie("foo"))

此代码块返回名为 foo 的 Cookie 的详细信息。

注意:如果你想了解更多处理 Cookie 的方法,请访问 Selenium 文档页面这里

网络爬虫的最佳实践和道德考虑

在进行网络爬虫时,遵循旨在确保从网站负责任地提取数据的最佳实践非常重要。这包括遵守 robots.txt 文件,该文件概述了爬行和抓取网站的规则。

确保避免过多的请求而使服务器过载,这会破坏网站的功能并对用户体验产生负面影响。这种过载可能导致拒绝服务(DoS)攻击

网络爬虫还会引发法律和道德问题。例如,未经许可抓取受版权保护的材料可能导致法律后果。至关重要的是,在进行网络爬虫之前,仔细评估法律和道德影响。你可以通过阅读网站提供的数据隐私政策、知识产权和条款与条件来做到这一点。

结论

从动态网站抓取数据的过程需要努力和计划。使用 Selenium,可以自动与任何动态网站进行交互并收集数据。

在本文中,你学习了如何使用 Selenium Python 包从 YouTube 和其他沙盒网站上显示的各种 HTML 元素中抓取数据。你还学习了如何使用高级技术处理分页、登录表单和 CAPTCHA 等不同的挑战。所有教程的源代码都可以在这个GitHub 仓库中找到。

虽然可以使用 Selenium 抓取数据,但这很耗时,并且很快变得复杂。因此,建议使用 Bright Data。其爬虫浏览器支持 Selenium 和各种类型的代理,你可以立即开始提取数据。考虑开始免费试用并利用 Bright Data 提供的爬虫 API,而不是维护你的服务器和代码。