---
title: "2025年用 Python 与 Selenium 进行数据抓取：分步指南"
description: "学习使用 Python 与 Selenium 进行数据抓取，了解如何从动态网站提取数据、使用无头浏览器与代理，并绕过反机器人系统。"
url: "https://marsproxies.cn/blog/selenium-web-scraping/"
---

- [EN ](https://marsproxies.com/blog/selenium-web-scraping/?locale-change "英语")
  [CN](https://marsproxies.cn/blog/selenium-web-scraping/?locale-change "语言切换器")

[联系销售](https://marsproxies.cn/contact-sales/) [注册](https://dashboard.marsproxies.com/register/) [登录](https://dashboard.marsproxies.com/login/)

[联系销售](https://marsproxies.cn/contact-sales/) [注册](https://dashboard.marsproxies.com/register/) [登录](https://dashboard.marsproxies.com/login/)

[联系销售](https://marsproxies.cn/contact-sales/)

[登录](https://dashboard.marsproxies.com/login/) [注册](https://dashboard.marsproxies.com/register/)

- [EN ](https://marsproxies.com/blog/selenium-web-scraping/?locale-change "英语")
  [CN](https://marsproxies.cn/blog/selenium-web-scraping/?locale-change "语言切换器")

[返回博客](https://marsproxies.cn/blog/) 2025年7月22日

# 2025年用 Python 与 Selenium 进行数据抓取：分步指南

[操作指南](https://marsproxies.cn/blog/category/how-to/)

\-

目录

1. [Selenium 是什么？为何适合用于数据抓取？](https://marsproxies.cn/blog/selenium-web-scraping/#b-selenium-%E6%98%AF%E4%BB%80%E4%B9%88%E4%B8%BA%E4%BD%95%E9%80%82%E5%90%88%E7%94%A8%E4%BA%8E%E6%95%B0%E6%8D%AE%E6%8A%93%E5%8F%96)
2. [搭建 Selenium 抓取程序](https://marsproxies.cn/blog/selenium-web-scraping/#b-%E6%90%AD%E5%BB%BA-selenium-%E6%8A%93%E5%8F%96%E7%A8%8B%E5%BA%8F)
3. [第一步：安装 Python](https://marsproxies.cn/blog/selenium-web-scraping/#b-%E7%AC%AC%E4%B8%80%E6%AD%A5%E5%AE%89%E8%A3%85-python)
4. [第二步：安装 Selenium](https://marsproxies.cn/blog/selenium-web-scraping/#b-%E7%AC%AC%E4%BA%8C%E6%AD%A5%E5%AE%89%E8%A3%85-selenium)
5. [第三步：安装 undetected-chromedriver](https://marsproxies.cn/blog/selenium-web-scraping/#b-%E7%AC%AC%E4%B8%89%E6%AD%A5%E5%AE%89%E8%A3%85-undetected-chromedriver)
6. [准备工作环境](https://marsproxies.cn/blog/selenium-web-scraping/#b-%E5%87%86%E5%A4%87%E5%B7%A5%E4%BD%9C%E7%8E%AF%E5%A2%83)
7. [开始构建 Selenium 抓取程序](https://marsproxies.cn/blog/selenium-web-scraping/#b-%E5%BC%80%E5%A7%8B%E6%9E%84%E5%BB%BA-selenium-%E6%8A%93%E5%8F%96%E7%A8%8B%E5%BA%8F)
8. [第一步：编写导入语句](https://marsproxies.cn/blog/selenium-web-scraping/#b-%E7%AC%AC%E4%B8%80%E6%AD%A5%E7%BC%96%E5%86%99%E5%AF%BC%E5%85%A5%E8%AF%AD%E5%8F%A5)
9. [第二步：配置日志系统](https://marsproxies.cn/blog/selenium-web-scraping/#b-%E7%AC%AC%E4%BA%8C%E6%AD%A5%E9%85%8D%E7%BD%AE%E6%97%A5%E5%BF%97%E7%B3%BB%E7%BB%9F)
10. [第三步：添加代理](https://marsproxies.cn/blog/selenium-web-scraping/#b-%E7%AC%AC%E4%B8%89%E6%AD%A5%E6%B7%BB%E5%8A%A0%E4%BB%A3%E7%90%86)
11. [第四步：添加 User-Agent](https://marsproxies.cn/blog/selenium-web-scraping/#b-%E7%AC%AC%E5%9B%9B%E6%AD%A5%E6%B7%BB%E5%8A%A0-user-agent)
12. [第五步：配置 undetected-chromedriver](https://marsproxies.cn/blog/selenium-web-scraping/#b-%E7%AC%AC%E4%BA%94%E6%AD%A5%E9%85%8D%E7%BD%AE-undetected-chromedriver)
13. [第六步：编写抓取逻辑](https://marsproxies.cn/blog/selenium-web-scraping/#b-%E7%AC%AC%E5%85%AD%E6%AD%A5%E7%BC%96%E5%86%99%E6%8A%93%E5%8F%96%E9%80%BB%E8%BE%91)
14. [第 7 步：编写主执行层](https://marsproxies.cn/blog/selenium-web-scraping/#b-%E7%AC%AC-7-%E6%AD%A5%E7%BC%96%E5%86%99%E4%B8%BB%E6%89%A7%E8%A1%8C%E5%B1%82)
15. [Selenium 数据抓取常见问题](https://marsproxies.cn/blog/selenium-web-scraping/#b-selenium-%E6%95%B0%E6%8D%AE%E6%8A%93%E5%8F%96%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98)
16. [什么情况下不适合用 Selenium 做数据抓取](https://marsproxies.cn/blog/selenium-web-scraping/#b-%E4%BB%80%E4%B9%88%E6%83%85%E5%86%B5%E4%B8%8B%E4%B8%8D%E9%80%82%E5%90%88%E7%94%A8-selenium-%E5%81%9A%E6%95%B0%E6%8D%AE%E6%8A%93%E5%8F%96)
17. [推荐做法与法律注意事项](https://marsproxies.cn/blog/selenium-web-scraping/#b-%E6%8E%A8%E8%8D%90%E5%81%9A%E6%B3%95%E4%B8%8E%E6%B3%95%E5%BE%8B%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9)
18. [结语](https://marsproxies.cn/blog/selenium-web-scraping/#b-%E7%BB%93%E8%AF%AD)

\-

坦白说，数据抓取早已不复往日那般容易。互联网如今更像一座堡垒，几乎每个网站都在想办法对抗机器人。就连互联网基础设施领域知名的 Cloudflare，如今也默认帮助网站[拦截 AI 爬虫](https://www.cloudflare.com/press-releases/2025/cloudflare-just-changed-how-ai-crawlers-scrape-the-internet-at-large/)。

数据提取正变得越来越困难。如果想继续在这场竞争中立足，用 Python 结合 Selenium 进行数据抓取是一个不错的起点。

本文将介绍如何借助真实浏览器从动态网站采集数据，同时避免被封锁。

## Selenium 是什么？为何适合用于数据抓取？

Selenium 已经存在多年，最初是一款用于测试 Web 应用的浏览器自动化框架，其核心引擎 Selenium WebDriver 负责控制浏览器。

借助 [Selenium WebDriver](https://www.selenium.dev/documentation/webdriver/)，您可以点击按钮、填写表单、滚动页面、定位元素——浏览器里能做的事，用代码同样能够实现。

那么，为什么要用 Selenium 来做数据抓取？为什么要选择一款并非为此而生的工具？

如今大多数网站并非一次性加载完成，而是逐步构建页面内容。Selenium 能让您访问浏览器在页面完全加载后实际呈现的内容。

您面对的还有十分严密的防护机制：Cloudflare、PerimeterX、BotGuard 等反机器人工具会识别浏览器指纹并当场拦截机器人。不过，如果使用 Selenium 控制[无头浏览器](https://marsproxies.cn/blog/headless-browser/)，并搭配代理与更接近真人的行为模式，就有机会突破这些防线。

此外，数据并非总是直接可见。有些抓取任务需要点击、滚动或触发弹窗才能显示目标内容，而基于 Selenium 构建的抓取程序同样能应对这类场景。

## 搭建 Selenium 抓取程序

前面已经说明了为什么 Selenium 在数据抓取领域依然占据重要地位。事实是，如今大多数网站不会轻易交出数据，您必须在外观和行为上接近真实用户，否则就会被封锁。

接下来，我们将一步步构建一个简单的 Selenium 抓取程序，从 [Books to Scrape](https://books.toscrape.com/) 网站的前三个分类中提取书名、评论、价格与库存状态。流程虽然基础，但这套结构能帮助您今后应对更复杂的抓取任务。

目标是灵活性。您将学会如何编写简洁、可扩展的代码，从真实的动态网站中提取数据，同时提前规避常见的阻碍。

准备好了吗？开始吧。

### 第一步：安装 Python

首先，检查 Python 是否可用。打开终端并执行：

```javascript
python --version
```

如果看到 Python 3.x.x，就可以继续往下走了。如果没有，请前往 [python.org](http://python.org/) 下载安装，然后重新检查一遍。

### 第二步：安装 Selenium

下一步是在本机安装 Selenium WebDriver，它是控制真实浏览器、实现抓取任务自动化的核心引擎。

```javascript
pip install selenium
```

就是这么简单：执行命令，等待安装完成，即可进入下一步。

### 第三步：安装 undetected-chromedriver

要想更难被检测，还需要再装一个组件：[undetected-chromedriver](https://pypi.org/project/undetected-chromedriver/)。它是对 Selenium 的 Chrome WebDriver 的一层封装，能够修补浏览器指纹、模拟无头浏览器的真实表现，帮助您在抓取时不触发防护机制。

```javascript
pip install undetected-chromedriver
```

执行安装命令。正是它让您能够融入正常流量、持续提取数据而不被反复封锁。至此环境搭建完成，接下来就可以编写即使在网站全力阻挡的情况下也能采集数据的抓取代码了。

## 准备工作环境

工具已经就绪，现在开始打基础。打开终端，进入用于存放本项目的文件夹：

```javascript
cd Desktop 
```

新建一个文件夹：

```javascript
mkdir “Selenium Web Scraper”
```

然后进入该文件夹：

```javascript
cd Selenium Web Scraper 
```

接着创建 Python 文件：

```javascript
echo. > Seleniumwebscraper.py
```

用您习惯的编辑器打开它，开始动手吧。

## 开始构建 Selenium 抓取程序

接下来编写一个 Selenium 抓取脚本，逐个分类从 Books to Scrape 中提取数据。您将学会如何提取星级评分、书名、库存状态等信息，同时不触发防护机制、不留下指纹痕迹。

先从简单流程开始：打开网站、点击“Travel”分类、抓取书籍数据，然后关闭。接下来，我们会更换浏览器、代理与身份信息，针对“Mystery”和“Historical Fiction”分类重复这一流程。

之所以要分步进行，原因很简单：在同一页面停留越久，或连续抓取多个分类，触发警报的概率就越高。借助 Selenium、无头浏览器以及合理的会话轮换，您可以分阶段抓取动态内容，让整个抓取任务更干净、更难被检测。

### 第一步：编写导入语句

第一步：导入必要的模块，以下是我们需要用到的：

```python
import undetected_chromedriver as uc
from selenium.webdriver.common.by import By
import time
import random
import pandas as pd
import logging
import os
```

下面逐一说明这些模块的作用：

### 第二步：配置日志系统

下一步是配置 Python 内置的日志系统。日志能让您清楚地了解代码运行时的状态，以下是各个日志级别的含义：

- DEBUG：用于深入排查问题的极详细信息
- INFO：抓取任务的常规进度信息
- WARNING：提示出现异常但尚不致命的情况
- ERROR：报告出现故障的情况
- CRITICAL：标记可能导致整个流程中断的严重故障

这里我们使用 INFO 级别，既能让抓取脚本的运行状态保持透明，又不会被过多技术细节淹没。如果需要排查连接中断或元素缺失之类的问题，可以将级别调高到 DEBUG。

```javascript
logging. basicConfig (level=logging. INFO , format= '[%(asctime)s] %(message)s' )
```

### 第三步：添加代理

对于数据抓取而言，代理几乎是必备条件，尤其是面对带有反机器人防护的动态网站时。Books to Scrape 这类网站不用代理也没问题，但任何设有严格反机器人规则的网站都会很快对您进行速率限制或直接封锁。来自同一个 IP 的每一次请求都会不断消耗您的伪装，直到您彻底遭到封锁。

本次搭建选用 MarsProxies 的[轮换住宅代理](https://marsproxies.cn/proxies/residential-proxies/)。单一干净端点让操作更简单，IP 轮换由 MarsProxies 自动处理。但如果抓取任务规模更大，建议每个页面至少使用两个来自不同地区的黏性会话 IP，这样每次访问页面都能保持“新鲜”状态，也更便于控制。更深入的示例可参考我们的[亚马逊数据抓取](https://marsproxies.cn/blog/amazon-web-scraping/)指南。

以下是 MarsProxies 提供的轮换住宅代理端点：

```javascript
PROXIES = [
    "http://ultra.marsproxies.com:44443" ,
    # Add more proxies if you have them
]
```

undetected-chromedriver 在处理用户名密码认证的代理时容易出问题，更顺畅的做法是在供应商端对您的 IP 地址进行白名单认证，这样会话才能保持干净。完整的白名单设置步骤，请参阅我们关于[如何使用 MarsProxies 住宅代理](https://marsproxies.cn/blog/residential-proxies-guide/)的详细指南。

### 第四步：添加 User-Agent

接下来需要准备 User-Agent。对于 Books to Scrape 这类轻量目标，几个 User-Agent 就足够了，但像 Amazon 或 Best Buy 这样的实际抓取目标，如果处理不当，很快就会被标记。

现代网站采用多层检测机制，不仅会检查 User-Agent 字符串，还会核查完整的浏览器指纹：屏幕尺寸、时区、语言、WebGL、Canvas 以及硬件信息。如果声称使用 iPhone，行为却呈现桌面端特征，这类不一致会立刻被识别出来。

解决办法是让各项参数完全对齐：为每个 User-Agent 搭配正确的屏幕尺寸、时区、语言与 GPU 信息，使浏览器的外观与行为都符合所声称的身份。

以下是我们的 User-Agent 代码块：

```javascript
USER_AGENTS = [
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.6422.112 Safari/537.36" ,
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.6422.112 Safari/537.36" ,
    "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.6422.112 Safari/537.36" ,
]
```

这里使用 Windows、Mac 与 Linux 这三种 User-Agent，因为它们是真实浏览器中最常见的指纹类型，三者统一使用 Chrome 125 这一稳定版本，与当前真实用户所使用的版本保持一致。

简单回顾一下，目前脚本应该是这样的：

```python
import undetected_chromedriver as uc
from selenium.webdriver.common.by import By
import time
import random
import pandas as pd
import logging
import os
```

```javascript
# Logging Setup
logging. basicConfig (level=logging. INFO , format= '[%(asctime)s] %(message)s' )
```

```javascript
# Proxies and User-Agents
PROXIES = [
    "http://ultra.marsproxies.com:44443" ,
    # Add more proxies if you have them
]
USER_AGENTS = [
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.6422.112 Safari/537.36" ,
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.6422.112 Safari/537.36" ,
    "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.6422.112 Safari/537.36" ,
]
```

### 第五步：配置 undetected-chromedriver

undetected-chromedriver 是整个 Selenium 技术栈的核心所在。只要抓取过稍具规模的动态页面，就会知道它往往是成败的关键。工具本身并不能解决所有问题，只有把它暴露出的每一个指纹都控制住，才能真正做到更难被检测。

对 Books to Scrape 来说，这样做有些大材小用。但面对防护严密的目标，必须把各项信息都模拟到位才能顺利通过检测。以下是需要重点控制的几项：

- 轮换 User-Agent

真实用户所使用的 Chrome 版本并不统一，因此抓取程序需要在符合当下真实使用情况的 User-Agent 之间轮换，这一点在现代数据抓取中是必不可少的。

- 设置屏幕尺寸

屏幕尺寸必须与 User-Agent 相匹配。声称是 iPhone 却使用 1920x1080 分辨率，会立刻触发警报。网站会对这两项信息进行交叉核验，因为真实设备与浏览器始终是一致的，您的设置也应如此。

- 设置语言

语言请求头会告诉网站您的浏览器使用的语言。留空或设置不一致，很容易暴露机器人身份，务必显式设置语言，例如 --lang=en-US,en 是一个较稳妥的默认值。

- 设置时区

时区必须与代理所在地区保持一致。如果 IP 显示在印度，而浏览器报告的却是美国东部时间，这种不一致会立刻暴露问题。时区应始终与代理位置同步，以降低被检测的风险。

- 无头模式

机器人偏爱无头模式，网站对此也心知肚明，部分检测系统会自动拦截无头浏览器。条件允许时应尽量使用完整浏览器模式，虽然速度更慢，但行为会更接近真人。只有在速度优先于隐蔽性时，才考虑使用无头模式。

并非每一项抓取任务都需要做到极致隐蔽，可以先从基础配置入手，再按需加码。如果目标网站防护较弱，这套配置就足以完成任务；如果防护收紧，再调整 User-Agent，在不触发警报的情况下继续提取数据。

```python
# Driver Setup
def create_driver (proxy, user_agent) :
    options = uc.ChromeOptions( )
    options.add_argument( f'--proxy-server= {proxy} ' )
    options.add_argument( f'user-agent= {user_agent} ' )
    options.add_argument( '--no-sandbox' )
    options.add_argument( '--disable-blink-features=AutomationControlled' )
    options.add_argument( '--lang=en-US,en' )
    driver = uc.Chrome(options=options)
    driver.execute_cdp_cmd( 'Network.setUserAgentOverride' , { "userAgent" : user_agent} )
    return driver
```

下面逐项说明：

### 第六步：编写抓取逻辑

环境搭建完成后，就可以专注于抓取数据本身了。整个流程需要两部分：一个函数负责从页面提取数据，另一个负责控制抓取流程。我们先从提取部分入手，获取动态内容中的书名、价格等信息。

在提取数据之前，您需要先了解网站的结构，这有助于您确定函数需要定位哪些元素。在本例中，我们关注以下四项内容：

- 书名
- 价格
- 库存状态
- 星级评分

下面我们来看看如何找到这些元素，并为每一个构建对应的 CSS 选择器。

#### 打开网站并检查标题

- 访问 Books to Scrape
- 滚动到您看到的第一本书
- 直接右键点击书名（蓝色链接）
- 在弹出的菜单中点击“检查”

#### 查看 HTML 结构

查找高亮显示的 HTML，您会看到类似这样的内容：

```markup
<h3 >
    <a href = "..." title = "Book Title" >Book Title</a >
</h3 >
```

这个 CSS 选择器展示了存储标题的标签（h3）和元素（a）。

#### 定位星级评分

在同一个商品卡片内，查看标题上方的位置，您会看到类似这样的内容：

```markup
<p class = "star-rating Three" > </p >
```

这说明评分信息隐藏在类名中（如 Three、Four 等）。

#### 查找价格

在 HTML 中向下查找，直到看到：

```markup
<div class = "product_price" >
    <p class = "price_color" >£51.77</p >
</div >
```

您可以从 p.price\_color 内的文本中提取价格。

#### 检查库存状态

在同一个 product\_price 的 div 中，您会找到：

```markup
<p class = "instock availability" >
    In stock
</p >
```

这里就是提取库存状态（“In stock”与否）的位置。现在，我们可以利用这些信息编写以下代码：

```python
# Extract Book Details
def extract_books (driver) :
    books = [ ]
    cards = driver.find_elements(By.CSS_SELECTOR, 'article.product_pod' )
    for card in cards:
        try :
            title = card.find_element(By.TAG_NAME, 'h3' ) .text.strip( )
            price = card.find_element(By.CLASS_NAME, 'price_color' ) .text.strip( )
            availability = card.find_element(By.CLASS_NAME, 'availability' ) .text.strip( )
            star_element = card.find_element(By.CSS_SELECTOR, 'p.star-rating' )
            star_rating = star_element.get_attribute( 'class' ) .split( ) [ - 1 ]
            books.append( {
                'title' : title,
                'price' : price,
                'availability' : availability,
                'star_rating' : star_rating
            } )
        except Exception as e:
            logging.warning( f"Skipping book due to error:  {e} " )
            continue
    return books
```

以下是各部分的含义：

接下来，您需要编写一个函数来控制每个页面的抓取流程：该函数会使用随机代理和 User-Agent 启动一个全新的浏览器会话，加载目标 URL，并调用数据提取逻辑来获取详细信息；如果找到数据，就将其保存为 CSV 文件；如果没有，则记录问题、等待片刻后重试。

以下是该函数的代码：

```python
# Scrape a Single Page with Fresh Identity Each Time
def scrape_page (url, output_file, max_retries= 3 ) :
    for attempt in range (max_retries) :
        proxy = random.choice(PROXIES)
        user_agent = random.choice(USER_AGENTS)
        driver = create_driver(proxy, user_agent)
        try :
            driver.get(url)
            time.sleep(random.uniform( 3 , 6 ) )
            books = extract_books(driver)
            if books:
                df = pd.DataFrame(books)
                file_exists = os.path.isfile(output_file)
                df.to_csv(output_file, mode= 'a' , index= False , header= not file_exists)
                logging.info( f" Extracted  { len (books) }  books from  {url} " )
                break
            else :
                raise ValueError( "No books extracted." )
        except Exception as e:
            logging.error( f" Attempt  {attempt + 1 }  failed:  {e} " )
            time.sleep(random.uniform( 2 , 5 ) )
        finally :
            driver.quit( )
            logging.info( "Session closed." )
```

我们来看看它的工作原理：

### 第 7 步：编写主执行层

完成数据抓取逻辑后，接下来需要规划要抓取的分类。这种结构可以让您为每个分类分配一个或多个 URL，每个 URL 都会在使用全新代理和身份的全新浏览器会话中运行，帮助您安全地从动态网页抓取数据，且不留下可识别的痕迹。

代码如下：

```typescript
# Main Execution: Rotate Identity Per Page
categories = {
    'Travel' : [
        'http://books.toscrape.com/catalogue/category/books/travel_2/index.html' ,
        # Add page 2 , page 3 URLs if needed
    ] ,
    'Mystery' : [
        'http://books.toscrape.com/catalogue/category/books/mystery_3/index.html' ,
        # Add more pages if needed
    ] ,
    'Historical Fiction' : [
        'http://books.toscrape.com/catalogue/category/books/historical-fiction_4/index.html' ,
        # Add more pages here too
    ] ,
}
```

设置好分类和 URL 后，最后一步就是执行层：在这一部分，您需要让 Selenium WebDriver 遍历每个分类，并从每个 URL 抓取数据。

```typescript
for category, urls in categories. items ( ) :
    output_file = f'{category.lower().replace(" ", "_")}_books.csv'
    for url in urls:
        scrape_page (url, output_file)
```

这部分代码会为每个分类设置文件名（例如 travel\_books.csv 或 mystery\_books.csv），让数据保持有序；然后遍历您定义的每个 URL，每次都使用新的代理和 User-Agent 启动全新的浏览器会话，以安全地抓取数据。

以下是完整的 Selenium 抓取脚本：

```python
import undetected_chromedriver as uc
from selenium.webdriver.common.by import By
import time
import random
import pandas as pd
import logging
import os
# Logging Setup
logging.basicConfig(level=logging.INFO, format = '[%(asctime)s] %(message)s' )
# Proxies and User-Agents
PROXIES = [
    "http://ultra.marsproxies.com:44443" ,
    # Add more proxies if you have them
]
USER_AGENTS = [
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.6422.112 Safari/537.36" ,
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.6422.112 Safari/537.36" ,
    "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.6422.112 Safari/537.36" ,
]
# Driver Setup
def create_driver (proxy, user_agent) :
    options = uc.ChromeOptions( )
    options.add_argument( f'--proxy-server= {proxy} ' )
    options.add_argument( f'user-agent= {user_agent} ' )
    options.add_argument( '--no-sandbox' )
    options.add_argument( '--disable-blink-features=AutomationControlled' )
    options.add_argument( '--lang=en-US,en' )
    driver = uc.Chrome(options=options)
    driver.execute_cdp_cmd( 'Network.setUserAgentOverride' , { "userAgent" : user_agent} )
    return driver
# Extract Book Details
def extract_books (driver) :
    books = [ ]
    cards = driver.find_elements(By.CSS_SELECTOR, 'article.product_pod' )

    for card in cards:
        try :
            title = card.find_element(By.TAG_NAME, 'h3' ) .text.strip( )
            price = card.find_element(By.CLASS_NAME, 'price_color' ) .text.strip( )
            availability = card.find_element(By.CLASS_NAME, 'availability' ) .text.strip( )
            star_element = card.find_element(By.CSS_SELECTOR, 'p.star-rating' )
            star_rating = star_element.get_attribute( 'class' ) .split( ) [ - 1 ]
            books.append( {
                'title' : title,
                'price' : price,
                'availability' : availability,
                'star_rating' : star_rating
            } )
        except Exception as e:
            logging.warning( f"Skipping book due to error:  {e} " )
            continue
    return books
# Scrape a Single Page with Fresh Identity Each Time
def scrape_page (url, output_file, max_retries= 3 ) :
    for attempt in range (max_retries) :
        proxy = random.choice(PROXIES)
        user_agent = random.choice(USER_AGENTS)
        driver = create_driver(proxy, user_agent)
        try :
            driver.get(url)
            time.sleep(random.uniform( 3 , 6 ) )

            books = extract_books(driver)
            if books:
                df = pd.DataFrame(books)
                file_exists = os.path.isfile(output_file)
                df.to_csv(output_file, mode= 'a' , index= False , header= not file_exists)
                logging.info( f" Extracted  { len (books) }  books from  {url} " )
                break
            else :
                raise ValueError( "No books extracted." )
        except Exception as e:
            logging.error( f" ] Attempt  {attempt + 1 }  failed:  {e} " )
            time.sleep(random.uniform( 2 , 5 ) )
        finally :
            driver.quit( )
            logging.info( "Session closed." )
# Main Execution: Rotate Identity Per Page
categories = {
    'Travel' : [
        'http://books.toscrape.com/catalogue/category/books/travel_2/index.html' ,
        # Add page 2, page 3 URLs if needed
    ] ,
    'Mystery' : [
        'http://books.toscrape.com/catalogue/category/books/mystery_3/index.html' ,
        # Add more pages if needed
    ] ,
    'Historical Fiction' : [
        'http://books.toscrape.com/catalogue/category/books/historical-fiction_4/index.html' ,
        # Add more pages here too
    ] ,
}
for category, urls in categories.items( ) :
    output_file = f' {category.lower( ) .replace( " " , "_" ) } _books.csv'
    for url in urls:
        scrape_page(url, output_file)
```

要运行代码，只需回到之前创建的终端会话，执行以下命令：

```javascript
python Extractor.py
```

输出结果如下：

该脚本完全按照我们的设计运行：加载了三个全新会话，从每个分类提取数据，并分别保存到不同的 CSV 文件中。但不得不承认，Books to Scrape 这个网站相当友好。

现实世界中的数据抓取，尤其是在大型网站上，完全是另一个难度级别：如今的反机器人防护更具挑战性，您的抓取脚本也需要更加谨慎。接下来我们来聊聊可能出现的问题。

## Selenium 数据抓取常见问题

数据抓取变得如此困难，原因很简单：AI 彻底改变了整个格局。OpenAI 等公司抓取了数十亿个网页，用未经许可获取的内容训练模型。出版商察觉到了这一点——他们看到自己的作品被使用、二次加工，并被从未同意提供内容的系统用来牟利。

于是，他们开始强力反击。

如今，当您在动态网页上运行自定义的 Selenium 抓取程序时，面对的正是这种反击所塑造的环境。如果您想抓取数据，就必须预料到会遇到阻力，并让抓取脚本具备应对这些阻力的能力。

以下是抓取真实网站时常遇到的一些问题：

- 有时候，您的抓取脚本运行得很顺利：日志正常、会话正常关闭，一切看起来都没问题，直到您打开 CSV 文件，却发现里面是空的。这其实是一种软封锁：网站向您返回了专门针对机器人的占位内容，比如空容器、占位符或被剥离的数据。应在继续抓取前加入检查逻辑，确认页面中确实存在真实内容，以免白白浪费时间抓取空数据。
- 接下来，检查您的浏览器指纹。轮换固然重要，但轮换得不严谨同样会让您被标记。如果代理显示法国，User-Agent 却是 iPhone，屏幕尺寸是桌面端大小，时区又显示纽约——那您已经输了。目标网站会察觉到这种不一致，对您实施软封锁，而您却在排查错误的方向。请确保整个抓取技术栈中的浏览器指纹始终保持一致。
- 代理池同样重要。来路随机、地点杂乱的 IP 会直接触发警报。要安全地扩展 Selenium 的使用规模，就需要构建一套干净、多样化且与行为模式保持一致的代理轮换策略。住宅代理（尤其是 MarsProxies 提供的住宅代理）在这方面很有帮助，因为它们在目标网站看来与真实用户别无二致，稳定性强，在正规网站上运行抓取脚本时被封锁的概率也低得多。
- 最后，注意您的机器人行为方式：不要一打开页面就立刻开始滚动。有些网站会故意延迟加载动态内容，等待那种一看就知道是机器人的滚动行为。如果动作太快，您永远只能抓取到空白页面。可以加入点击、悬停、滚动停顿等更接近真实用户行为的操作，目标是在加载内容的同时不被识别出来。

## 什么情况下不适合用 Selenium 做数据抓取

到这里，您已经明白 [Selenium](https://marsproxies.cn/blog/bypass-captcha-selenium/) 功能强大。但遇到当地警方就能处理的小事，没必要出动超人。下面我们来分析一下哪些情况并不适合使用 Selenium：

- 网站内容是静态的

如果打开“查看页面源代码”就能直接看到数据，说明这是一个静态网站。静态网页的数据抓取不需要用到 Selenium WebDriver，使用 requests 和 BeautifulSoup 等传统抓取工具即可：速度更快、更轻量，被封锁的概率也更低。我们在[Python 数据抓取指南](https://marsproxies.cn/blog/python-web-scraping/)中详细介绍了这套传统抓取方案。

- 有更合适的替代方案时

先检查 Network 面板。有些动态网站通过 JSON API 加载数据，您可以直接调用这些接口，这比启动浏览器、模拟用户交互要更快、更省成本、也更可靠。把 Selenium 留到别无选择的时候再用。关于更多数据抓取工具和策略，请参阅我们的[数据抓取技巧指南](https://marsproxies.cn/blog/web-scraping-techniques/)。

- 大规模抓取数据时

需要抓取成千上万个页面？Selenium 并不是为此设计的。要把 Selenium 扩展到成百上千个会话，需要相当完善的基础设施。如果您的使用场景是高并发量，不妨考虑从一开始就专为大规模抓取设计的工具，比如[Scrapy](https://marsproxies.cn/blog/python-web-scraping/)这个专为规模化而生的框架。完整内容请阅读[《Scrapy 与 Selenium 对比指南》](https://marsproxies.cn/blog/scrapy-vs-selenium/)。

## 推荐做法与法律注意事项

以下是您需要注意的一些推荐做法和法律事项。

- 遵守 robots.txt

robots.txt 是一个简单的文件，用于告诉机器人网站哪些部分禁止访问。它不具有法律约束力，但忽视它可能导致您被封锁、封禁甚至被起诉，尤其是在抓取受限或敏感内容时。抓取前请务必先查看该文件。

- 避免因超出速率限制被封禁

前面已经介绍过技术层面的方法：代理、轮换 User-Agent、智能延迟，以及更接近真实用户的行为。请每次都坚持遵循这些规则，不这样做而直接抓取数据，就如同闭着眼睛走进一个诱捕机制（honeypot）。

- 法律边界与合规抓取

请清楚区分公开数据和私有数据：面向公众的页面通常可以合理抓取，但抓取登录后的内容、付费墙背后的内容，或借助攻击手段抓取数据，在大多数地区都是违法的。只抓取无需登录即可被任何用户看到的内容。

## 结语

希望这篇指南能帮助您搭建一套基于 undetected-chromedriver 的可用 Selenium 抓取方案。大多数动态网页都不会像 Books to Scrape 那样友好，但只要搭配合适的配置、智能的轮换策略和谨慎的操作，在扩展 Selenium 使用规模时您就能始终占据主动。更多内容请参阅[《Selenium 与 Puppeteer 对比》](https://marsproxies.cn/blog/puppeteer-vs-selenium/)。

如果您想和其他深知现代网站防护有多严格的开发者及数据抓取从业者交流心得，欢迎[加入我们的 Discord](https://discord.com/invite/YJWrbVq8at/)，一起参与讨论。

Selenium 数据抓取合法吗？

抓取公开网站的数据并不违法。但如果抓取的是私有数据，比如登录后的内容、付费墙背后的内容，或受保护系统中的内容，就越界了。请始终只抓取无需特殊权限、任何用户都能看到的数据。

Selenium 比 BeautifulSoup 更好吗？

这取决于具体的抓取任务。Selenium WebDriver 功能更强大，因为它可以直接控制浏览器，适合动态网站；但速度较慢、也更“重”。BeautifulSoup 更适合静态页面，无需浏览器自动化即可批量抓取数据。

Selenium 数据抓取是免费的吗？

是的，Selenium 本身免费使用。但大规模数据抓取通常需要为代理、服务器，有时还有反检测工具等额外支出付费，以保持抓取脚本的稳定运行并避免被封锁。

哪种浏览器适合用于 Selenium 数据抓取？

Chrome 是使用 Selenium 做数据抓取时的常见选择：它稳定、支持完善，并且能与 undetected-chromedriver 等工具顺畅配合。在动态网页上进行隐身抓取时，坚持使用 Chrome 能让配置保持一致，出问题的概率也更低。

[了解更多](https://dashboard.marsproxies.com/register/)

\-

作者

[Dalius Pamedytis 软件工程师](https://marsproxies.cn/blog/authors/dalius-pamedytis/)

目录

1. [Selenium 是什么？为何适合用于数据抓取？](https://marsproxies.cn/blog/selenium-web-scraping/#b-selenium-%E6%98%AF%E4%BB%80%E4%B9%88%E4%B8%BA%E4%BD%95%E9%80%82%E5%90%88%E7%94%A8%E4%BA%8E%E6%95%B0%E6%8D%AE%E6%8A%93%E5%8F%96)
2. [搭建 Selenium 抓取程序](https://marsproxies.cn/blog/selenium-web-scraping/#b-%E6%90%AD%E5%BB%BA-selenium-%E6%8A%93%E5%8F%96%E7%A8%8B%E5%BA%8F)
3. [第一步：安装 Python](https://marsproxies.cn/blog/selenium-web-scraping/#b-%E7%AC%AC%E4%B8%80%E6%AD%A5%E5%AE%89%E8%A3%85-python)
4. [第二步：安装 Selenium](https://marsproxies.cn/blog/selenium-web-scraping/#b-%E7%AC%AC%E4%BA%8C%E6%AD%A5%E5%AE%89%E8%A3%85-selenium)
5. [第三步：安装 undetected-chromedriver](https://marsproxies.cn/blog/selenium-web-scraping/#b-%E7%AC%AC%E4%B8%89%E6%AD%A5%E5%AE%89%E8%A3%85-undetected-chromedriver)
6. [准备工作环境](https://marsproxies.cn/blog/selenium-web-scraping/#b-%E5%87%86%E5%A4%87%E5%B7%A5%E4%BD%9C%E7%8E%AF%E5%A2%83)
7. [开始构建 Selenium 抓取程序](https://marsproxies.cn/blog/selenium-web-scraping/#b-%E5%BC%80%E5%A7%8B%E6%9E%84%E5%BB%BA-selenium-%E6%8A%93%E5%8F%96%E7%A8%8B%E5%BA%8F)
8. [第一步：编写导入语句](https://marsproxies.cn/blog/selenium-web-scraping/#b-%E7%AC%AC%E4%B8%80%E6%AD%A5%E7%BC%96%E5%86%99%E5%AF%BC%E5%85%A5%E8%AF%AD%E5%8F%A5)
9. [第二步：配置日志系统](https://marsproxies.cn/blog/selenium-web-scraping/#b-%E7%AC%AC%E4%BA%8C%E6%AD%A5%E9%85%8D%E7%BD%AE%E6%97%A5%E5%BF%97%E7%B3%BB%E7%BB%9F)
10. [第三步：添加代理](https://marsproxies.cn/blog/selenium-web-scraping/#b-%E7%AC%AC%E4%B8%89%E6%AD%A5%E6%B7%BB%E5%8A%A0%E4%BB%A3%E7%90%86)
11. [第四步：添加 User-Agent](https://marsproxies.cn/blog/selenium-web-scraping/#b-%E7%AC%AC%E5%9B%9B%E6%AD%A5%E6%B7%BB%E5%8A%A0-user-agent)
12. [第五步：配置 undetected-chromedriver](https://marsproxies.cn/blog/selenium-web-scraping/#b-%E7%AC%AC%E4%BA%94%E6%AD%A5%E9%85%8D%E7%BD%AE-undetected-chromedriver)
13. [第六步：编写抓取逻辑](https://marsproxies.cn/blog/selenium-web-scraping/#b-%E7%AC%AC%E5%85%AD%E6%AD%A5%E7%BC%96%E5%86%99%E6%8A%93%E5%8F%96%E9%80%BB%E8%BE%91)
14. [第 7 步：编写主执行层](https://marsproxies.cn/blog/selenium-web-scraping/#b-%E7%AC%AC-7-%E6%AD%A5%E7%BC%96%E5%86%99%E4%B8%BB%E6%89%A7%E8%A1%8C%E5%B1%82)
15. [Selenium 数据抓取常见问题](https://marsproxies.cn/blog/selenium-web-scraping/#b-selenium-%E6%95%B0%E6%8D%AE%E6%8A%93%E5%8F%96%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98)
16. [什么情况下不适合用 Selenium 做数据抓取](https://marsproxies.cn/blog/selenium-web-scraping/#b-%E4%BB%80%E4%B9%88%E6%83%85%E5%86%B5%E4%B8%8B%E4%B8%8D%E9%80%82%E5%90%88%E7%94%A8-selenium-%E5%81%9A%E6%95%B0%E6%8D%AE%E6%8A%93%E5%8F%96)
17. [推荐做法与法律注意事项](https://marsproxies.cn/blog/selenium-web-scraping/#b-%E6%8E%A8%E8%8D%90%E5%81%9A%E6%B3%95%E4%B8%8E%E6%B3%95%E5%BE%8B%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9)
18. [结语](https://marsproxies.cn/blog/selenium-web-scraping/#b-%E7%BB%93%E8%AF%AD)

分类

- [产品动态](https://marsproxies.cn/blog/category/product-news/)

  [5](https://marsproxies.cn/blog/category/product-news/)
- [产品对比](https://marsproxies.cn/blog/category/comparisons/)

  [3](https://marsproxies.cn/blog/category/comparisons/)
- [反检测解决方案](https://marsproxies.cn/blog/category/antidetect-solution/)

  [3](https://marsproxies.cn/blog/category/antidetect-solution/)
- [操作指南](https://marsproxies.cn/blog/category/how-to/)

  [115](https://marsproxies.cn/blog/category/how-to/)
- [球鞋抢购机器人](https://marsproxies.cn/blog/category/sneaker-bots/)

  [2](https://marsproxies.cn/blog/category/sneaker-bots/)
- [资讯](https://marsproxies.cn/blog/category/insights/)

  [87](https://marsproxies.cn/blog/category/insights/)

## 相关文章

[操作指南](https://marsproxies.cn/blog/category/how-to/)

### [如何在 PS5 上设置代理服务器（分步指南）](https://marsproxies.cn/blog/proxy-server-on-ps5/)

学习如何在 PS5 上设置代理服务器，按照本指南配置代理设置、提升下载速度并绕过封锁。

[Lukas Tilkevicius 增长与合作经理](https://marsproxies.cn/blog/authors/lukas-tilkevicius/)

2026年10月7日

[操作指南](https://marsproxies.cn/blog/category/how-to/)

### [如何使用 Node Unblocker 进行数据抓取与隐私保护](https://marsproxies.cn/blog/node-unblocker/)

了解如何使用 Node Unblocker 进行数据抓取、保护隐私并绕过访问限制，本文将介绍其搭建步骤、使用场景、优势与主要局限性。

[Dalius Pamedytis 软件工程师](https://marsproxies.cn/blog/authors/dalius-pamedytis/)

2026年10月6日

[操作指南](https://marsproxies.cn/blog/category/how-to/)

### [如何修复 Python 中的 externally-managed-environment 错误](https://marsproxies.cn/blog/externally-managed-environment/)

修复 Python 中的 externally-managed-environment 错误，了解 pip 为何阻止系统 Python 安装，以及虚拟环境如何解决这一问题。

[Lukas Tilkevicius 增长与合作经理](https://marsproxies.cn/blog/authors/lukas-tilkevicius/)

2026年10月5日
