跳到正文

Fetch Policy 引擎

Markitai 使用策略驱动的 Fetch Policy 引擎来确定获取 URL 内容的最佳策略。该引擎设计为弹性、高效且用户友好。

策略选择逻辑

引擎按以下策略驱动的方式选择抓取策略的顺序:

  1. 显式策略:如果您提供了显式策略(如 -s playwright-s defuddle-s jina),引擎通常只会使用该策略,但有两个例外:显式的 -s defuddle/-s jina/-s cloudflare 在远程服务拒绝请求时(限流、认证失败等)仍会优雅回退到完整的 auto 链路;而域名配置中的内容类设置(wait_for_selectorskip_auto_scroll 等)即便在显式选择 playwright 时也仍然生效。
  2. 域名配置:您可以为特定域名配置专属设置,如自定义等待选择器、额外等待时间,或完整的自定义策略顺序。
  3. 自适应回退:在 auto 模式(默认)下,引擎根据域名和历史成功记录智能排序策略。

默认顺序(标准域名)

Markitai 采用本地优先策略:对于大多数网站,会先尝试原生本地流水线,再使用远程服务:

Static (HTTP) → Playwright (浏览器) → Defuddle → Jina → Cloudflare

Static 的原生 webextract 流水线在提取质量基准语料库上已能匹敌远程 Defuddle(在中日韩文本间距处理上甚至更优),因此排在最前。与远程策略不同,它不会把 URL 发送到本机之外。

SPA/重 JS 顺序

对于已知需要 JavaScript 的域名(如 x.cominstagram.comfallback_patterns 中列出的域名,或此前静态抓取失败并已被学习进 SPA 缓存的域名),Markitai 会直接跳转到浏览器:

Playwright (浏览器) → Defuddle → Jina → Cloudflare → Static

这里 Static 排在最后,因为对这些域名它已经失败过(或预期会失败),无法产出可用内容。

远程后备与仅限本地的 URL

fetch.remote_consent 的默认值是 always。对于公网 URL,本地策略失败后,Markitai 可以无需交互确认,继续尝试 Defuddle、Jina 或 Cloudflare。每个进程第一次准备使用远程服务时,会先在 stderr 输出说明。由于该决定会在进程内缓存,说明会完整列出后续可能授权的服务:defuddle.md、Jina、Cloudflare、FxTwitter 与 Twitter oEmbed。各远程服务仍按顺序逐个尝试,URL 只会发送给当前正在尝试的服务。

Playwright 还有一条公网 URL 增强路径:X/Twitter 状态或文章的本地 DOM 提取失败后,可能依次尝试 FxTwitter 与 Twitter oEmbed。它们和其他远程服务一样,共用同一个进程级同意决定,不再享有例外。在 ask 模式下,这意味着:如果本次运行尚未做出决定且终端可交互,这条路径自己就会弹出那一次共享确认;如果先前已经同意或拒绝,则直接沿用;无法询问时(非交互环境)则跳过。neverMARKITAI_NO_REMOTE_FETCH 会直接禁用它。同意是延迟解析的——只有在确认 URL 属于公网之后才会询问,因此绝不会为一个本就不会离开本机的 URL 弹出提问。

以下 URL 无论选择哪种策略,都只会留在本机处理:

  • localhost、私网 IP 和常见内网主机名
  • userinfo 或 query/fragment 敏感参数中带有认证信息的 URL,包括签名 URL、Token、签名、密码、API Key 与授权码

auto 策略链中,以下匹配项也只会留在本机处理:

  • 匹配 fetch.policy.local_only_patterns 的域名和 IP
  • 启用 fetch.policy.inherit_no_proxy 时,从 NO_PROXY 继承的条目

对于仍属公网的 URL,显式传入非 auto 远程 -s CLI 参数表示有意覆盖上述两项基于模式的规则及 fetch.remote_consent=never。仅在配置文件中设置远程 fetch.strategy 时仍受同意策略约束。两种路径都不能绕过私网、本机及自带认证信息 URL 的硬性保护。

如需获得硬性的全本机保证(包括显式指定远程策略的运行),请设置 MARKITAI_NO_REMOTE_FETCH=1。将 fetch.remote_consent 设为 never 会让自动策略链与配置文件选择的策略留在本机,但仍允许通过显式 CLI -s 主动选择远程服务。也可以设为 ask,让交互式终端按上述完整服务清单(含 X/Twitter 增强)做一次进程级确认;非交互环境在此设置下会跳过全部远程服务。

配置

您可以在 markitai.json 中调整 fetch policy:

json
{
  "fetch": {
    "policy": {
      "enabled": true,
      "max_strategy_hops": 5
    },
    "domain_profiles": {
      "x.com": {
        "wait_for_selector": "[data-testid=tweetText]",
        "wait_for": "domcontentloaded",
        "extra_wait_ms": 1200
      }
    },
    "playwright": {
      "session_mode": "domain_persistent",
      "session_ttl_seconds": 600
    }
  }
}

Policy 选项

选项类型默认值说明
enabledbooleantrue启用或禁用智能策略排序
max_strategy_hopsinteger5放弃前尝试的最大策略数
strategy_prioritylistnull自定义全局策略顺序(覆盖默认优先级)
local_only_patternslist[]限制为本地策略的域名/IP 模式(NO_PROXY 语法)
inherit_no_proxybooleantrueNO_PROXY 环境变量合并到 local_only_patterns

域名配置

域名配置允许按域名覆盖抓取行为:

选项类型默认值说明
wait_for_selectorstringnull提取内容前等待的 CSS 选择器
wait_forstringnull页面加载事件覆盖值(loaddomcontentloadednetworkidle);未设置时继承全局 fetch.playwright.wait_for(默认 domcontentloaded
extra_wait_msintegernull页面加载事件后的额外等待毫秒数覆盖值;未设置时继承全局 fetch.playwright.extra_wait_ms(默认 3000
prefer_strategystringnull该域名的首选策略(staticdefuddleplaywrightcloudflarejina
strategy_prioritylistnull该域名的自定义策略顺序(覆盖全局和 prefer_strategy
skip_auto_scrollbooleanfalse对单内容页面(推文、issue、文档)跳过自动滚动
reject_resource_patternslistnull阻止 Playwright 导航中匹配这些 URL 模式的资源(如 ["**/analytics/**"]

Markitai 内置了 x.com/twitter.comgithub.com 的域名配置。如果您为同一域名配置自己的条目,会整体替换内置配置,而不是逐字段合并。内置的调优(例如 x.com 配置里的 skip_auto_scroll/reject_resource_patterns)会随之丢失,除非您自己重新声明。

多域名配置示例:

json
{
  "fetch": {
    "domain_profiles": {
      "x.com": {
        "wait_for_selector": "[data-testid=tweetText]",
        "extra_wait_ms": 1200
      },
      "instagram.com": {
        "wait_for": "networkidle",
        "extra_wait_ms": 2000
      },
      "docs.example.com": {
        "prefer_strategy": "static"
      }
    }
  }
}

Playwright 会话持久化

控制 Playwright 如何管理浏览器上下文:

选项类型默认值说明
session_modestring"isolated"isolated:每个请求新建上下文;domain_persistent:按域名复用上下文
session_ttl_secondsinteger600持久化会话的保活时间(秒)

使用 domain_persistent 模式可以通过复用 cookies、localStorage 等浏览器状态,显著加速对同一站点的多次请求。

静态 HTTP 适配器

静态抓取(Static 策略)默认使用 httpx,适用于绝大多数网站。对于有 TLS 指纹检测的反爬站点,可选择启用 curl-cffi 适配器。

适配器安装方式特点
httpx(默认)内置,开箱即用快速可靠,覆盖大多数场景
curl-cffi(可选)uv pip install markitai[extra-fetch]模拟 Chrome TLS/HTTP 签名,绕过部分反爬保护

何时需要 curl-cffi?

大多数情况下不需要。如果 Static 策略对某些站点返回 403/空内容,Policy Engine 会自动回退到 Playwright 或 Cloudflare。只有当您需要在不启动浏览器的前提下绕过 TLS 指纹检测时,才需要 curl-cffi。

启用 curl-cffi

bash
# 安装
uv pip install markitai[extra-fetch]

# 设置环境变量激活
export MARKITAI_STATIC_HTTP=curl_cffi

即使设置了环境变量但未安装 curl-cffi,Markitai 也会静默降级到 httpx,不会报错。

工作原理

URL 请求

    ├─ 显式策略 (-s static/playwright/defuddle/jina/cloudflare)?
    │       └─ 是 → 仅使用该策略

    ├─ 域名在 SPA 缓存中或已知需要 JS(fallback_patterns)?
    │       └─ 是 → SPA 顺序(Playwright → Defuddle → Jina → Cloudflare → Static)

    └─ 默认 → 标准顺序(Static → Playwright → Defuddle → Jina → Cloudflare)

            ├─ 尝试策略 #1 → 成功? → 完成
            ├─ 尝试策略 #2 → 成功? → 完成
            ├─ 尝试策略 #3 → 成功? → 完成
            ├─ 尝试策略 #4 → 成功? → 完成
            └─ 尝试策略 #5 → 成功? → 完成 / 放弃

域名配置(strategy_priorityprefer_strategy)以及全局 strategy_priority 覆盖项,可以在 SPA/默认回退之前按域名或全局重新排序此链路。详见下方域名配置。私网、本机、内网及自带认证信息的 URL 始终只能使用本地策略(staticplaywright)。在策略链中,匹配 local_only_patterns 的域名也仅限本地策略;对于公网 URL,显式传入非 auto CLI -s 参数只会覆盖这一基于模式的限制。

每个策略在接受结果前都会验证内容质量,包括内容是否为空或过短、是否命中登录墙,以及是否是反爬/CAPTCHA 挑战页面(Geetest、Cloudflare、reCAPTCHA、hCaptcha)。校验未通过时会回退到下一个策略。

TIP

当静态抓取成功但内容显示需要 JavaScript 渲染(或页面为空)时,该域名会被加入 SPA 缓存,有效期 30 天。后续对该域名的请求将直接跳到浏览器渲染,节省时间。其他失败情形(CAPTCHA、登录墙、网络错误)不会触发这一学习机制,只有“需要 JS”这一信号会触发。