Crawl4AI 高级特性实战:代理、PDF/截图、SSL 证书、自定义请求头、会话持久化与反爬规避
本文系统讲解 Crawl4AI 中面向生产场景的七类高级特性:通过 BrowserConfig.proxy_config 配置代理、一次性抓取 PDF 与截图、爬取并导出 SSL 证书、以多种方式注入自定义请求头、用 storage_state 持久化 Cookie 与 localStorage、遵循 robots.txt 规则,以及借助 Stealth Mode 与 Undetected Browser 应对 Bot 检测。读完后你将掌握这些参数的正确用法、底层实现位置(crawl4ai/async_configs.py、crawl4ai/ssl_certificate.py、crawl4ai/utils.py、crawl4ai/browser_adapter.py)及其组合运用的完整工作流。
前置条件:熟悉 AsyncWebCrawler 基础用法,并在 Python 环境中安装好 Playwright(pip install crawl4ai && crawl4ai-setup 或参考 安装指南)。
1. 代理配置:proxy_config 的三种输入形式
当你需要把爬虫流量路由到代理——IP 轮换、地理测试或隐私隔离——Crawl4AI 通过 BrowserConfig.proxy_config 提供支持。
import asyncio
from crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig
async def main():
browser_cfg = BrowserConfig(
proxy_config={
"server": "http://proxy.example.com:8080",
"username": "myuser",
"password": "mypass",
},
headless=True
)
crawler_cfg = CrawlerRunConfig(
verbose=True
)
async with AsyncWebCrawler(config=browser_cfg) as crawler:
result = await crawler.arun(
url="https://www.whatismyip.com/",
config=crawler_cfg
)
if result.success:
print("[OK] Page fetched via proxy.")
print("Page HTML snippet:", result.html[:200])
else:
print("[ERROR]", result.error_message)
if __name__ == "__main__":
asyncio.run(main())
关键点
proxy_config接受一个字典,包含server及可选的username/password;- 多数商业代理提供商给出 HTTP/HTTPS "网关" 地址,直接填入
server即可; - 代理无需认证时省略
username/password。
源码视角:ProxyConfig 的数据模型
在 crawl4ai/async_configs.py 中定义了 ProxyConfig 类,构造参数为 server(必填)、username、password、ip(可选,用于校验出口 IP;若不显式给出,会从 server 中自动解析出 host 部分)。配置归一化的关键逻辑在 BrowserConfig 的初始化中:传入字典时调用 ProxyConfig.from_dict(),传入字符串时调用 ProxyConfig.from_string()。
from_string 支持多种写法,这让你可以用环境变量或简单字符串批量管理代理:
from crawl4ai.async_configs import ProxyConfig
# 以下格式全部合法
ProxyConfig.from_string("http://user:pass@10.0.0.1:8080")
ProxyConfig.from_string("http://10.0.0.1:8080")
ProxyConfig.from_string("socks5://10.0.0.1:8080")
ProxyConfig.from_string("10.0.0.1:8080:user:pass")
ProxyConfig.from_string("10.0.0.1:8080")
此外,ProxyConfig.from_env("PROXIES") 可从环境变量读取以逗号分隔的代理字符串列表,便于在 CI 或容器部署中免改代码地注入代理池。
版本兼容提示:从源码可确认,旧的 proxy 字符串参数已被标记为废弃(BrowserConfig 初始化中会发出 UserWarning),新代码请一律使用 proxy_config;若同时提供 proxy 与 proxy_config,proxy_config 优先。另外 CrawlerRunConfig 也支持 proxy_config 参数,且可传入代理列表用于重试轮转——这是 crawl4ai/async_configs.py 中 _normalize_proxy_config 的归一化逻辑所支持的形态,ProxyConfig.DIRECT(值为 "direct")可作为列表中的哨兵表示"该次重试不使用代理"。
2. 抓取 PDF 与截图:一次 arun 双份产出
有时你需要页面的可视化记录或 PDF "打印件"。Crawl4AI 能在一次运行中同时完成两者:
import os, asyncio
from base64 import b64decode
from crawl4ai import AsyncWebCrawler, CacheMode, CrawlerRunConfig
async def main():
run_config = CrawlerRunConfig(
cache_mode=CacheMode.BYPASS,
screenshot=True,
pdf=True
)
async with AsyncWebCrawler() as crawler:
result = await crawler.arun(
url="https://en.wikipedia.org/wiki/List_of_common_misconceptions",
config=run_config
)
if result.success:
print(f"Screenshot data present: {result.screenshot is not None}")
print(f"PDF data present: {result.pdf is not None}")
if result.screenshot:
print(f"[OK] Screenshot captured, size: {len(result.screenshot)} bytes")
with open("wikipedia_screenshot.png", "wb") as f:
f.write(b64decode(result.screenshot))
else:
print("[WARN] Screenshot data is None.")
if result.pdf:
print(f"[OK] PDF captured, size: {len(result.pdf)} bytes")
with open("wikipedia_page.pdf", "wb") as f:
f.write(result.pdf)
else:
print("[WARN] PDF data is None.")
else:
print("[ERROR]", result.error_message)
if __name__ == "__main__":
asyncio.run(main())
为什么需要 PDF + 截图双通道?
- 超长或结构复杂的页面,传统"整页截图"可能缓慢甚至出错;
- 对极长页面,导出 PDF 更可靠;当你同时请求两者时,Crawl4AI 会自动把 PDF 首页转换为图像作为截图输出。
相关参数(均位于 CrawlerRunConfig,可参见 crawl4ai/async_configs.py 的字段文档):
| 参数 | 说明 | 默认值 |
|---|---|---|
pdf=True |
将当前页面导出为 PDF,base64 编码后存放于 result.pdf |
False |
screenshot=True |
生成页面截图,base64 编码后存放于 result.screenshot |
False |
scroll_delay |
整页截图时每次滚动之间的延迟(秒),默认 0.2;页面资源加载慢时应调大 |
0.2 |
scan_full_page |
为 True 时滚动遍历整个页面以加载全部懒加载内容,配合 scroll_delay 控制节奏 |
— |
force_viewport_screenshot |
为 True 时无论页面多高,只截取视口范围,避免超长页面整页截图的开销 |
False |
对截图质量有更高要求时,还可在 BrowserConfig 中设置 device_scale_factor(设备像素比),例如 2.0 可使 1920×1080 视口产出 3840×2160 的高清截图,代价是内存与渲染时间增加。
3. 获取并导出 SSL 证书
出于合规审计、故障排查或数据分析需要,你可能要抓取目标站点的 SSL 证书。Crawl4AI 支持在爬取过程中完成这件事:
import asyncio, os
from crawl4ai import AsyncWebCrawler, CrawlerRunConfig, CacheMode
async def main():
tmp_dir = os.path.join(os.getcwd(), "tmp")
os.makedirs(tmp_dir, exist_ok=True)
config = CrawlerRunConfig(
fetch_ssl_certificate=True,
cache_mode=CacheMode.BYPASS
)
async with AsyncWebCrawler() as crawler:
result = await crawler.arun(url="https://example.com", config=config)
if result.success and result.ssl_certificate:
cert = result.ssl_certificate
print("\nCertificate Information:")
print(f"Issuer (CN): {cert.issuer.get('CN', '')}")
print(f"Valid until: {cert.valid_until}")
print(f"Fingerprint: {cert.fingerprint}")
# Export in multiple formats:
cert.to_json(os.path.join(tmp_dir, "certificate.json"))
cert.to_pem(os.path.join(tmp_dir, "certificate.pem"))
cert.to_der(os.path.join(tmp_dir, "certificate.der"))
print("\nCertificate exported to JSON/PEM/DER in 'tmp' folder.")
else:
print("[ERROR] No certificate or crawl failed.")
if __name__ == "__main__":
asyncio.run(main())
关键点
fetch_ssl_certificate=True触发证书抓取(默认False);result.ssl_certificate是一个SSLCertificate对象,提供to_json、to_pem、to_der方法,可保存为多种格式(便于服务器配置、Java 密钥库导入等)。
源码视角:SSLCertificate 的设计
证书处理逻辑集中在 crawl4ai/ssl_certificate.py:SSLCertificate 继承自 dict,因此实例可以直接 JSON 序列化,issuer、valid_until、fingerprint 以属性形式暴露。其静态方法 from_url(url, timeout=10) 的工作方式是直接对主机名 443 端口建立 TCP 连接并用 ssl.create_default_context() 包裹 socket(见 crawl4ai/ssl_certificate.py),再把返回的 DER 数据交给 OpenSSL.crypto 解析——这意味着证书抓取独立于浏览器页面本身,即使页面渲染失败,只要 HTTPS 握手成功,证书依然可以拿到。该模块依赖 pyOpenSSL,因此安装时需要确保该依赖可用。
4. 自定义请求头:两种注入途径
某些场景需要设置自定义请求头,例如语言偏好、认证 Token 或特定的 User-Agent 字符串。Crawl4AI 提供了至少两条路径:
import asyncio
from crawl4ai import AsyncWebCrawler
async def main():
# Option 1: Set headers at the crawler strategy level
crawler1 = AsyncWebCrawler(
# The underlying strategy can accept headers in its constructor
crawler_strategy=None # We'll override below for clarity
)
crawler1.crawler_strategy.update_user_agent("MyCustomUA/1.0")
crawler1.crawler_strategy.set_custom_headers({
"Accept-Language": "fr-FR,fr;q=0.9"
})
result1 = await crawler1.arun("https://www.example.com")
print("Example 1 result success:", result1.success)
# Option 2: Pass headers directly to `arun()`
crawler2 = AsyncWebCrawler()
result2 = await crawler2.arun(
url="https://www.example.com",
headers={"Accept-Language": "es-ES,es;q=0.9"}
)
print("Example 2 result success:", result2.success)
if __name__ == "__main__":
asyncio.run(main())
两种途径的适用范围(结合 crawl4ai/async_configs.py 的字段文档可以明确区分):
| 途径 | 作用层级 | 适合场景 |
|---|---|---|
策略层 update_user_agent / set_custom_headers |
浏览器上下文级,对该爬虫实例的所有请求生效 | 需要长期稳定的身份标识 |
arun(headers=...) 或 BrowserConfig.headers |
单次运行 / 上下文创建时注入 | 按请求变化的语言、Token |
另外,BrowserConfig 还支持 user_agent(直接指定 UA 字符串)与 user_agent_mode="random" 配合 user_agent_generator_config 的随机 UA 生成模式。需要注意:
- 部分站点对特定头(如
Accept-Language)返回内容会不同; - 如需高级 UA 随机化与 Client Hints 伪造,应参考 基于身份的爬取(Anti-Bot) 或使用
UserAgentGenerator(见 crawl4ai/user_agent_generator.py)。
5. 会话持久化与本地存储
Crawl4AI 可以保留 Cookie 与 localStorage,让你"接着上次继续"——登录一次,之后免登录反复访问,是跳过重复认证流程的理想方案。
5.1 storage_state:以字典注入"已登录"状态
storage_state 是 BrowserConfig 的参数,接受路径字符串或内存字典(见 crawl4ai/async_configs.py 的字段说明):
import asyncio
from crawl4ai import AsyncWebCrawler
async def main():
storage_dict = {
"cookies": [
{
"name": "session",
"value": "abcd1234",
"domain": "example.com",
"path": "/",
"expires": 1699999999.0,
"httpOnly": False,
"secure": False,
"sameSite": "None"
}
],
"origins": [
{
"origin": "https://example.com",
"localStorage": [
{"name": "token", "value": "my_auth_token"}
]
}
]
}
# Provide the storage state as a dictionary to start "already logged in"
async with AsyncWebCrawler(
headless=True,
storage_state=storage_dict
) as crawler:
result = await crawler.arun("https://example.com/protected")
if result.success:
print("Protected page content length:", len(result.html))
else:
print("Failed to crawl protected page")
if __name__ == "__main__":
asyncio.run(main())
字典结构与 Playwright 的 storage state 格式一致:cookies 数组携带 name、value、domain、path、expires、httpOnly、secure、sameSite 字段;origins 数组按 origin 挂载 localStorage 键值对。
5.2 导出与复用状态:登录一次,长期受益
先手动或自动化完成登录,然后导出浏览器上下文,之后复用即可——无需再次输入凭据:
await context.storage_state(path="my_storage.json"):在 hooks 中通过浏览器上下文把 Cookie、localStorage 等导出到文件;- 后续运行传入
storage_state="my_storage.json"(路径形式)即可跳过登录步骤。
进阶场景(多步登录、交互式页面登录后再捕获状态)请参考 会话管理教程 或 浏览器上下文与管理式浏览器说明。
6. robots.txt 合规检查
Crawl4AI 支持遵循 robots.txt 规则,并带有高效的本地缓存:
import asyncio
from crawl4ai import AsyncWebCrawler, CrawlerRunConfig
async def main():
# Enable robots.txt checking in config
config = CrawlerRunConfig(
check_robots_txt=True # Will check and respect robots.txt rules
)
async with AsyncWebCrawler() as crawler:
result = await crawler.arun(
"https://example.com",
config=config
)
if not result.success and result.status_code == 403:
print("Access denied by robots.txt")
if __name__ == "__main__":
asyncio.run(main())
关键点
- robots.txt 文件会被缓存到本地以提升效率;
- 缓存数据库位于
~/.crawl4ai/robots/robots_cache.db; - 缓存默认 TTL 为 7 天;
- 若 robots.txt 无法抓取,则允许爬取(fail-open 策略);
- URL 被禁止访问时返回 403 状态码。
源码视角:缓存实现细节
上述行为在 crawl4ai/utils.py 中可以直接验证:CACHE_TTL = 7 * 24 * 60 * 60(即 7 天),缓存目录为 ~/.crawl4ai/robots,底层用 SQLite 建 robots_cache 表(按 domain 建索引),每条缓存记录保存 rules、fetch_time 与 hash 三列——hash 用于变化检测,fetch_time 用于 TTL 过期清理(clear_expired 会删除 fetch_time 早于 now - ttl 的条目)。check 方法以 2 秒超时异步 GET https://{domain}/robots.txt,抓取失败即放行,与文档描述一致。
7. 反 Bot 特性:Stealth Mode 与 Undetected Browser
Crawl4AI 提供两套对抗 Bot 检测的机制,可按站点防护强度选择。
7.1 Stealth Mode
Stealth mode 基于 playwright-stealth 修改浏览器指纹与行为,一个开关即可启用:
browser_config = BrowserConfig(
enable_stealth=True, # Activates stealth mode
headless=False
)
适用场景:具备基础 Bot 检测的站点(检查 navigator.webdriver、plugins 等)。源码中该参数定义在 crawl4ai/async_configs.py:enable_stealth 默认 False,且明确"不可与 undetected 浏览器模式同时使用"——两种机制互斥,组合时以 undetected 为准。
7.2 Undetected Browser
面对高级检测,使用 undetected 浏览器适配器:
from crawl4ai import UndetectedAdapter
from crawl4ai.async_crawler_strategy import AsyncPlaywrightCrawlerStrategy
# Create undetected adapter
adapter = UndetectedAdapter()
strategy = AsyncPlaywrightCrawlerStrategy(
browser_config=browser_config,
browser_adapter=adapter
)
async with AsyncWebCrawler(crawler_strategy=strategy, config=browser_config) as crawler:
# Your crawling code
UndetectedAdapter 定义在 crawl4ai/browser_adapter.py,继承自抽象基类 BrowserAdapter(L24)。适配器模式的意义在于:AsyncPlaywrightCrawlerStrategy 不直接绑定某一浏览器实现,而是通过注入的 browser_adapter 完成启动与页面操作——换成 undetected-chromedriver 内核时,上层的爬取、提取逻辑完全不用改。
适用场景:具备复杂 Bot 检测的站点(如 Cloudflare、DataDome 一类的防护)。
7.3 选择策略对照表
| 检测等级 | 推荐方案 |
|---|---|
| 无防护 | 普通浏览器 |
| 基础检查 | 普通 + Stealth mode |
| 高级防护 | Undetected browser |
| 最大规避 | Undetected + Stealth mode 参数(注意源码约束:两者不可同时激活,以 undetected 为主) |
最佳实践:从普通浏览器 + stealth mode 起步,仅在确实被拦截时再上 undetected browser——它可能略慢。详细示例见 Undetected Browser Mode;仓库中也有对应的可运行演示,如 docs/examples/stealth_mode_example.py、docs/examples/undetected_simple_demo.py 与 docs/examples/hello_world_undetected.py。
注意:官方在文档中说明,未来版本可能默认启用 stealth mode 与 undetected browser;目前版本需要显式开启。
组合实战:一次运行启用全部高级特性
下面把代理、PDF、截图、SSL、自定义请求头与会话复用组合在同一次 arun 中。实际项目里请按各自需要裁剪:
import os, asyncio
from base64 import b64decode
from crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig, CacheMode
async def main():
# 1. Browser config with proxy + headless
browser_cfg = BrowserConfig(
proxy_config={
"server": "http://proxy.example.com:8080",
"username": "myuser",
"password": "mypass",
},
headless=True,
)
# 2. Crawler config with PDF, screenshot, SSL, custom headers, and ignoring caches
crawler_cfg = CrawlerRunConfig(
pdf=True,
screenshot=True,
fetch_ssl_certificate=True,
cache_mode=CacheMode.BYPASS,
headers={"Accept-Language": "en-US,en;q=0.8"},
storage_state="my_storage.json", # Reuse session from a previous sign-in
verbose=True,
)
# 3. Crawl
async with AsyncWebCrawler(config=browser_cfg) as crawler:
result = await crawler.arun(
url="https://secure.example.com/protected",
config=crawler_cfg
)
if result.success:
print("[OK] Crawled the secure page. Links found:", len(result.links.get("internal", [])))
# Save PDF & screenshot
if result.pdf:
with open("result.pdf", "wb") as f:
f.write(b64decode(result.pdf))
if result.screenshot:
with open("result.png", "wb") as f:
f.write(b64decode(result.screenshot))
# Check SSL cert
if result.ssl_certificate:
print("SSL Issuer CN:", result.ssl_certificate.issuer.get("CN", ""))
else:
print("[ERROR]", result.error_message)
if __name__ == "__main__":
asyncio.run(main())
两点值得注意的配置分层:浏览器级能力(代理、UA、stealth、viewport)挂在 BrowserConfig 上,随浏览器生命周期存在;运行级能力(PDF/截图、SSL 抓取、robots 检查、缓存策略)挂在 CrawlerRunConfig 上,可按每次 arun 独立调整。需要说明的是,组合示例中的 storage_state 在 CrawlerRunConfig 上传递;按源码字段定义,会话状态的持久注入应使用 BrowserConfig.storage_state,两者语义接近,实际以你所用版本的字段校验为准。
小结
本文覆盖的 Crawl4AI 高级特性及其落地位置:
- 代理:
BrowserConfig.proxy_config,底层为 ProxyConfig,支持 dict/字符串/环境变量/列表轮转; - PDF 与截图:
CrawlerRunConfig的pdf、screenshot、scroll_delay、scan_full_page、force_viewport_screenshot; - SSL 证书:
fetch_ssl_certificate+ SSLCertificate 的to_json/to_pem/to_der导出; - 自定义请求头:策略层
set_custom_headers/update_user_agent与arun(headers=...)两条注入路径; - 会话持久化:
storage_state字典或 JSON 文件复用 Cookie 与 localStorage; - robots.txt:
check_robots_txt,本地 SQLite 缓存 7 天 TTL,禁止访问返回 403; - 反 Bot:
enable_stealth(playwright-stealth)与 UndetectedAdapter(undetected 内核适配器)。
掌握这些能力后,你可以构建模拟真实用户行为、处理安全站点、产出可视化快照、跨运行复用会话并规避 Bot 检测的稳健采集流水线。本文所有参数行为均以当前仓库源码为准;代理轮转、多步登录、undetected 模式等更深层场景,可分别深入 proxy 相关测试、会话管理文档 与 undetected browser 文档 继续学习。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00