1. OpenClaw 数据采集自动化到底解决什么问题OpenClaw 数据采集自动化本质是把「打开网页、复制字段、粘贴到表格」这套动作交给一个能理解自然语言的 AI 助手去编排再由 Python 脚本负责真正落地执行。它适合三类人需要每天盯竞品价格的运营、要批量清洗公开数据的分析师、以及想把采集链路塞进自己 Agent 工作流的 Python 开发者。你不需要先成为爬虫高手只要会写函数、会配 JSON就能把一条采集链路跑起来。我先把整条链路拆开讲清楚不然后面改 endpoint 会一头雾水。一条完整的 OpenClaw 采集链路通常有四层第一层是触发层。可以是你在 OpenClaw 对话框里敲一句「采集今天的榜单」也可以是 APScheduler 定时触发甚至是一个 webhook。触发层只负责「什么时候开始」不关心怎么采。第二层是编排层也就是 AI 助手所在的位置。它接收你的自然语言指令翻译成结构化的采集任务目标 URL、字段选择器、翻页规则、去重键、导出格式。这一层是 OpenClaw 的价值所在——你不用为每个新站点重写一遍调度逻辑改几句描述就行。第三层是执行层纯 Python。requests 发请求、BeautifulSoup 或 parsel 解析、pandas 清洗、openpyxl 导出。这一层要稳定、要能重试、要能限速跟 AI 没关系是硬功夫。第四层是模型层。编排层要理解你的指令、要判断字段映射、要在解析失败时给出修复建议这些都得调用大模型。默认情况下很多教程会让你去连某个海外端点但国内网络环境下经常超时或者握手失败。这就是为什么我们要把 endpoint 改到 TaoToken——它提供兼容 OpenAI 协议的接口Base URL 换成https://taotoken.net/api之后你的 AI 助手调用就走通了。为什么强调「改 endpoint」而不是「换个库」因为 OpenClaw 的编排层和你的 Python 执行层是解耦的。执行层根本不关心模型从哪来它只关心编排层吐出来的任务 JSON 对不对。所以你只要把模型调用的 Base URL 和 Key 换掉整条链路其他部分一行不用动。这是最省事的迁移方式也是我这篇要重点带你跑通的部分。还有一个容易被忽略的点采集自动化的难点从来不是「抓一次」而是「每天都抓、抓失败能自愈、字段变了能报警」。所以下面我会把重试、限速、字段校验都写进可复制的配置里而不是只给你一个能跑一次的 demo。你照着配完得到的是一条能长期挂着的链路而不是一次性的玩具脚本。2. 把 AI 助手 endpoint 改到 TaoToken 的前置准备在动 Python 之前先把模型这一侧的地基打好。很多人卡在第一步不是因为代码错而是 Key 没拿对、Base URL 写错、或者模型 ID 填了个不存在的名字。这一节把三件套——Base URL、API Key、Model ID——一次讲透。先说 Base URL。TaoToken 的 API 地址是https://taotoken.net/api注意这里不要加任何多余的路径后缀也不要带 UTM 参数。很多兼容 OpenAI 协议的客户端会自动在末尾拼/v1/chat/completions所以你填的 Base URL 就到/api为止。如果你用的是 OpenAI 官方 SDK通常写法是from openai import OpenAI client OpenAI( base_urlhttps://taotoken.net/api, api_key你的_TaoToken_Key )这里有个坑我踩过有人把 base_url 写成https://taotoken.net/api/v1结果 SDK 又拼了一次/v1变成/api/v1/v1/chat/completions直接 404。记住SDK 自己会补版本号你只填到/api。再说 API Key。你需要登录 TaoToken 控制台在 API Keys 页面创建一个新 Key。创建时建议按用途命名比如openclaw-harvester这样以后要轮换或者吊销时不会误伤别的项目。Key 只在创建时完整显示一次复制下来存到环境变量里别硬编码进脚本。推荐做法export TAOTOKEN_API_KEYsk-你的key然后在 Python 里用os.environ[TAOTOKEN_API_KEY]读取。这样你把脚本传到 Git 仓库时不会泄露密钥。第三件是 Model ID。这个必须填对因为不同模型对指令遵循、JSON 输出稳定性的表现不一样。采集编排这种任务需要模型能稳定输出结构化 JSON所以选一个指令遵循强的模型。具体有哪些可选、当前叫什么名字去模型对话页面或者文档里看最新列表别照抄别人半年前的文章。填错 Model ID 的典型报错是model_not_found或者 400遇到就回去核对。如果你用的是 Claude Code 这类工具配置方式略有不同它读的是 settings 文件。但核心三件套不变Base URL 指向https://taotoken.net/apiKey 用你创建的Model ID 填对。下面第三节我会给出可直接复制的 JSON 和 TOML 片段。最后提醒一句Key 的权限和额度在控制台里可以单独设置采集任务如果量大建议单独建一个 Key 并设好额度上限避免某个脚本跑飞了把额度烧光。这是运维习惯不是技术难点但能省你很多事。3. 可复制的采集脚本与 AI 助手配置这一节是全文的核心我给你三份可直接复制的配置一份是 OpenClaw 侧的模型接入配置一份是 Python 采集脚本一份是任务描述模板。三份拼起来就是完整链路。先看模型接入配置。如果你用的是支持 OpenAI 兼容协议的客户端配置文件通常长这样JSON 格式路径按你实际工具的约定放{ provider: openai-compatible, base_url: https://taotoken.net/api, api_key_env: TAOTOKEN_API_KEY, model: 你的模型ID, timeout: 60, max_retries: 3 }注意api_key_env这种写法是让程序从环境变量读 Key比直接写api_key安全。如果你的工具不支持环境变量引用那就退而求其次写明文但一定别提交到公开仓库。如果你用的是 Claude Code 这类读 TOML 或 settings 的工具配置片段类似[model] provider openai-compatible base_url https://taotoken.net/api api_key sk-你的key model 你的模型ID同样Base URL 到/api为止。三件套齐了Base URL、Key、Model ID缺一不可。接下来是 Python 采集脚本。这份脚本的设计目标是接收一个任务 JSON执行采集做清洗和去重导出结果失败自动重试。我把它写成可复用的模块import os import time import json import requests from bs4 import BeautifulSoup from openai import OpenAI client OpenAI( base_urlhttps://taotoken.net/api, api_keyos.environ[TAOTOKEN_API_KEY] ) def build_task(natural_language: str) - dict: 让 AI 助手把自然语言翻译成结构化采集任务 resp client.chat.completions.create( model你的模型ID, messages[ {role: system, content: 你是数据采集编排助手只输出 JSON不要解释。}, {role: user, content: natural_language} ], temperature0 ) content resp.choices[0].message.content return json.loads(content) def fetch_with_retry(url: str, retries: int 3, delay: float 2.0) - str: headers {User-Agent: Mozilla/5.0 (OpenClaw Harvester)} for i in range(retries): try: r requests.get(url, headersheaders, timeout15) r.raise_for_status() return r.text except requests.RequestException as e: if i retries - 1: raise time.sleep(delay * (i 1)) def parse(html: str, rules: dict) - dict: soup BeautifulSoup(html, html.parser) data {} for field, selector in rules.items(): data[field] [el.get_text(stripTrue) for el in soup.select(selector)] return data def run(task: dict) - list: results [] for item in task[sources]: html fetch_with_retry(item[url]) row parse(html, item[extract_rules]) results.append(row) time.sleep(task.get(interval, 1.0)) return results if __name__ __main__: task build_task(采集 https://example.com/list 的标题和价格标题选择器 .title价格选择器 .price) data run(task) with open(output.json, w, encodingutf-8) as f: json.dump(data, f, ensure_asciiFalse, indent2) print(采集完成共, len(data), 条)这份脚本里build_task负责调模型fetch_with_retry负责网络重试parse负责解析run负责串起来。你可以把build_task的输入换成任何自然语言描述模型会吐出对应的任务 JSON。任务描述模板我建议固定成这个结构模型输出会更稳{ sources: [ { url: https://example.com/list, extract_rules: { title: .title, price: .price } } ], interval: 1.5, dedup_key: title, export: {format: json, path: output.json} }把这三份拼起来你就有了「自然语言 → 任务 JSON → 采集执行 → 导出」的完整闭环。下一节我们验证它真的能跑通。4. 验证请求与成功结果配置写完不验证等于没写。这一节带你从最小请求开始一步步确认链路是通的而不是等到跑完整脚本才发现模型根本没连上。第一步先单独验证模型连通性。写一个最小脚本只调一次模型看能不能拿到回复import os from openai import OpenAI client OpenAI( base_urlhttps://taotoken.net/api, api_keyos.environ[TAOTOKEN_API_KEY] ) resp client.chat.completions.create( model你的模型ID, messages[{role: user, content: 只回复两个字通了}] ) print(resp.choices[0].message.content)如果这一步打印出「通了」说明 Base URL、Key、Model ID 三件套都对。如果报 401是 Key 问题报 404多半是 Base URL 多写了/v1报 model_not_found是 Model ID 填错。这三种错误下一节会详细拆。第二步验证模型能稳定输出 JSON。把build_task单独跑一次打印返回的 dicttask build_task(采集 https://example.com/list 的标题选择器 .title) print(json.dumps(task, ensure_asciiFalse, indent2))成功的话你会看到一个带sources数组的 JSON。如果模型返回了带 json 包裹的文本json.loads会失败这时候要么在 system prompt 里强调「不要 markdown 代码块」要么加一层清洗把反引号剥掉。我一般直接在 prompt 里写死「只输出 JSON不要任何代码块标记」稳定性最好。第三步验证采集执行。拿一个真实可访问的页面跑run(task)看output.json里有没有数据。成功结果长这样[ { title: [示例标题一, 示例标题二], price: [19.9, 29.9] } ]如果title是空数组说明选择器没匹配到元素回去检查页面结构或者让模型重新生成选择器。如果请求直接抛异常看是不是目标站点需要特定 header 或者有反爬。第四步验证重试逻辑。你可以故意把 URL 改成一个不存在的域名观察脚本是不是重试了三次才抛错。这一步是确认你的链路在真实网络抖动下不会一崩到底。四步都过了你的采集链路就算跑通了。整个过程里模型只负责「翻译指令」真正干活的是 Python所以模型偶尔抽风不会让整条链路瘫痪——这也是把编排层和执行层分开的好处。5. 本篇常见报错排查这一节按真实报错来你遇到哪个直接对号入座。401 Unauthorized。最常见的原因是 Key 没读到。检查os.environ[TAOTOKEN_API_KEY]是不是空的环境变量是不是在启动脚本的同一个 shell 里 export 的。还有一种情况是 Key 被吊销或者额度用尽去控制台确认 Key 状态。注意 401 和 403 不同401 是身份没通过403 是身份通过了但没权限别混。local proxy failed / connection error。这类报错通常出现在你本地有网络代理设置但代理没生效或者配置冲突。检查你的环境变量里有没有HTTP_PROXY、HTTPS_PROXY残留有的话清掉再试。另外确认 Base URL 拼写完全正确https://taotoken.net/api一个字母都不能错。reading choices 报错比如NoneType object has no attribute choices或list index out of range。这说明模型返回体结构和你预期的不一样。常见原因是 Model ID 填错服务端返回了一个错误对象而不是正常的 completion。打印完整的resp看看结构确认resp.choices存在。如果返回体里是error字段读它的 message通常写得很清楚。OAuth 相关报错。如果你用的是 Claude Code 这类带 OAuth 流程的工具报 OAuth 失败通常是配置文件里的认证方式没切到 API Key 模式。检查 settings 里是不是还留着旧的 OAuth token 字段把它删掉改成api_key直填。三件套里 Key 这一项必须是 API Key不是 OAuth token。JSON 解析失败json.decoder.JSONDecodeError。模型返回了带 markdown 代码块的文本。解决办法是在 system prompt 里明确禁止代码块或者在json.loads之前做一次清洗content content.strip().removeprefix(json).removeprefix().removesuffix().strip()采集结果为空。不是报错但很常见。先确认页面能正常访问再确认选择器。可以用soup.select(.title)单独打印一下看返回的列表长度。如果页面是 JS 渲染的requests 拿到的 HTML 里根本没有数据这时候要么换接口要么上无头浏览器别在静态解析上死磕。超时 timeout。把timeout调大或者在fetch_with_retry里加指数退避。采集任务对延迟不敏感宁可慢一点也别频繁失败。排查的核心思路是先确认模型侧通不通最小请求再确认执行侧通不通单页采集最后确认编排侧对不对任务 JSON 结构。分层定位比盯着一个报错瞎改快得多。6. 把采集链路长期跑起来的几个实用建议链路跑通只是开始能长期稳定跑才是目的。这里给你几个我实际用下来有效的做法。第一把任务配置和代码分离。任务 JSON 存成独立文件代码只负责读文件执行。这样你加一个新站点只需要改 JSON不用动 Python。配合 OpenClaw 的自然语言编排你甚至可以让模型直接生成新的任务 JSON 存盘。第二给每个采集源单独设限速。time.sleep是最简单的但更稳的是用令牌桶。对同一个域名间隔别低于 1 秒量大就排队。这不是技术问题是基本的礼貌也能降低被封的概率。第三导出格式按下游需求定。要进数据库就导 JSON要给人看就导 Excel要做报表就导 CSV。别所有场景都导一种格式再二次转换多一道转换多一个出错点。第四定期检查字段是否失效。页面改版是采集任务的常态你可以加一个校验如果某个字段连续三次采集为空就发个提醒。这个提醒可以走 OpenClaw 的消息通道也可以简单写个日志。第五Key 和额度分开管理。采集任务单独用一个 Key设好额度上限。这样即使某个脚本出问题也不会影响你其他项目的调用。如果你想把这条链路进一步产品化比如做成团队共用的采集服务可以看看 Coding Plan 这类长期方案把模型调用和任务编排都托管起来省去自己维护调度器的麻烦。模型对话页面可以用来快速试 prompt接入文档里有完整的参数说明API Keys 页面管理你的密钥。这几个入口配合起来从试跑到上线是一条顺的路径。最后说个心态问题采集自动化不是一次写完就完事它更像养一盆植物需要偶尔浇水更新选择器、修剪清理无效任务、换盆迁移 endpoint。把 endpoint 改到 TaoToken 只是换了个更顺手的盆真正让植物活得好的是你持续维护的习惯。