
1. 从零跑通第一个采集脚本为什么先要解决 Key 管理刚学 Python 爬虫的人卡住的地方往往不是requests.get()写不出来而是脚本里散落着一堆 API Key、数据库密码、第三方接口凭证。你写第一个采集脚本时可能只连一个数据源感觉无所谓但当你开始给采集结果做清洗、翻译、摘要或者调用大模型接口做结构化抽取时Key 就会从 1 个变成 5 个、10 个。每个平台一套鉴权方式有的放 header有的放 query有的还要签名改一次配置要翻五个文档。这篇笔记面向刚入门 Python 爬虫的读者目标很具体用requestsBeautifulSoup写一个能跑的采集脚本同时把模型调用的 Key 统一到 TaoToken 上让采集链路里的“取数”和“处理”两段用同一套凭证体系。TaoToken 是一个模型 API 聚合平台你可以把它理解成一个统一的 Key 入口——原本你要分别去不同厂商注册、拿 Key、记不同的 Base URL现在用同一个 Key 和同一个 Base URL 就能调用多种模型。对爬虫学习场景来说它的价值在于你采集完网页内容后想顺手做摘要、分类、字段抽取不用再单独折腾一套鉴权。适合谁看写过一点 Python、知道列表和字典、装过 pip 包但还没完整跑通过一个“采集→处理→输出”闭环的人。我会给出完整可复制的代码、TaoToken 的配置片段以及运行后打印采集结果的验证动作。你跟着敲一遍能确认三件事环境依赖装对了、网页请求链路通了、统一 Key 的调用方式理解了。先说清楚边界爬虫要遵守目标站点的 robots.txt 和使用条款控制请求频率别给人家服务器添麻烦。本文示例用公开的练习页面只做学习用途。另外涉及模型调用的部分Key 一定要放在环境变量或独立配置文件里别硬编码进.py文件然后传到公开仓库——这是新手最容易踩的坑我后面会专门讲怎么避免。整篇的节奏是先讲清楚问题和场景再配 TaoToken 的前置准备然后给可复制的配置和代码接着验证请求结果再排查常见报错最后给一个继续深入的方向。你可以按顺序读也可以直接跳到代码段复制运行。2. TaoToken 前置准备统一 Key 与 Base URL 怎么配在写采集脚本之前先把 TaoToken 这边的准备工作做完。这一步不复杂但顺序别搞反先拿 Key再确认 Base URL最后把模型 ID 记下来。这三样东西后面写配置片段时都要用到。2.1 获取 API Key 与确认接口地址打开 TaoToken 官网注册登录后进入控制台找到 API Keys 页面创建一个新的 Key。创建时给它起个能认出来的名字比如spider-learn方便以后区分不同用途。Key 一般以sk-开头复制出来先存到密码管理器或者临时文本里页面刷新后可能就不再完整显示了。接口地址这块要记牢TaoToken 的 API 根地址是https://taotoken.net/api。注意这里不带任何查询参数就是干净的根路径。很多新手会把官网地址和 API 地址搞混官网是给人看的页面API 地址是给代码请求的端点两者不能互换。你在代码里配置base_url时填的是 API 地址。模型 ID 需要你在控制台或文档里确认当前可用的模型名称。不同模型 ID 对应不同的能力和计费学习阶段选一个通用的对话模型就够了。把这三个信息整理成一张小卡片配置项值说明Base URLhttps://taotoken.net/api代码请求的根地址API Keysk-开头的一串字符放在环境变量里别写死Model ID控制台确认的模型名调用时指定用哪个模型2.2 用环境变量管理 Key别硬编码我见过太多新手把 Key 直接写在代码第一行然后截图发到群里问问题Key 就这么泄露了。正确做法是用环境变量。Linux 或 macOS 下你可以在~/.bashrc或~/.zshrc里加一行export TAOTOKEN_API_KEYsk-你的实际KeyWindows 用户可以在系统环境变量里新建一个TAOTOKEN_API_KEY或者用 PowerShell 临时设置$env:TAOTOKEN_API_KEYsk-你的实际Key设置完记得新开一个终端窗口让环境变量生效。然后在 Python 里用os.environ.get(TAOTOKEN_API_KEY)读取。这样代码可以随便分享Key 始终留在本地。2.3 安装依赖一次装齐这个采集脚本需要三个库requests负责发 HTTP 请求beautifulsoup4负责解析 HTMLlxml作为解析器让 BeautifulSoup 跑得更快更稳。一条命令装完pip install requests beautifulsoup4 lxml如果你用的是虚拟环境推荐先创建再安装python -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate pip install requests beautifulsoup4 lxml装完后可以用pip list确认这三个包都在列表里。版本不用太纠结近两年的版本都兼容。到这里前置准备就完成了接下来进入代码环节。3. 可复制配置requests BeautifulSoup 采集脚本完整代码这一节是全文的核心我会把配置片段和采集脚本拆开讲你可以直接复制运行。脚本分两部分一部分是 TaoToken 的调用配置另一部分是网页采集逻辑。两者通过一个函数衔接起来形成“采集→处理”的闭环。3.1 TaoToken 调用配置片段先建一个config.py把模型调用的配置集中管理。这样以后换模型、换地址只改一个文件# config.py import os TAOTOKEN_BASE_URL https://taotoken.net/api TAOTOKEN_API_KEY os.environ.get(TAOTOKEN_API_KEY, ) TAOTOKEN_MODEL 你的模型ID # 从控制台确认后填入 # 采集相关配置 TARGET_URL https://example.com # 换成你要练习的公开页面 REQUEST_TIMEOUT 10 USER_AGENT ( Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 )如果你更习惯用 JSON 管理配置也可以写成config.json{ base_url: https://taotoken.net/api, model: 你的模型ID, target_url: https://example.com, timeout: 10 }然后在代码里用json.load()读进来。两种方式都行选你顺手的。关键是 Key 不要出现在这些文件里只从环境变量取。3.2 采集脚本主体代码新建spider.py完整代码如下# spider.py import os import json import time import requests from bs4 import BeautifulSoup from config import ( TAOTOKEN_BASE_URL, TAOTOKEN_API_KEY, TAOTOKEN_MODEL, TARGET_URL, REQUEST_TIMEOUT, USER_AGENT, ) def fetch_page(url): 请求网页并返回 HTML 文本 headers {User-Agent: USER_AGENT} resp requests.get(url, headersheaders, timeoutREQUEST_TIMEOUT) resp.raise_for_status() resp.encoding resp.apparent_encoding return resp.text def parse_page(html): 用 BeautifulSoup 提取标题和正文段落 soup BeautifulSoup(html, lxml) title soup.title.get_text(stripTrue) if soup.title else 无标题 paragraphs [p.get_text(stripTrue) for p in soup.find_all(p)] paragraphs [p for p in paragraphs if p] # 去掉空段落 return {title: title, paragraphs: paragraphs} def summarize_with_taotoken(text): 调用 TaoToken 统一接口做摘要 if not TAOTOKEN_API_KEY: return 未检测到 TAOTOKEN_API_KEY跳过模型调用 url f{TAOTOKEN_BASE_URL}/v1/chat/completions headers { Authorization: fBearer {TAOTOKEN_API_KEY}, Content-Type: application/json, } payload { model: TAOTOKEN_MODEL, messages: [ {role: system, content: 你是一个文本摘要助手用一句话概括内容。}, {role: user, content: text[:2000]}, ], temperature: 0.3, } resp requests.post(url, headersheaders, jsonpayload, timeout30) resp.raise_for_status() data resp.json() return data[choices][0][message][content] def main(): print(f开始采集{TARGET_URL}) html fetch_page(TARGET_URL) print(f页面长度{len(html)} 字符) parsed parse_page(html) print(f标题{parsed[title]}) print(f段落数{len(parsed[paragraphs])}) # 打印前 3 段作为采集结果验证 for i, p in enumerate(parsed[paragraphs][:3], 1): print(f 段落{i}: {p[:80]}...) # 用统一 Key 做一次摘要 joined \n.join(parsed[paragraphs][:10]) if joined: summary summarize_with_taotoken(joined) print(f摘要{summary}) else: print(没有提取到正文跳过摘要) time.sleep(1) # 控制频率做个有礼貌的爬虫 if __name__ __main__: main()这段代码有几个设计点值得说明。fetch_page里设置了User-Agent避免被服务器当成脚本直接拒绝resp.apparent_encoding让 requests 自动推断编码减少中文乱码。parse_page用lxml解析器比默认的html.parser快不少。summarize_with_taotoken里先判断 Key 是否存在没有就跳过这样即使你还没配 Key采集部分也能独立跑通。3.3 运行与观察输出在终端里执行python spider.py如果一切正常你会看到类似这样的输出开始采集https://example.com 页面长度1256 字符 标题Example Domain 段落数2 段落1: This domain is for use in illustrative examples... 段落2: ... 摘要这是一个用于示例说明的保留域名页面。看到“页面长度”“标题”“段落数”这三行说明采集链路通了看到“摘要”那一行说明 TaoToken 的统一 Key 调用也通了。如果摘要那行显示“未检测到 TAOTOKEN_API_KEY”先回去检查环境变量有没有生效。4. 验证请求与成功结果确认调用链路打通代码跑起来只是第一步你得知道怎么判断“真的通了”而不是碰巧没报错。这一节讲三个验证动作从采集端到模型端逐层确认。4.1 验证采集端状态码与内容长度最直接的验证是看 HTTP 状态码。在fetch_page里我用了resp.raise_for_status()如果状态码是 4xx 或 5xx 会直接抛异常。你可以在请求后加一行打印print(f状态码{resp.status_code}) print(fContent-Type{resp.headers.get(Content-Type)})正常返回应该是200Content-Type通常是text/html。如果状态码是 403多半是 User-Agent 被识别了如果是 404检查 URL 有没有写错。内容长度也要看一眼如果只有几十个字符可能是被重定向到了验证页。4.2 验证解析端标题和段落是否为空BeautifulSoup 解析完重点看title和paragraphs是否为空。如果标题是“无标题”说明页面结构里没有title标签或者你的选择器写错了。段落数为 0 也常见有些页面正文不在p标签里而在div里。这时候你可以打印一下soup.prettify()[:500]看看实际 HTML 长什么样再调整选择器。我试过拿一个新闻列表页做练习正文全在div classcontent里find_all(p)一个都抓不到。后来改成soup.select(div.content p)就正常了。所以解析结果为空时先别怀疑代码去看看页面结构。4.3 验证模型端响应结构与 choices 字段TaoToken 的接口返回是标准的 OpenAI 兼容格式成功时结构大致是{ choices: [ { message: { role: assistant, content: 这里是摘要内容 } } ] }所以代码里用data[choices][0][message][content]取值。如果你打印整个data发现没有choices字段而是有个error字段那就是调用出问题了去看第 5 节的排查。验证模型端最省事的办法是先打印resp.status_code和resp.text[:200]一眼就能看出是鉴权问题还是参数问题。三个验证动作做完你对整条链路的信心就建立起来了采集端有内容、解析端有结构、模型端有回复。这时候再去改目标 URL、换模型、加字段抽取心里就有底了。5. 本篇常见报错排查401、local proxy failed 与 choices 缺失新手跑这个脚本报错基本集中在几个地方。我把最常见的几类列出来对照着排查能省不少时间。5.1 401 UnauthorizedKey 没读到或格式不对报错长这样requests.exceptions.HTTPError: 401 Client Error: Unauthorized for url: https://taotoken.net/api/v1/chat/completions原因通常是三个环境变量没设置、设置后没重启终端、Key 复制时带了空格或换行。排查步骤先在终端里执行echo $TAOTOKEN_API_KEYWindows 用echo %TAOTOKEN_API_KEY%看能不能打印出 Key。如果打印为空说明环境变量没生效重新设置并新开终端。如果打印出来但末尾有空格在代码里加.strip()处理一下。还有一种情况是 Key 本身失效了去控制台确认一下这个 Key 是否还在启用状态。5.2 local proxy failed网络层被拦截报错可能长这样requests.exceptions.ProxyError: HTTPSConnectionPool(hosttaotoken.net, port443): Max retries exceeded ... local proxy failed这个报错说明你的请求被本地网络配置拦截了。检查一下终端里有没有设置HTTP_PROXY或HTTPS_PROXY环境变量有的话先清掉unset HTTP_PROXY unset HTTPS_PROXY如果你在用某些网络工具先关掉再试。正常情况下直接访问https://taotoken.net/api应该是通的。可以在终端里用curl -I https://taotoken.net/api测一下连通性返回 200 或 401 都说明网络层没问题。5.3 reading choices响应结构不是预期格式报错长这样KeyError: choices或者TypeError: NoneType object is not subscriptable这说明resp.json()返回的结构里没有choices。最可能的原因是接口返回了错误信息比如{error: {message: model not found, type: invalid_request_error}}排查方法在取值前先打印resp.status_code和resp.text看清楚服务端到底返回了什么。如果是model not found说明TAOTOKEN_MODEL填的模型 ID 不对去控制台核对。如果是invalid api key回到 5.1 检查 Key。养成“先看原始响应再取值”的习惯能避免很多猜测。5.4 其他零碎问题中文乱码的话确认resp.encoding resp.apparent_encoding这行在resp.text之前执行。解析不到内容的话用soup.prettify()看实际结构。请求超时的话把REQUEST_TIMEOUT调大一点或者检查目标站点是否可达。采集频率太高被限流的话在循环里加time.sleep(1)做个有礼貌的爬虫。6. 继续深入把统一 Key 用在更多采集场景跑通第一个脚本之后你可以沿着几个方向继续练。一个是采集端把单页采集扩展成多页循环加上分页参数把结果存成 CSV 或 JSON。另一个是处理端用 TaoToken 的统一 Key 做字段抽取比如从采集到的商品描述里提取价格、规格或者把非结构化文本转成 JSON。这两端用同一套配置改起来很省心。如果你打算长期写采集和数据处理脚本可以了解一下 Coding Plan它适合需要持续调用模型能力的场景。想先试试模型对话效果可以直接在模型对话页面体验。接入文档里有更详细的参数说明API Keys 页面管理你的凭证。采集脚本写多了你会发现真正花时间的不是写requests.get()而是处理各种边界情况编码、反爬、结构变化、频率控制。把 Key 管理这件事用统一入口解决掉你就能把精力放在这些更有意思的问题上。下一步可以试试把采集结果存进 SQLite再用模型做批量摘要形成一个完整的小流水线。