mcpField
C
Crawl Census

Crawl Census

远程服务
crawlcensus.com浏览器自动化09 周前更新

关于 Crawl Census

Crawl Census 为爬虫提供客户端和远程 MCP 服务,可在抓取前检查域名是允许、拒绝还是收费,帮助开发者减少无效请求并识别付费内容。

主要功能

  1. 01预检域名处理结果
  2. 02支持 JavaScript 和 Python 礼貌抓取
  3. 03按结果拆分 URL 队列
  4. 04同步阻止列表和变更记录
  5. 05查看站点报告与普查数据

适用场景

  1. 01抓取前检查域名是否允许
  2. 02区分收费站点与拒绝访问
  3. 03抓取前筛选大型 URL 队列

MCP 相关

其位于 https://crawlcensus.com/mcp 的远程 MCP 服务提供预检、Agent 资料、普查事实与统计、站点报告和扫描工具。

配置

远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。

服务地址https://crawlcensus.com/mcp
一键复制安装命令
Claude CodeTerminal
Cursor.cursor/mcp.json
VS Code.vscode/mcp.json
Claude Desktopclaude_desktop_config.json
Windsurf~/.codeium/windsurf/mcp_config.json

命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。

工具

7
参数类型必填说明
domainstring是不带路径的主机名,例如 example.com

详细介绍

crawl-census-client

先询问,再抓取。 这是一款即插即用的客户端,能避免爬虫把请求浪费在紧闭的大门上,也能避免它绕过有人试图出售的内容。

阅读 robots.txt 能回答一个问题,却会掩盖另外两个问题。根据 Crawl Census 对 23,482 个域名的测量结果:

  • 2,874 个域名在 robots.txt 中允许 AI Agent 抓取,随后却在网络边缘拒绝这些 Agent。 解析器看到的是允许;抓取请求却返回 403。你为这次往返付出代价,却一无所获。
  • 208 个域名会向 AI 用户代理返回 HTTP 402 Payment Required。 这是报价,不是拒绝。把它当作拦截,就会放弃运营方想卖给你的内容。绕过它重试,就是拿走对方正在收费的内容。

无依赖项。无需密钥。

MCP 服务

同一组测量结果也通过远程 MCP 服务提供,因此 Agent 可以在抓取前询问,而不是失败后才询问。该服务已列入 官方 MCP 注册表,名称为 io.github.taylorsmithgg/crawl-census。

{ "mcpServers": { "crawl-census": { "url": "https://crawlcensus.com/mcp" } } }
工具回答的问题
crawl_preflight这些域名会向我的 Agent 提供内容、拒绝它,还是向它收费?
agent_profile这份普查发布了哪些关于我的爬虫的信息?我该如何更正?
census_facts以带日期的记录、分母和引用内容呈现的主要发现
site_report某个域名的存储审计报告
scan_site立即测量某个域名
census_stats语料库级别的总计

读取工具无需身份验证。采用 Streamable HTTP。

安装

npm i github:taylorsmithgg/crawl-census-client
pip install git+https://github.com/taylorsmithgg/crawl-census-client

使用

import { politeFetch } from "crawl-census-client";

const r = await politeFetch("https://example.com/", { agent: "gptbot" });
if (r.skipped) console.log(r.verdict, r.reason);   // disallow | refuse | pay
else           process(await r.response.text());
from crawl_census import polite_fetch

r = polite_fetch("https://example.com/", agent="gptbot")
if r.skipped:
    print(r.verdict, r.reason)
else:
    process(r.body)

跳过会作为结果返回,而不会抛出异常。对于网络中的很大一部分站点,这是正常情况;抓取循环应能统计跳过次数,而不必为每个 URL 都套上 try/except。

抓取前拆分队列

每 1,000 个域名调用一次,而不是每个主机调用一次:

const { crawl, skip, pay, unknown } = await partition(urls, { agent: "gptbot" });
p = partition(urls, agent="gptbot")
p.crawl, p.skip, p.pay, p.unknown

或者直接获取文件

如果抓取器只需要在内存中保存一份拒绝列表,可以完全跳过逐域名调用:

curl https://crawlcensus.com/agents/gptbot/blocklist.txt   # one domain per line, commented header
const sync = await syncBlocklist("gptbot");   // full list once
if (sync.blocked.has(host)) skip();
setInterval(() => sync.refresh(), 3600_000);  // then deltas only, a few hundred bytes
sync = BlocklistSync("gptbot")
if host in sync: skip()
sync.refresh()          # {'added': 3, 'removed': 1, 'size': 3310, 'cursor': ...}

增量数据源地址为 https://crawlcensus.com/agents/<agent>/changes.json?since=<unix>,每个响应都会包含 next_since,因此长时间运行的爬虫每小时只需下载几百字节,就能保持最新状态,而无需重新下载整个列表。

该文件仅涵盖 robots.txt。边缘拒绝和 HTTP 402 是逐请求行为,仍需使用 preflight 或 politeFetch。

一次抓取会给普查带来多少开销

这是实测结果,而非推测。过去,并发抓取 20 个主机会产生 20 次预检调用,每次只包含一个域名;同时请求同一个主机三次会产生三次调用,因为缓存只有在首次查询完成后才会生效。匿名额度为每小时 240 次调用,因此当一次调用涵盖 25 个主机时,爬虫会在 240 个主机时达到上限。

现在,politeFetch 会自动共享查询:同一时刻发起的查询会合并为一次批量调用;并发查询同一主机时,则会等待同一个请求完成。

模式之前现在
并发请求 20 个主机20 次调用1 次调用,包含 20 个主机
并发请求 1 个主机的 3 个 URL3 次调用1 次调用
并发请求 60 个主机60 次调用3 次调用(25 / 25 / 10)
先调用 partition 再抓取2 次调用1 次调用

batchSize 默认为 25,这是无密钥时每次调用的上限。使用 Pro 或 Data 密钥可调高该值。 batchWaitMs 会延长合并窗口,以适应分批到达而非同时到达的并发请求;默认值为零,会在下一个时钟周期刷新。

当来源站点报价时付费

如果来源站点给出了金额,pay 判定结果会包含该金额:

const r = await politeFetch(url, { agent: "claudebot" });
if (r.verdict === "pay") console.log(r.price);   // "USD 0.5", or null if none was quoted

有两点值得注意。大多数返回 HTTP 402 的来源站点都没有给出金额,因此 price 通常为 null,双方必须通过其他渠道协商。此外,收费方式因爬虫而异:在测量的语料库中,213 个收费来源站点里有 78 个会向部分 Agent 收费,却为其他 Agent 免费提供内容。因此,请使用你自己的令牌进行查询,不要假定列表中的域名一定会向你收费。

两种未知状态

partition 会将工作队列划分为 crawl、pay、skip、unknown 和 undecidable。

后两者看起来相似,实际并非如此。unknown 表示尚未测量该域名:提交它,下次检查就会给出实际判定。undecidable 表示该站点的 robots.txt 禁止 CrawlCensusBot,因此这次普查永远不会测量它——重试注定是浪费,而每次都重新提交未知项的循环会永远重新提交这些域名。服务端用 measurable 布尔值标记二者的区别;应读取它,绝不要依据 reason 的文字说明判断。

const p = await partition(urls, { agent: "gptbot" });
await Promise.all(p.crawl.map(politeFetchOne));
if (p.unmeasured.length) await submitUnmeasured(p, { agent: "gptbot" });
// p.undecidable: read their robots.txt yourself. Asking us again cannot help.

提交是单独的一次调用,这是有意为之。一个在看起来像查询的操作中悄悄发送 POST 请求的库不是合格的公民,而且你应该自行决定何时消耗队列位置。

跳过所有无法为你提供服务的对象

拒绝列表只覆盖较小的一部分。根据实时普查数据,只跳过 robots.txt 禁止抓取的域名,每轮仍会在大约 2,900 个域名上浪费请求:这些域名虽然在 robots.txt 中允许抓取,却在边缘拒绝请求,或返回 HTTP 402——对于 PerplexityBot,这类域名甚至多于其拒绝列表中的域名。这些请求什么也拿不到,每个都会耗费一次往返。

const skip = await syncSkipList("gptbot");
if (skip.has(host)) continue;        // disallowed, refused at the edge, or priced
skip.why(host);                      // "disallow" | "pay" | "refuse" | null
setInterval(() => skip.refresh(), 3600_000);
Agent拒绝列表还可跳过总计
GPTBot3,5422,9446,486
ClaudeBot3,1693,1946,363
PerplexityBot1,1283,6584,786

内部会将这三类状态分开保存,因此有变化时,只会更新所属的那一类。why() 遵循与预检相同的优先级:禁止访问优先于收费,因为收费不等于许可。

保持拒绝列表最新

syncBlocklist / BlocklistSync 会先下载列表,然后只应用发生变化的内容。

列表会通过 x-cursor 标头和 # cursor: 注释,提供生成列表时变更流中的精确位置。客户端会读取该位置并从那里继续,因此快照与首次轮询之间不会出现空档,也不依赖你的时钟与服务端同步。按秒轮询无法表示一秒内的具体位置;而一次抓取批次可能会在同一秒写入数十条事件,因此按秒精度恢复可能会遗漏剩余事件:实时测量显示,在三个同秒变更中的第一个之后恢复,使用游标找回了另外两个变更,而按秒恢复则一个也没找回。

const sync = await syncBlocklist("gptbot");   // cursor comes from the list itself
if (sync.blocked.has(host)) skip();
setInterval(() => sync.refresh(), 3600_000);  // a few hundred bytes per poll

refresh() 只会将 robots 状态变更应用到列表,因为列表本身只由这类状态构成。边缘拒绝、新价格和 llms.txt 变更会返回到 other 中,供你单独处理——早期版本会将这些域名从拒绝列表中删除,导致爬虫恢复抓取刚刚开始拒绝它的域名。

判定结果

每种判定结果的权威定义——其含义、对爬虫的要求,以及再次查询是否可能改变结果——以数据形式发布在 /api/v1/verdicts。下表只是摘要;如果两者有任何出入,以该接口为准,本文档已过时。

politeFetch 默认会跳过 disallow、refuse 和 pay,这与接口派生出的 do_not_fetch 集合一致。这里特意保留了这份副本——抓取循环不应为了做出判断而发起网络请求——并且有测试会对比两者,确保它们不会在无人察觉的情况下产生偏差。

判定结果含义默认行为
allowrobots.txt 允许此 Agent,且携带其用户代理的实时请求已成功获得响应抓取
disallowrobots.txt 在站点根路径禁止此 Agent跳过
refuserobots.txt 允许访问,但边缘仍拒绝了请求。该许可并非真实许可跳过
pay源站返回了 HTTP 402。该站点会按商业条款向此 Agent 提供服务跳过
unknown测量结果不够新,无法作出判定抓取

onPay: "fetch"(on_pay="fetch")会覆盖付费墙的默认行为。这是明确选择加入的选项,结果中会记录 paidRouteOverridden,便于在日志中查看。

它会降级运行,而不会失败

如果人口普查服务无法访问,所有判定都会变为 unknown,爬取也会照常继续。第三方服务中断绝不能停止你的流水线。我们专门为此提供了一项实时测试。

我们会发布哪些关于你的 Agent 的信息

const p = await agentProfile("claudebot");
// robots disallow rate, edge refusal rate, operator page, correction channel

如果某项数据有误,该响应中以及你的运营者页面上都提供了更正渠道。注册信息会直接更正,不作争辩;有争议的测量结果会连同争议和底层扫描记录一并发布,而不会悄悄修改。

限制

匿名用户每次预检最多可查询 25 个域名;使用 Pro 密钥时最多可查询 200 个,使用 Data 密钥时最多可查询 1,000 个。传入 apiKey。详情请见 https://crawlcensus.com/for-crawlers。

测试

node test.mjs 会刻意针对实时人口普查服务运行。这个客户端的价值在于其判定是否符合现实,而模拟测试只能验证模拟结果是否与自身一致。

采用 MIT 许可。数据采用 CC BY 4.0 许可,署名格式为“来源:Crawl Census(crawlcensus.com)”。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。