1. 从零跑通第一个采集脚本,为什么先要解决 Key 管理
刚学 Python 爬虫的人,卡住的地方往往不是requests.get()写不出来,而是脚本里散落着一堆 API Key、数据库密码、第三方接口凭证。你写第一个采集脚本时可能只连一个数据源,感觉无所谓;但当你开始给采集结果做清洗、翻译、摘要,或者调用大模型接口做结构化抽取时,Key 就会从 1 个变成 5 个、10 个。每个平台一套鉴权方式,有的放 header,有的放 query,有的还要签名,改一次配置要翻五个文档。
这篇笔记面向刚入门 Python 爬虫的读者,目标很具体:用requests+BeautifulSoup写一个能跑的采集脚本,同时把模型调用的 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 URL | https://taotoken.net/api | 代码请求的根地址 |
| API Key | sk-开头的一串字符 | 放在环境变量里,别写死 |
| Model ID | 控制台确认的模型名 | 调用时指定用哪个模型 |
2.2 用环境变量管理 Key,别硬编码
我见过太多新手把 Key 直接写在代码第一行,然后截图发到群里问问题,Key 就这么泄露了。正确做法是用环境变量。Linux 或 macOS 下,你可以在~/.bashrc或~/.zshrc里加一行:
export TAOTOKEN_API_KEY="sk-你的实际Key"Windows 用户可以在系统环境变量里新建一个TAOTOKEN_API_KEY,或者用 PowerShell 临时设置:
$env:TAOTOKEN_API_KEY="sk-你的实际Key"设置完记得新开一个终端窗口,让环境变量生效。然后在 Python 里用os.environ.get("TAOTOKEN_API_KEY")读取。这样代码可以随便分享,Key 始终留在本地。
2.3 安装依赖,一次装齐
这个采集脚本需要三个库:requests负责发 HTTP 请求,beautifulsoup4负责解析 HTML,lxml作为解析器让 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, headers=headers, timeout=REQUEST_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(strip=True) if soup.title else "无标题" paragraphs = [p.get_text(strip=True) 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": f"Bearer {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, headers=headers, json=payload, timeout=30) 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(f"Content-Type:{resp.headers.get('Content-Type')}")正常返回应该是200,Content-Type通常是text/html。如果状态码是 403,多半是 User-Agent 被识别了;如果是 404,检查 URL 有没有写错。内容长度也要看一眼,如果只有几十个字符,可能是被重定向到了验证页。
4.2 验证解析端:标题和段落是否为空
BeautifulSoup 解析完,重点看title和paragraphs是否为空。如果标题是“无标题”,说明页面结构里没有<title>标签,或者你的选择器写错了。段落数为 0 也常见,有些页面正文不在<p>标签里,而在<div>里。这时候你可以打印一下soup.prettify()[:500],看看实际 HTML 长什么样,再调整选择器。
我试过拿一个新闻列表页做练习,正文全在<div class="content">里,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 Unauthorized:Key 没读到或格式不对
报错长这样:
requests.exceptions.HTTPError: 401 Client Error: Unauthorized for url: https://taotoken.net/api/v1/chat/completions原因通常是三个:环境变量没设置、设置后没重启终端、Key 复制时带了空格或换行。排查步骤:先在终端里执行echo $TAOTOKEN_API_KEY(Windows 用echo %TAOTOKEN_API_KEY%),看能不能打印出 Key。如果打印为空,说明环境变量没生效,重新设置并新开终端。如果打印出来但末尾有空格,在代码里加.strip()处理一下。
还有一种情况是 Key 本身失效了,去控制台确认一下这个 Key 是否还在启用状态。
5.2 local proxy failed:网络层被拦截
报错可能长这样:
requests.exceptions.ProxyError: HTTPSConnectionPool(host='taotoken.net', port=443): 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,再用模型做批量摘要,形成一个完整的小流水线。