无需 KYC — 无身份证、无自拍、无证件。加密货币支付:BTC, USDT, USDC, ETH, SOL, LTC
语言: 简体中文
获取 API 密钥

文档 · 任务

批量与整站抓取 (crawl) API:读取多个 URL 或整个网站

两个 endpoint 启动后台任务:/batch 用于最多 100 个 URL 的列表,/crawl 用于一个网站。两者都返回 job ID;你从 /jobs/{job_id} 收集页面,一次一页结果。

最后更新: · 4 分钟阅读

快速回答

如何使用 WebReaderAPI 将网站整站抓取 (crawl) 为 Markdown?

将起始 URL 连同页面 limit 发送到 POST https://webreaderapi.com/api/v1/crawl。WebReaderAPI 在后台读取网站,仅限同一域名,遵循其 sitemap、robots.txt 和 Crawl-delay,每个任务最多 10,000 页。从任务中收集 Markdown 页面,一次一页结果。每次页面读取花费 1 积分(使用浏览器为 2),自 2026 年 10 月起从 US$0.07/千页 起。无需 KYC;加密货币支付。

任务一览

批量每个批量任务最多 100 个 URL:POST https://webreaderapi.com/api/v1/batch
整站抓取 (crawl)每个任务抓取一个网站,最多 10,000 页,遵循其 sitemap、robots.txt 和 Crawl-delay:POST https://webreaderapi.com/api/v1/crawl
结果GET https://webreaderapi.com/api/v1/jobs/{job_id},然后 ?cursor=… 获取下一页结果
计费每次页面读取按 /read 调用计费;被 robots.txt 跳过的页面和失败的页面不收费
整站抓取 (crawl) 范围一个域名;指向其他域名的链接会列出但不读取
取消任务v1 中不可用:将 limit 设置为你准备支付的最大页数

启动批量任务

POST/api/v1/batch

在后台使用相同选项读取最多 100 个 URL。选项使用 /read 的名称和值。答案是 job ID;值仅为示例。

认证:将 API 密钥放在 Authorization: Bearer API_KEY 请求头中。

请求体

字段类型必填描述
urlsarray of strings是1 到 100 个 http 或 https URL。重复的只读取一次。
optionsobject否除 url 外的任意 /read 参数:format、main_content、render、include_links、include_images、country、max_chars、timeout。
示例: three articles as Markdown
{
  "urls": [
    "https://example.com/blog/post-1",
    "https://example.com/blog/post-2",
    "https://example.org/news/launch"
  ],
  "options": {
    "format": "markdown",
    "max_chars": 50000
  }
}

响应 202 Accepted

{
  "job_id": "job_5c1e8a90d2"
}

代码示例

curl
curl -s "https://webreaderapi.com/api/v1/batch" \
  -H "Authorization: Bearer $WEBREADER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"urls": ["https://example.com/blog/post-1", "https://example.com/blog/post-2"], "options": {"format": "markdown"}}'
Python
import os
import requests

resp = requests.post(
    "https://webreaderapi.com/api/v1/batch",
    headers={"Authorization": "Bearer " + os.environ["WEBREADER_API_KEY"]},
    json={"urls": ["https://example.com/blog/post-1", "https://example.com/blog/post-2"], "options": {"format": "markdown"}},
    timeout=30,
)
print(resp.json()["job_id"])
Node.js
const res = await fetch('https://webreaderapi.com/api/v1/batch', {
  method: 'POST',
  headers: { Authorization: `Bearer ${process.env.WEBREADER_API_KEY}`, 'Content-Type': 'application/json' },
  body: JSON.stringify({ urls: ['https://example.com/blog/post-1', 'https://example.com/blog/post-2'], options: { format: 'markdown' } }),
});
console.log((await res.json()).job_id);

启动一个整站抓取 (crawl) 任务

POST/api/v1/crawl

从一个起始 URL 开始,按广度优先读取一个网站。爬虫只会停留在起始 URL 的域名内,使用 robots.txt 中指定的站点地图或位于 /sitemap.xml 的站点地图,并遵守 robots.txt 和 Crawl-delay。以下数值仅为示例。

认证:将 API 密钥放在 Authorization: Bearer API_KEY 请求头中。

请求体

字段类型必填描述
urlstring是起始页面,例如文档站点的首页。
limitinteger否最多读取的页面数,上限为 10,000。任务达到该数量时停止。
max_depthinteger否距起始 URL 最多的链接步数。
include_pathsarray of strings否要保留的简单路径模式,例如 /docs/*。
exclude_pathsarray of strings否要跳过的简单路径模式,例如 /blog/tag/*。
optionsobject否除 url 外的任意 /read 参数,应用于每个页面。
示例: the docs section of a site, 500 pages at most
{
  "url": "https://docs.example.com/",
  "limit": 500,
  "max_depth": 3,
  "include_paths": [
    "/docs/*"
  ],
  "exclude_paths": [
    "/docs/archive/*"
  ],
  "options": {
    "format": "markdown"
  }
}

响应 202 Accepted

{
  "job_id": "job_8b27f41c0e"
}

代码示例

curl
curl -s "https://webreaderapi.com/api/v1/crawl" \
  -H "Authorization: Bearer $WEBREADER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://docs.example.com/", "limit": 500, "include_paths": ["/docs/*"]}'
Python
import os
import requests

resp = requests.post(
    "https://webreaderapi.com/api/v1/crawl",
    headers={"Authorization": "Bearer " + os.environ["WEBREADER_API_KEY"]},
    json={"url": "https://docs.example.com/", "limit": 500, "include_paths": ["/docs/*"]},
    timeout=30,
)
print(resp.json()["job_id"])
Node.js
const res = await fetch('https://webreaderapi.com/api/v1/crawl', {
  method: 'POST',
  headers: { Authorization: `Bearer ${process.env.WEBREADER_API_KEY}`, 'Content-Type': 'application/json' },
  body: JSON.stringify({ url: 'https://docs.example.com/', limit: 500, include_paths: ['/docs/*'] }),
});
console.log((await res.json()).job_id);

获取任务状态和结果

GET/api/v1/jobs/{job_id}

返回任务状态以及已就绪的下一批结果。results 中的每一项要么是完整的 /read 响应,要么是 {url, error},表示该页面无法读取。当出现 next_cursor 时,将其设为 cursor 再次调用;当它不存在时,表示暂无更多结果就绪。以下数值仅为示例。

认证:将 API 密钥放在 Authorization: Bearer API_KEY 请求头中。

参数

名称位置类型必填描述
job_idpathstring是由 /batch 或 /crawl 返回的 ID。
cursorquerystring否上一次调用返回的 next_cursor 值,用于获取后续结果。

响应 200

{
  "job_id": "job_8b27f41c0e",
  "status": "running",
  "results": [
    {
      "url": "https://docs.example.com/docs/install",
      "final_url": "https://docs.example.com/docs/install",
      "status_code": 200,
      "rendered": false,
      "credits_used": 1,
      "title": "Install",
      "markdown": "# Install\n\nRun the installer...",
      "word_count": 418
    },
    {
      "url": "https://docs.example.com/docs/private",
      "error": {
        "code": "blocked_by_robots",
        "message": "robots.txt disallows this page for WebReaderAPI."
      }
    }
  ],
  "next_cursor": "c_000002",
  "credits_used": 1
}

代码示例

curl
curl -sG "https://webreaderapi.com/api/v1/jobs/job_8b27f41c0e" \
  -H "Authorization: Bearer $WEBREADER_API_KEY" \
  -d cursor=c_000002
Python
import os
import requests

resp = requests.get(
    "https://webreaderapi.com/api/v1/jobs/job_8b27f41c0e",
    headers={"Authorization": "Bearer " + os.environ["WEBREADER_API_KEY"]},
    params={"cursor": "c_000002"},
    timeout=30,
)
job = resp.json()
print(job["status"], len(job["results"]), job.get("next_cursor"))
Node.js
const res = await fetch('https://webreaderapi.com/api/v1/jobs/job_8b27f41c0e?cursor=c_000002', {
  headers: { Authorization: `Bearer ${process.env.WEBREADER_API_KEY}` },
});
const job = await res.json();
console.log(job.status, job.results.length, job.next_cursor);

如何等待任务完成?

轮询 /jobs/{job_id} 并保留 cursor。处理拿到的结果,然后将 cursor 设为 next_cursor 再次调用。当 next_cursor 不存在且 status 为 done 时,说明已获取全部结果;当它不存在且任务仍为 running 时,等待后用同一个 cursor 再次查询。

开始时间隔 2 秒轮询一次,在没有新结果到达时每次将等待时间翻倍,最多 30 秒。遵守站点 Crawl-delay 的整站抓取 (crawl) 可能需要较长时间,因此等待久一点是正常的,且不产生费用。

Python:轮询任务并将每个页面保存为 .md 文件
import os
import pathlib
import re
import time

import requests

JOBS = "https://webreaderapi.com/api/v1/jobs"
HEADERS = {"Authorization": "Bearer " + os.environ["WEBREADER_API_KEY"]}


def save_job(job_id, folder="pages"):
    out = pathlib.Path(folder)
    out.mkdir(exist_ok=True)
    cursor, wait, saved = None, 2, 0
    while True:
        params = {"cursor": cursor} if cursor else {}
        job = requests.get(f"{JOBS}/{job_id}", headers=HEADERS, params=params, timeout=30).json()
        for item in job["results"]:
            if "error" in item:
                print("skipped", item["url"], item["error"]["code"])
                continue
            name = re.sub(r"[^a-z0-9]+", "-", item["final_url"].lower()).strip("-")[:120]
            (out / f"{name}.md").write_text(item["markdown"], encoding="utf-8")
            saved += 1
        if job.get("next_cursor"):
            cursor, wait = job["next_cursor"], 2
            continue
        if job["status"] == "done":
            return saved
        time.sleep(wait)
        wait = min(wait * 2, 30)


if __name__ == "__main__":
    print(save_job("job_8b27f41c0e"), "pages saved")

整站抓取 (crawl) 会读取哪些页面?

整站抓取 (crawl) 从你的 URL 开始,按广度优先一次向外扩展一个链接步,最多到 max_depth。它还会读取站点的站点地图,地址来自 robots.txt 中给出的地址或 /sitemap.xml,以找到链接指向较少的页面。

  • 仅限同一域名。 指向其他域名的链接在你请求 include_links 时会列在结果中,但不会被读取。
  • 路径过滤。 include_paths 和 exclude_paths 接受 /blog/* 之类的简单模式。
  • 每页只读一份。 当站点声明了 canonical URL 时,通过多个地址到达的同一页面只读取一次。
  • 硬性停止。 任务在读取 limit 个页面后结束。

整站抓取 (crawl) 如何遵守站点规则?

每个请求都带有 User-Agent WebReaderAPI/1.0 (+https://webreaderapi.com/bot/),爬虫会遵循适用于 WebReaderAPI 的 robots.txt 规则;若没有为其命名的规则,则遵循用于所有爬虫的规则。被禁止的页面会被跳过,并以错误 blocked_by_robots 出现在 results 中;这些页面不计费。

当 robots.txt 设置了 Crawl-delay 时,爬虫在对该站点的两次请求之间会等待那么久。如果网站在其 robots.txt 中声明 Content-Signal: ai-input=no,我们不会为你读取其页面。如果网站拒绝我们的请求,我们会返回其答复:我们从不破解 CAPTCHA、不登录账户,也不试图绕过封锁或付费墙。

整站抓取 (crawl) 的费用是多少?

每个读取的页面都按一次 /read 调用计费:1 积分,若页面需要浏览器则为 2 积分,使用 country 时再加 10 积分。被跳过和失败的页面免费。任务的 credits_used 会累计截至目前已计费的金额。

一个 500 页的文档站点在不使用浏览器的情况下读取约消耗 500 积分,10,000 个网页 套餐(US$3.75)可以覆盖很多次。由于 v1 中任务无法取消,limit 就是你的支出上限:把它设为你能承受付费的最大页面数。

批处理与整站抓取:常见问题

应该用 /batch 还是多次调用 /read?

当你已经拥有 URL 且不需要立即拿到每个结果时,用 /batch。它免去了你管理并发和重试的麻烦。当 agent 需要立即获取一个页面时,用 /read。

任务结果会保留多久?

结果一就绪就尽快收集。结果会等待你获取;一旦交付,就不再保留页面内容的副本,所以请在你自己这边保存所需内容。

整站抓取 (crawl) 会跟随指向其他网站的链接吗?

不会。一次整站抓取 (crawl) 只读取一个域名。其他域名会在你请求时作为链接出现,如果你希望读取这些 URL,可以把它们发给 /batch。

可以停止已经开始的整站抓取 (crawl) 吗?

v1 中不行。任务会在 limit 个页面时停止,所以请选择与预算相符的上限。已读取的页面仍会计费;从未读取的页面不产生费用。

低至 US$0.07/千页 · 无需 KYC

获取 API 密钥