跳到主要内容

抓取层:浏览器与 HTTP

本章讲清:crawler_strategy.crawl(url) 怎么把一个 URL 变成原始 HTML。这是主线第一步(见 01-pipeline.md §4.2)。

1. 这一章解决什么

现代网页大量靠 JS 渲染——你 curl 下来的 HTML 可能是空壳,正文要等脚本跑完、滚动到位才出现。Crawl4AI 的抓取层要解决的就是:怎样像真人浏览器一样把页面「跑熟」再取 HTML

它给两条路:

策略跑 JS?速度何时用
AsyncPlaywrightCrawlerStrategy✓ 真浏览器默认;SPA、懒加载、要截图/点按钮
AsyncHTTPCrawlerStrategy✗ 纯 HTTP静态页、API、量大且不需要 JS

两者都实现抽象基类 AsyncCrawlerStrategy.crawl(async_crawler_strategy.py:36-43),返回 AsyncCrawlResponse(含 html、status_code、screenshot、网络日志等)。

2. 浏览器抓取:_crawl_web 的一生

Playwright 策略的核心是 _crawl_web(async_crawler_strategy.py:514),一个很长的方法。它的大致流水线:

怎么读: 从上到下是一次页面抓取里依次发生的动作;带 hook 的地方是你能插钩子的点。

_crawl_web(url, config)

├─ 从 BrowserManager 借一个 page(会话/上下文复用)
├─ hook: on_page_context_created
├─ 设置网络/控制台监听(network_requests / console_messages)
├─ page.goto(url) ── 导航
├─ hook: before_goto / after_goto
├─ 执行用户 JS(config.js_code)
├─ smart_wait(wait_for) ── 等元素/条件出现 :234
├─ virtual_scroll(若配) ── 处理无限滚动列表 :997
├─ process_iframes(若配) ── 把 iframe 内容拉进主页 :344
├─ 截图 / PDF / MHTML(若配)
├─ hook: before_retrieve_html
└─ 取 page.content() → 原始 HTML

2.1 钩子(hooks):在抓取流程里插自己的代码

execute_hook(async_crawler_strategy.py:190)让你在固定时机注入回调,比如 before_goto 时改 header、on_page_context_created 时注入 cookie。这是「全控制」卖点的来源——登录、点同意框、反检测脚本都靠 hook。

2.2 smart_wait:别在页面没好时就取 HTML

smart_wait(async_crawler_strategy.py:234)解决「等多久」的难题。wait_for 可以是:

  • CSS 选择器——等这个元素出现;
  • js:() => 条件 ——等这段 JS 返回 true。

比起死等固定秒数,这是「等到内容真的就绪」。

2.3 虚拟滚动:抓无限列表

很多页面(社媒 feed、商品流)是「虚拟滚动」:DOM 里只保留视口附近的元素,滚走的就被回收。直接取 HTML 只能拿到一屏。_handle_virtual_scroll(async_crawler_strategy.py:1286)注入一段 JS(:1320 起的 virtual_scroll_js):反复滚动、在每一屏把新出现的内容拼接保存下来,最后合并成完整 HTML。这样无限列表也能抓全。

2.4 iframe 内联

process_iframes(async_crawler_strategy.py:344)把页面里的 <iframe> 内容取出来、塞回主文档,这样嵌在 iframe 里的正文也不会丢。

3. 浏览器管理与反检测

抓取不直接 new 一个浏览器,而是经过 BrowserManager(browser_manager.py)——它做会话/上下文池化:同一个 session_id 复用同一个浏览器上下文,保留 cookie/登录态,适合多步流程。

反检测层是适配器模式(browser_adapter.py):

适配器干什么
PlaywrightAdapter标准 Playwright
UndetectedAdapter走 patchright / stealth,降低被识别为机器人的概率

配合 playwright-stealthfake-useragent(见 pyproject.toml 依赖)做指纹伪装。但注意:这是降低概率,不是保证绕过(见 index.md §5)。

4. HTTP 轻量抓取

不需要 JS 时,AsyncHTTPCrawlerStrategy.crawl(async_crawler_strategy.py:2796)用 httpx 直接发请求,没有浏览器开销。它自己定义了一套错误类型(HTTPCrawlerErrorConnectionTimeoutErrorHTTPStatusError,:2449-2466)。适合大批量静态页或 API。

用法上通过 HTTPCrawlerConfig 配置,把它作为 crawler_strategy 传给 AsyncWebCrawler 即可——主线 aprocess_html 之后的处理完全一样。

5. 巧妙之处

  • 抓取与处理彻底解耦。 crawler strategy 只负责「URL → 原始 HTML」,清洗/Markdown 完全在 aprocess_html 里。所以换浏览器还是换 HTTP,后面流程不变。
  • 虚拟滚动靠 JS 端累积。 不是在 Python 里反复取 HTML,而是注入 JS 在浏览器侧拼接,减少往返。
  • 会话池化保登录态。 session_id 复用上下文,让「登录→翻页→抓取」这种多步流程可行。

6. 边界

  • Playwright 路径需要预先 crawl4ai-setup 下载 Chromium,体积大。
  • HTTP 路径跑不了 JS,SPA 会抓到空壳。
  • 反检测不保证成功,强反爬站点仍可能被拦(交给主线的重试 + 代理 + fallback,见 01 §4.2-4.4)。

7. 代码地图

主题文件路径符号名
抽象基类crawl4ai/async_crawler_strategy.pyAsyncCrawlerStrategy.crawl
浏览器抓取主体crawl4ai/async_crawler_strategy.pyAsyncPlaywrightCrawlerStrategy._crawl_web
钩子crawl4ai/async_crawler_strategy.pyexecute_hook
智能等待crawl4ai/async_crawler_strategy.pysmart_wait
虚拟滚动crawl4ai/async_crawler_strategy.py_handle_virtual_scroll
iframe 内联crawl4ai/async_crawler_strategy.pyprocess_iframes
HTTP 抓取crawl4ai/async_crawler_strategy.pyAsyncHTTPCrawlerStrategy.crawl
浏览器池化crawl4ai/browser_manager.pyBrowserManager
反检测适配器crawl4ai/browser_adapter.pyPlaywrightAdapterUndetectedAdapter