本页内容
大多数关键词研究工具回答的是错误的问题。它们告诉你一个词条在 1 到 100 的尺度上有多难,那是摘要的摘要。你真正需要知道的是谁占据着前十名,以及那些是什么类型的页面,因为这决定了这个位置究竟能不能拿下。
本指南把这套分析搭成一条跑在 MCP 连接上的可复现流水线。这正是我们2026 年 web scraping SERP 研究背后的方法,也包括那个让大多数自制关键词研究失效的错误。
目录
- 三个阶段
- 让大多数关键词研究变成虚构的错误
- 阶段一:发现候选词条
- 阶段二:拉取真实自然排名
- 阶段三:分类页面类型
- 给差距打分
- 在投入之前检查意图
- credits 成本与运行时间
- 从 REST API 运行
- 常见问题
三个阶段
| 阶段 | Tool | Credits | 回答什么 |
|---|---|---|---|
| 发现 | search_web | 5 | 存在哪些词条、有谁出现 |
| 测量 | serp_rank | 5 | 真实的自然前十名 |
| 分类 | analyze_content(可选) | 3 | 每个结果是什么类型的页面 |
阶段三通常靠人的判断而不是调用 tool——你要标注的是九个 URL,用眼睛看比走 API 更快。
让大多数关键词研究变成虚构的错误
从这里开始,因为它会让后面所有环节失效。
搜索 API 的结果顺序不是 Google 的排名。 搜索工具会先检索结果,然后重新排序。CrawlForge 的 search_web 会用 BM25、语义相似度、权威度和新鲜度权重对检索结果重排,并且在响应中如实报告了这一点:
{
"processing": {
"ranking": {
"algorithmsUsed": ["bm25", "semantic", "authority", "freshness"],
"weightsApplied": { "bm25": 0.4, "semantic": 0.3, "authority": 0.2, "freshness": 0.1 }
}
}
}这种重排让结果更适合调研,也让它无法用于衡量排名。如果你从搜索 API 读出第 1 位并把它记录为 Google 排名,那么建立在其上的每一条结论都是错的。
用 search_web 了解哪些域名在场。任何你打算称之为“位置”的东西,都用 serp_rank——它返回的是 Google 自己的 rank_group 值。
阶段一:发现候选词条
先把范围放宽。你要找的是这个品类的词汇,还不是排名。
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
const client = new Client({ name: 'keyword-gap', version: '1.0.0' });
interface Candidate {
keyword: string;
indexedPages: number;
domains: string[];
}
async function discover(keyword: string): Promise<Candidate> {
const res = await client.callTool({
name: 'search_web',
arguments: { query: keyword, limit: 20 },
});
const data = JSON.parse(res.content[0].text);
return {
keyword,
// Google's rough index estimate -- a crowding signal, NOT search volume.
indexedPages: parseInt(data.total_results ?? '0', 10),
// Presence only. This order is re-ranked and is not a Google ranking.
domains: [...new Set(data.results.map((r) => r.displayLink))],
};
}有两个字段重要。total_results 是 Google 对竞争页面数量的粗略估算——一个拥挤程度信号,不是搜索量。域名列表告诉你谁在这场对话里。
阶段二:拉取真实自然排名
现在开始测量。serp_rank 会发起一次实时 Google 查询,返回真实的自然排名位置以及竞争对手列表。
interface RankResult {
keyword: string;
found: boolean;
position: number | null;
competitors: Array<{ position: number; domain: string; url: string }>;
}
async function measure(keyword: string, target: string): Promise<RankResult> {
const res = await client.callTool({
name: 'serp_rank',
arguments: {
keyword,
target,
location_name: 'United States',
device: 'desktop',
depth: 10,
},
});
const data = JSON.parse(res.content[0].text);
// Unconfigured deployments return configured:false rather than a fake rank.
if (data.configured === false) {
throw new Error('serp_rank is not configured on this server');
}
return {
keyword,
found: data.found,
position: data.position,
competitors: (data.results ?? []).map((r) => ({
position: r.position,
domain: r.domain,
url: r.url,
})),
};
}要顺序执行,不要并行。 实时 SERP 端点会执行一次真实的 Google 查询;同时发起多个请求必然导致超时,而不是更快出结果。
depth: 10 是合适的默认值。扫描更深成本更高,而且对差距分析来说,第 11 位往后的结果很少会改变决策。
阶段三:分类页面类型
这是真正产出洞察的阶段,而且主要靠判断。
对九个或十个结果中的每一个,标注它属于哪种页面:
- 商业页 — 首页、产品页、定价页
- 厂商内容 — 某家公司的博客文章或文档
- 独立页面 — 目录站、论坛帖子、代码仓库、新闻报道
然后数一数商业结果的数量。这一个数字比任何难度分都更能说明问题:
type PageType = 'commercial' | 'vendor-content' | 'independent';
function gapScore(labels: PageType[]): 'closed' | 'contested' | 'open' {
const commercial = labels.filter((l) => l === 'commercial').length;
if (commercial >= 4) return 'closed';
if (commercial >= 1) return 'contested';
return 'open';
}套用到我们研究中的真实数据:
| 关键词 | 商业结果 | 判定 |
|---|---|---|
| web scraping api | 9 个中 6 个 | 关闭 |
| firecrawl alternative | 9 个中 2 个 | 争夺中 |
| mcp scraping | 8 个中 0 个 | 开放 |
“web scraping api”是关闭的——六个厂商首页和产品页,每一个背后都是多年的外链建设。再高的内容质量也撼动不了。
“firecrawl alternative”落在中间。只有两个结果是商业落地页,即 Apify 的替代品页面和 Context 的一个比较页,但其余部分密集地挤满了厂商博客文章,全都在追逐同一批正在离开的客户。可以打赢,但很拥挤,只有当你确实有具体内容可说时才值得投入。
“mcp scraping”判定为开放,其构成解释了原因:两个目录站、一个 Reddit 帖子、一个 GitHub 仓库、三篇第三方博客和一个文档页。没有人为它发布过商业页面。
给差距打分
把两个信号结合起来。一个词条值得投入的条件是 SERP 开放并且拥挤程度可控:
interface Scored {
keyword: string;
verdict: 'closed' | 'contested' | 'open';
indexedPages: number;
priority: 'high' | 'medium' | 'skip';
}
function prioritise(c: Candidate, verdict: Scored['verdict']): Scored['priority'] {
if (verdict === 'closed') return 'skip';
if (verdict === 'open' && c.indexedPages < 2_000_000) return 'high';
return 'medium';
}这个阈值是判断,不是定律。重要的是排序:开放且中等拥挤的 SERP,永远胜过争夺中但拥挤度低的 SERP。
在投入之前检查意图
最后一道关卡,而且无法自动化。
读一读前十名的标题,问问那些搜索者是否想买你卖的东西。在我们的研究中,“llm scraper”通过了所有数值筛选——32.9 万个竞争页面,明显切题——一接触真实结果就失败了。其中相当大一部分是想屏蔽 scraper 的人:一个叫“Prevent LLM scrapers/trawlers?”的 YunoHost 帖子、一个关于如何对抗它们的 r/sysadmin 帖子、Akamai 谈机器人管理的文章。
同样的词,相反的意图。在那里排名换来的是永远不会转化的流量,以及一个会教会 Google“你的页面是个糟糕答案”的跳出率。
三十秒的阅读能抓住任何分数都看不见的东西。
credits 成本与运行时间
一次十关键词的研究:
| 项目 | 调用次数 | Credits |
|---|---|---|
| 发现 | 10 次 search_web | 50 |
| 测量 | 10 次 serp_rank | 50 |
| 合计 | 100 |
这是 Free 方案 1,000 个一次性 credits 的十分之一。
运行时间才是真正的约束。在我们的测量中,实时 SERP 查询每次耗时在 10 到 41 秒之间——同一个关键词在连续两次运行中分别是 11 秒和 28 秒,因为该端点执行的是一次实时 Google 查询,其延迟取决于上游容量。十个关键词顺序执行需要五到十分钟。把客户端超时设为至少 60 秒,并把任务放到后台运行。
从 REST API 运行
如果你不在 MCP 客户端里,同样的查询也可以走 HTTP:
curl -X POST https://www.crawlforge.dev/api/v1/tools/serp_rank \
-H "X-API-Key: $CRAWLFORGE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"keyword": "mcp scraping",
"target": "crawlforge.dev",
"location_name": "United States",
"depth": 10
}'REST 响应使用 rank 和 all_positions,而 MCP tool 返回的是 position;两者报告的是底层同一个 Google 自然排名位置。失败的查询——提供方不可达、超时——会返回错误,并且不计费。
下一步
一旦你知道哪些词条是开放的,接下来的工作就是技术层面的:确保你为它们发布的页面确实可被抓取且标记正确。我们的用 CrawlForge 自动化 SEO 审计指南覆盖了这另一半,而 serp_rank API 参考记录了上面用到的每一个参数。
免费开始,赠 1,000 credits——足够约 200 次排名检查。
亲自试一试——无需注册
在 Playground 中运行 CrawlForge 的 28 个抓取与提取工具中的任意一个,然后免费开始,获取 1,000 credits。
1,000 免费 credits • 一次性 • 无需信用卡
标签
及时获取最新洞察
将教程、产品更新与 Web 抓取技巧直接发送到你的收件箱。
拒绝垃圾邮件,随时可取消订阅。