

# 如何根据必应搜索结果构建抓取队列

收集一小份必应搜索结果样本，检查每个地址和页面相关性，然后在加入抓取队列之前，将其标为已接受、已拒绝或未解决。Actor 是托管的数据采集程序。Task 是已保存的输入预设。Actor 收集源数据行，读者进行分析。

## 首次检查设置与来源约定

公开的 Google Search Scraper build 1.0.15 支持 Google、Bing、Brave 和 DuckDuckGo，但此处这一方法只明确接受 Bing。当前公开任务输入使用 `queries ["AI agents", "small business automation"]`、`engines ["bing"]`、`maxResultsPerExecutedQuery 20`、`country "US"`、`language "en"`、`safeSearch true` 和 `includeSponsoredResults false`。对于这次试点，把整个 queries 列表和 engines 列表替换为一个预定查询以及 `engines ["bing"]`，设置 `maxResultsPerExecutedQuery 2`、预定的国家、语言和相同的布尔值，并注明不存在扩展设置，也不存在公开的页面上限输入。

### 原生结果字段与输出摘要

每条数据集结果行包含这些确切字段：`runId`、`country`、`language`、`safeSearch`、`engine`、`executedQuery`、`page`、`rankOnPage`、`rank`、`title`、`canonicalUrl`、`resultDomain`、`snippet`、`isSponsored`、`advertiserDomain`、`observedAt` 和 `schemaVersion`。一行表示在某个引擎、某次查询、某一页和某个位置上的一次观测。`canonicalUrl` 字段提供的是规范化后的候选地址，不是已经检查过的 HTML canonical 标签，也不是原始链接。摘要是搜索文本，不是已获取的页面内容。

输出运行摘要报告这些项：`queriesRequested`、`searchesCompiled`、`executionsPlanned`、`enginesSuccessful`、`enginesFailed`、`pagesAttempted`、`pagesParsed`、`resultsSaved`、`engineStatusCounts`、`engineResultCounts`、`queryResultCounts` 和 `stopReason`。

### 必应对照运行参考

针对 `Python asyncio documentation` 的一次精确对照运行返回：

- `queriesRequested`：1
- `searchesCompiled`：1
- `executionsPlanned`：1
- `enginesSuccessful`：1
- `enginesFailed`：0
- `pagesAttempted`：1
- `pagesParsed`：1
- `resultsSaved`：2
- `engineStatusCounts`：`{"bing": {"ok": 1}}`
- `engineResultCounts`：`{"bing": 2}`
- `queryResultCounts`：`{"Python asyncio documentation": 2}`
- `stopReason`：`result_caps_reached`
- 返回的结果：两个直接指向 `docs.python.org` 的 URL，排名分别为 1 和 2。

这只证明一份有范围限制的必应元数据样本。它没有测试全部市场、搜索运算符、重复排名或目标获取。主要来源包括 [Google Search Scraper Actor](https://apify.com/chronometrica/google-search-scraper) 和 [Bing Search Results Task](https://apify.com/chronometrica/google-search-scraper/examples/bing-search-results-scraper)。

1. 在搜索之前，先确定你需要的页面和纳入规则。在这里，Bing 是受支持的发现来源。使用中性主题和有限的行数上限，不要承诺有数百个有效站点。搜索发现提供的是候选，并不承诺每个页面都能被采集。
2. 使用只含一个预定短语的查询，把引擎设为 bing，并设置较小的行数上限。检查已执行的查询、引擎、时间戳和输出。查询用词会改变你的源样本。除非你自己测试搜索引擎赋予这些词的含义，否则使用普通词语。
3. 在选择目标之前，保留返回的结果行。保留标题、候选地址、源主机、排名、查询、时间和来源停止状态。按你的规则拒绝损坏的地址或非网页地址。把不透明重定向或目标不明确的地址保持为未解决。像规范地址这样的规范化字段名，并不能证明原始页面的真实身份。把返回的字符串原样保留，作为源证据。
4. 按你的采集目的检查每个候选主机和路径。搜索标题和摘要可能过时或有误。需要时，使用你自己的采集流程检查公开目标。记录最终 URL、内容类型和页面证据。不要只凭标题猜测产品内容。登录页面和私人页面仍然不可用。
5. 把每个目标标为已接受、已拒绝或需要复核，并写明原因。已接受表示它在该时刻通过了你的检查。这并不保证抓取成功、权利完整或产品数据准确。不要把失败的目标检查和来源缺口放进已接受队列。
6. 只在安全规则下合并[已复核的重复目标地址](/zh-Hans/articles/%E6%90%9C%E7%B4%A2%E7%BB%93%E6%9E%9C%E5%90%88%E5%B9%B6-%E4%BF%9D%E7%95%99%E6%9F%A5%E8%AF%A2%E4%B8%8E%E6%8E%92%E5%90%8D%E8%AF%81%E6%8D%AE/)，同时保留全部结果引用。把观测记录和目标记录分开保存。不要删除用于区分不同页面的不同路径或查询参数。同一主机并不表示同一页面。同一标题并不表示同一目标。
7. 用目标地址、来源引用、接受证据、期望提取的内容和状态来构建小型队列。把已接受的目标传给一个专为这些页面制作、且有范围限制的独立爬虫。搜索 Actor 不会执行该抓取，也不会提供[正文](/zh-Hans/articles/%E7%BD%91%E9%A1%B5%E6%AD%A3%E6%96%87%E6%8F%90%E5%8F%96%E6%A3%80%E6%9F%A5/)。
8. 核对已收集的观测、已复核且各计一次的候选、已接受的目标、已拒绝的目标、未解决的目标，以及上限状态。已接受目标为零可以是正常缺口，不是要用猜测的页面去填满的列表。在扩大发现预算之前，先检查一个目标，然后结束。

## 原创虚构的分步演算示例

本节中的全部域名、词语和计数都是原创虚构。在精确目标规则下，七条返回的观测指向六个不同的候选地址。两条观测共用地址 `https://garden.example/products`. 另外五条观测分别指向一个产品页面、一篇博客指南、一次不透明重定向、一个登录页面和一个无效地址。

### 1. 七条结果观测

| 观测 ID | 查询 | 排名 | 观测时间 | 返回的 URL | 来源引用 |
| --- | --- | --- | --- | --- | --- |
| obs-1 | garden tools | 1 | 2026-10-13T06:20:14Z | https://garden.example/products | Bing 引擎，第 1 页 |
| obs-2 | indoor plants | 2 | 2026-10-13T06:20:15Z | https://garden.example/products | Bing 引擎，第 1 页 |
| obs-3 | garden tools | 3 | 2026-10-13T06:20:16Z | https://garden.example/items/shears | Bing 引擎，第 1 页 |
| obs-4 | indoor plants | 4 | 2026-10-13T06:20:17Z | https://blog.example/guide | Bing 引擎，第 1 页 |
| obs-5 | garden tools | 5 | 2026-10-13T06:20:18Z | https://redirect.example/out | Bing 引擎，第 1 页 |
| obs-6 | indoor plants | 6 | 2026-10-13T06:20:19Z | https://account.example/login | Bing 引擎，第 1 页 |
| obs-7 | garden tools | 7 | 2026-10-13T06:20:20Z | ftp://invalid.example/file | Bing 引擎，第 1 页 |

### 2. 六个不重复的目标候选及其状态

| 候选目标 URL | 目标检查结果 | 相关性状态 | 原因 / 证据 |
| --- | --- | --- | --- |
| `https://garden.example/products` | 有效的 HTTP 200 | accepted_target | 共享的产品索引符合采集范围。 |
| `https://garden.example/items/shears` | 有效的 HTTP 200 | accepted_target | 具体产品页面符合采集范围。 |
| `https://blog.example/guide` | 有效的 HTTP 200 | rejected_target | 博客指南与产品采集无关。 |
| `https://redirect.example/out` | 不可用 / 不透明 | needs_review | 不透明重定向无法直接核验。 |
| `https://account.example/login` | 需要登录 | needs_review | 目标需要身份验证；不可用。 |
| `ftp://invalid.example/file` | 非 HTTP scheme | rejected_target | 格式错误或非 http 的地址违反采集规则。 |

### 3. 两个已接受的队列目标

| 目标地址 | 来源引用 | 检查证据 | 期望的下一步提取 | 目标状态 |
| --- | --- | --- | --- | --- |
| `https://garden.example/products` | obs-1, obs-2 | 已核验 HTTP 200 状态，符合产品索引标准 | 提取分类商品列表 | accepted |
| `https://garden.example/items/shears` | obs-3 | 已核验 HTTP 200 状态，符合单个产品标准 | 提取产品详情和价格 | accepted |

核对结果显示，六个候选产生两个已接受目标、两个已拒绝目标和两个未解决目标。产品索引的两条观测仍然附在同一个队列目标上，并保留两者的查询、排名和时间引用。不要把七条观测称为七个抓取站点，也不要丢弃重复引用。如果稍后独立爬虫运行时产品索引失败，请记录该失败；较早的接受并不保证能够提取。

## 下一步行动

在把该已接受目标加入独立抓取队列之前，先记录一个候选目标及其相关性检查；如果不可用，则保留 needs_review。使用 [Google Search Scraper Actor](https://apify.com/chronometrica/google-search-scraper) 和 [Bing Search Results Task preset](https://apify.com/chronometrica/google-search-scraper/examples/bing-search-results-scraper)。

## 来源和延伸阅读

- [自动化查找用于抓取 Reddit 讨论的 URL 的流程](https://www.reddit.com/r/learnpython/comments/f96o07/automate_the_process_of_finding_urls_for_scraping/)