在 Python 中使用 curl_cffi 进行网络爬虫

了解 curl_cffi 如何通过模拟真实浏览器的 TLS 指纹,实现隐蔽且高效的 Python 网络爬虫。
4 min read
使用 curl_cffi 进行网络爬虫

在本指南中,你将学习到:

  • curl_cffi 是什么以及它所提供的特性
  • 它是如何通过最小化基于 TLS 指纹的机器人检测来躲避反爬虫的
  • 如何在 Python 中配合它进行网络爬虫
  • 高级用法和方法
  • 与其他类似 HTTP 客户端的对比

让我们开始吧!

什么是 curl_cffi

curl_cffi 是一个通过 CFFI 为 curl-impersonate 分支提供 Python 绑定的库。换句话说,它是一个能够模拟浏览器 TLS/JA3/HTTP2 指纹的 HTTP 客户端。因此,对于基于 TLS 指纹检测的反爬虫屏蔽来说,该库是一个非常优秀的解决方案。

⚙️ 特性

  • 支持 JA3/TLS 和 HTTP2 指纹伪装,包括最新浏览器及自定义指纹
  • requestshttpx 更快,速度与 aiohttp 相当
  • 模仿 requests 的 API
  • 支持 asyncio 进行异步 HTTP 请求
  • 支持在每次请求时进行代理轮换
  • 支持 HTTP/2.0
  • 支持 WebSocket

工作原理

curl_cffi 基于 cURL Impersonate,它是一个能够生成与真实浏览器匹配的 TLS 指纹的库。

当你发送 HTTPS 请求时,会发生一次 TLS 握手,从而产生一个独特的 TLS 指纹。由于普通 HTTP 客户端与浏览器存在差异,这些指纹可能会暴露自动化行为,进而触发反爬虫防护。

cURL Impersonate 会对 cURL 进行修改,使其匹配真实的浏览器 TLS 指纹:

  • TLS 库调整:使用浏览器所用的 TLS 库而不是 cURL 本身的库。
  • 配置变更:调整 TLS 扩展和 SSL 选项以模仿浏览器。
  • HTTP/2 定制:匹配浏览器的握手方式。
  • 自定义 cURL 参数:使用 --ciphers--curves 以及自定义头部信息来实现更精准的模拟。

这样的改动使得请求更接近浏览器的行为,从而帮助绕过反爬虫检测。欲了解更多信息,请参阅我们关于 cURL Impersonate 的指南

如何使用 curl_cffi 进行网络爬虫:分步指南

假设你要从 Walmart “Keyboard” 页面获取数据:

沃尔玛“键盘”产品页面

如果你使用任意 HTTP 客户端访问这个页面,你会收到如下的错误页面:

请注意服务器的响应

不要被 200 OK 响应状态迷惑。实际上,Walmart 的服务器返回的是一个反机器人检测页面,要求你通过 CAPTCHA 验证来证明自己是人类。

你可能会好奇:即使在请求中设置了 User-Agent 模拟真实浏览器,为何仍会触发?答案就是 TLS 指纹!

下面让我们看一看如何使用 curl_cffi 来绕过这些反爬虫检测,以轻松进行爬取。

步骤 #1:项目环境搭建

首先,请确保你的机器上安装了 Python 3 及以上版本。若尚未安装,可从Python 官方网站下载并按照其指示完成安装。

然后,使用以下命令为你的 curl_cffi 爬虫项目创建一个目录:

mkdir curl-cfii-scraper

进入该目录,并在其中创建一个虚拟环境

cd curl-cfii-scraper
python -m venv env

在你喜欢的 Python IDE 中打开这个项目文件夹。Visual Studio Code(安装 Python 扩展)PyCharm 社区版都是不错的选择。

现在,在项目文件夹下创建一个 scraper.py 文件,初始时它是空的,后续你会把爬虫逻辑加入其中。

在 IDE 的终端中激活虚拟环境。对于 Linux 或 macOS:

./env/bin/activate

在 Windows 上则执行:

env/Scripts/activate

很好!到此为止,你的环境已经就绪。

步骤 #2:安装 curl_cffi

在激活的虚拟环境中,通过 pip 包 curl-cffi 安装该 HTTP 客户端:

pip install curl-cffi

在后台,这个库会根据你的操作系统(Windows、macOS 或 Linux)自动下载针对该平台的 curl impersonation 二进制文件。

步骤 #3:连接到目标页面

curl_cffi 中导入 requests

from curl_cffi import requests

这个对象提供了一个与Python Requests 库非常相似的高级 API。

你可以像下面这样发送一个 GET 请求到目标页面:

response = requests.get("https://www.walmart.com/search?q=keyboard", impersonate="chrome")

这里的 impersonate="chrome" 参数让 curl_cffi 将该请求伪装成最新版本的 Chrome 浏览器请求。这样,Walmart 会将该自动化请求视为普通浏览器请求,而不是反爬虫页面。

你可以通过以下方式获取目标页面的 HTML 内容:

html = response.text

如果你打印 html,将会看到:

<!DOCTYPE html>
<html lang="en-US">
   <head>
      <meta charSet="utf-8"/>
      <meta property="fb:app_id" content="105223049547814"/>
      <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1, interactive-widget=resizes-content"/>
      <link rel="dns-prefetch" href="https://tap.walmart.com "/>
      <link rel="preload" fetchpriority="high" crossorigin="anonymous" href="https://i5.walmartimages.com/dfw/63fd9f59-a78c/fcfae9b6-2f69-4f89-beed-f0eeb4237946/v1/BogleWeb_subset-Bold.woff2" as="font" type="font/woff2"/>
      <link rel="preload" fetchpriority="high" crossorigin="anonymous" href="https://i5.walmartimages.com/dfw/63fd9f59-a78c/fcfae9b6-2f69-4f89-beed-f0eeb4237946/v1/BogleWeb_subset-Regular.woff2" as="font" type="font/woff2"/>
      <link rel="preconnect" href="https://beacon.walmart.com"/>
      <link rel="preconnect" href="https://b.wal.co"/>
      <title>Electronics - Walmart.com</title>
      <!-- omitted for brevity ... -->

太好了!这是 Walmart “keyboard” 产品页的正常 HTML 内容。

步骤 #4:编写数据爬取逻辑

curl_cffi 仅仅是一个获取页面 HTML 的 HTTP 客户端。若想进行网络爬虫,你还需要一个用于解析 HTML 的库,例如 BeautifulSoup。有关更多详细信息,你可以阅读我们关于 使用 BeautifulSoup 进行网页爬虫的指南

在激活的虚拟环境中,安装 BeautifulSoup:

pip install beautifulsoup4

scraper.py 中导入:

from bs4 import BeautifulSoup

然后,用它来解析页面的 HTML:

soup = BeautifulSoup(response.text, "html.parser")

"html.parser" 是 Python 标准库自带的 HTML 分析器,BeautifulSoup 将使用它来解析 HTML 字符串。现在,soup 可以让你使用各种方法选择并提取页面上的元素。

在本例中,为了演示,我们只采集页面的标题。你可以使用 CSS 选择器 调用 find() 并获取其文本:

title_element = soup.find("title")
title = title_element.text

若想编写更高级的爬取逻辑,可参考我们关于 如何爬取 Walmart 的指南。

最后,打印页面标题:

print(title)

很棒!你已经实现了一个基本的爬虫逻辑。

步骤 #5:整合所有代码

下面是你完整的 curl_cffi 爬虫脚本:

from curl_cffi import requests
from bs4 import BeautifulSoup

# Send a GET request to the Walmart search page for "keyboard"
response = requests.get("https://www.walmart.com/search?q=keyboard", impersonate="chrome")

# Extract the HTML from the page
html = response.text

# Parse the response content with BeautifulSoup
soup = BeautifulSoup(response.text, "html.parser")

# Find the title tag using a CSS selector and print it
title_element = soup.find("title")
# Extract data from it
title = title_element.text

# More complex scraping logic...

# Print the scraped data
print(title)

使用以下命令运行:

python3 scraper.py

同样地,在 Windows 上则使用:

python scraper.py

运行结果会是:

Electronics - Walmart.com

如果你去掉 impersonate="chrome" 参数,那么得到的将会是:

Robot or human?

这就说明,当需要避开反爬虫检测时,模拟浏览器指纹是关键所在。

任务完成!

curl_cffi:高级用法

现在你已经掌握了该库的基本原理,可以继续探索一些更高级的场景。

选择不同的浏览器指纹

curl_cffi 支持模拟多种浏览器。每种浏览器都有一个独特的标签(label),你可以通过传递给 impersonate 参数来指定,例如:

response = requests.get("<YOUR_URL>", impersonate="<BROWSER_LABEL>")

以下是所支持的浏览器对应的标签:

  • chrome99chrome100chrome101chrome104chrome107chrome110chrome116chrome119chrome120chrome123chrome124chrome131
  • chrome99_androidchrome131_android
  • edge99edge101
  • safari15_3safari15_5safari17_0safari17_2_iossafari18_0safari18_0_ios

  1. 如果想始终模拟最新的浏览器版本,可直接使用 chromesafarisafari_ios
  2. 目前不支持 Firefox,仅支持基于 WebKit 的浏览器。
  3. 只有当浏览器指纹真的发生变化时才会添加新的版本。如果跳过了某个版本(例如 chrome122),可以用上一版本的指纹来模拟。
  4. 对于非浏览器目标,可以使用 ja3akamai 等来指定自定义的 TLS 指纹。详情可参见 官方文档

会话管理

就像 requests 库一样,curl-cfii 也支持会话。Session 对象可以在多次请求之间持久化某些参数,比如 cookies、请求头或其他与会话相关的数据。

下面是一个使用 cURL Impersonate 的 Python 绑定来创建会话的示例:

# Create a new session
session = requests.Session()

# This endpoint sets a cookie on the server
session.get("https://httpbin.io/cookies/set/userId/5", impersonate="chrome")

# Print the session's cookies to confirm they are being stored
print(session.cookies)

运行以上脚本的输出为:

<Cookies[<Cookie userId=5 for httpbin.org />]>

结果表明,会话确实在不同请求之间持久化了状态,例如服务器设置的 Cookie。

代理集成

就像 requests 一样,curl_cffi 也支持使用 proxies 对象进行代理连接:

# Define your proxy URL
proxy = "YOUR_PROXY_URL"

# Create a dictionary of proxies for HTTP and HTTPS
proxies = {"http": proxy, "https": proxy}

# Make a request using a proxy and browser impersonation
response = requests.get("<YOUR_URL>", impersonate="chrome", proxies=proxies)

因为它和 requests 的用法非常相似,如果想更深入地了解,可以参考我们关于 在 Requests 中使用代理的教程。

异步 API

curl_cffi 通过基于 asyncioAsyncSession 对象支持异步请求:

from curl_cffi.requests import AsyncSession
import asyncio

# Define an async function to execute the asynchronous code
async def fetch_data():
    async with AsyncSession() as session:
        # Perform the asynchronous GET request
        response = await session.get("https://httpbin.org/anything", impersonate="chrome")
        # Print the response text
        print(response.text)

# Run the async function
asyncio.run(fetch_data())

通过 AsyncSession 可以更方便地并发多个请求,这对提升爬虫的速度至关重要。

WebSocket 连接

curl_cffi 也支持通过 WebSocket 类进行 WebSocket 连接:

from curl_cffi.requests import WebSocket


# Define a callback function to handle incoming messages
def on_message(ws, message):
    print(message)

# Initialize the WebSocket connection with the callback
ws = WebSocket(on_message=on_message)

# Connect to a sample WebSocket server and listen for messages
ws.run_forever("wss://api.gemini.com/v1/marketdata/BTCUSD")

这对于想要爬取使用 WebSocket 动态更新数据的网站或 API(如金融行情、体育比分或在线聊天室)非常实用。

无需抓取渲染后的页面,即可直接连接 WebSocket 频道,以更高效的方式获取数据。

:你也可以通过 AsyncWebSocket 类实现异步方式的 WebSocket

curl_cffi 与 Requests、AIOHTTP、HTTPX 在网络爬虫场景下的对比

下表简要对比了 curl_cffi 与其他常见的 Python HTTP 客户端

特性 curl_cffi Requests AIOHTTP HTTPX
同步 API ✔️ ✔️ ✔️
异步 API ✔️ ✔️ ✔️
支持 WebSocket ✔️ ✔️
连接池 ✔️ ✔️ ✔️ ✔️
HTTP/2 支持 ✔️ ✔️
User-Agent 自定义 ✔️ ✔️ ✔️ ✔️
TLS 指纹伪装 ✔️
速度
重试机制 可通过 HTTPAdapter 需通过第三方库 内置 Transport
支持代理 ✔️ ✔️ ✔️ ✔️
Cookie 处理 ✔️ ✔️ ✔️ ✔️

curl_cffi 在网络爬虫中可选的替代方案

curl_cffi 属于“手动”爬虫的范畴,需要你亲自编写大部分爬虫代码。对于简单的静态网站,这没什么问题,但面对动态内容或具有强力验证机制的站点会比较麻烦。

Bright Data 为此提供了一系列 curl_cffi 之外的爬虫解决方案:

  • 抓取浏览器 API:完全托管的云端浏览器实例,与 Puppeteer、Selenium 和 Playwright 深度集成。这些浏览器自带 CAPTCHA 识别与自动代理轮换功能,能够像真实用户一样与网站交互并绕过反爬虫防护。
  • 网页抓取 API:为 100 多个热门站点提供预配置的端点,用于获取新鲜且结构化的数据。此类 API 既合规又高效,可通过 HTTPX 或任何其他 HTTP 客户端进行数据提取。
  • 无代码抓取工具:一款直观的、按需使用的数据采集服务,能免去编写代码的繁琐。它在无需处理基础设施、代理和反爬等难题的同时,为用户提供高可控性与可扩展性。
  • 数据集:访问众多网站的预构建数据集,或根据实际需求定制数据采集方案。

这些工具为你提供了更健壮、可扩展且合规的数据采集方式,从而显著减少手动开发工作量。

总结

通过本文,你了解了如何使用 curl_cffi 进行网络爬虫,探索了它的用途、主要特性及优势。作为一个快速且可靠的 HTTP 客户端,它可以很好地模拟真实浏览器。

但需要注意的是,自动化 HTTP 请求会暴露你的公共 IP 地址,可能泄露你的身份和地理位置,带来隐私风险。首选的解决方案之一,是使用代理服务器来 隐藏你的 IP

Bright Data 拥有业内领先的代理服务器网络,为世界 500 强企业和超 2 万家客户提供服务,代理种类包括:

立即创建一个免费的 Bright Data 帐号,来体验我们的代理和爬虫解决方案吧!