既然我们已经介绍了些理论概念,现在可以放心地进入实践部分了。在本节中,我将向您展示如何使用 Selenium 构建一个网页爬虫。进行此项目时,请确保您的机器已安装 Python 和 Chrome。
#1:配置环境
照例,在 Python 中我们应将所有内容封装在虚拟环境内。如果您不熟悉虚拟环境,请先阅读这篇文章。现在,让我们打开一个新的终端窗口,并执行以下操作:
- 创建一个新文件夹
- 进入该文件夹
- 创建新的虚拟环境
- 激活虚拟环境
~ mkdir headless_scraper
~ cd headless_scraper
~ python3 -m venv env
~ source env/bin/activate
#2:安装依赖项
很明显,我们的项目需要 Selenium 和一个 Web 驱动程序。幸运的是,我们可以使用 Python 的包管理器 `pip` 安装这两者。在同一个终端窗口中,输入以下命令:
~ pip install selenium webdriver-manager
现在一切准备就绪!我们可以开始实际编码了。先说明一下,本文主要关注与无头浏览器的交互。完整的网页抓取解决方案需要付出更多努力。但我相信,只要您关注我们的博客文章,很快就能掌握。
#3:启动自动化浏览器
目前,我们已经有了项目,但还没有可执行的文件。让我们创建一个新的 `.py` 文件,并在 IDE 中打开它:
~ touch headles_scraper.py
~ code .
此时你应该已经进入 Visual Studio Code 或你的 IDE 了。你可以从在 `handle_scraper.py` 中导入必要的包开始:
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
该包可帮助你轻松管理 Selenium 支持的各类浏览器的 WebDriver。你可以在此处阅读更多相关信息。接下来,我们需要使用 Selenium 创建一个新浏览器并打开一个网站:
driver = webdriver.Chrome(ChromeDriverManager().install())
driver.get('https://webscrapingapi.com')
现在运行此文件,你会发现它确实有效。但它并非使用 Python 无头浏览器,而是打开了一个带界面的 Chrome 窗口:
#4:实现无头模式
我们的目标是构建一个资源友好的网页爬虫。因此,理想情况下,我们希望使用 Selenium 打开无头浏览器。幸运的是,有一种简单的方法可以将 Selenium 从有头模式切换为无头模式。我们只需利用 Chrome WebDriver 的 `Options` 即可。因此,让我们导入 `Options` 并添加两行代码:
...
from selenium.webdriver.chrome.options import Options
...
options = Options()
options.headless = True
driver = webdriver.Chrome(ChromeDriverManager().install(), options=options)
driver.get('https://webscrapingapi.com')
再次运行脚本。如您所见,这次没有弹出窗口。但它真的在后台运行吗?一个快速可视化并验证的方法是使用 Selenium 截屏。只需在脚本末尾添加这一行:
driver.get_screenshot_as_file('headless.png')
如果一切顺利,你应该会得到和我一样的图片:
#5:添加数据抓取功能
什么是网页抓取工具?简而言之,网页抓取工具本质上是一个通过调用服务器端点并从中收集数据的程序。对于网站而言,这些数据通常由 HTML 文件组成。但如今某些服务器也会提供 JSON 对象。因此,我们统一使用“数据”这一术语。在接下来的部分中,让我们设定更高的目标。让我们尝试使用面向对象编程!我们的目标是:
- 创建一个 Scraper 类
- 添加一个提取原始数据的方法
- 添加一个从单个元素中提取数据的方法
- 添加一个从同类元素中提取数据的方法
因此,我们需要构建三个基本方法。但就学习而言,这三个方法不仅为网页抓取铺平了道路,也为 Python 中的面向对象编程(OOP)打开了大门。我觉得这非常酷!现在,让我们删除之前编写的所有代码,从头开始:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.remote.webelement import WebElement
class Scraper:
def __init__(self, headless: bool = True) -> None:
self.headless = headless
pass
def setup_scraper(self) -> None:
self.options = Options()
self.options.headless = self.headless
self.driver = webdriver.Chrome(options=self.options)
def navigate(self, target) -> None:
self.driver.get(target) if target else print('[!] No target given. Please specify a URL.')
def extract_raw_data(self) -> str:
return self.driver.page_source
def extract_single_element(self, selector: str, selector_type: By = By.CSS_SELECTOR) -> WebElement:
return self.driver.find_element(selector_type, selector)
def extract_all_elements(self, selector: str, selector_type: By = By.CSS_SELECTOR) -> list[WebElement]:
return self.driver.find_elements(selector_type, selector)
我添加了类型注解,主要是为了便于理解,而非提升性能。这样,你就能从输入/输出的角度直观地理解这个程序。现在,这些方法基本上不言自明。我们并没有对数据执行任何操作,只是将其返回。如果你愿意,这可以作为你构建一个使用 Python 无头浏览器的复杂爬虫的起点。
目前,执行该文件不会产生任何效果。这是因为我们仅声明了 Scraper 及其方法,现在需要实际调用它们。因此,让我们添加以下代码:
# Initialize a new Scraper and navigate to a target
scraper = Scraper()
scraper.setup_scraper()
scraper.navigate('https://httpbin.org')
# Extract and print the entire HTML document
raw_data = scraper.extract_raw_data()
print(raw_data)
# Extract and print an element by its class name
single_element = scraper.extract_single_element('title', By.CLASS_NAME)
print(single_element.text)
# Extract and print all elements belonging to a tag type
all_elements = scraper.extract_all_elements('a', By.TAG_NAME)
print([el.get_attribute('href') for el in all_elements])
就这样。如果你现在运行脚本,就能看到一些操作发生了。再次强调,这仅仅是一个旨在帮助你入门的原型。如果你想进一步了解如何在网页抓取中使用 Python 无头浏览器,我建议你:
这样,你既能积累知识,又能为个人作品集增添一个项目。