☰
探索Trae:用Trae CN + Python 爬虫抓取 Gitbook 电子书并落地到 TaoToken
2026/10/1 15:19:21 网站建设 项目流程

1. 为什么要在 Trae CN 里跑 Gitbook 爬虫

Gitbook 是很多技术文档、开源手册、内部知识库的默认载体,它的页面结构高度统一:左侧目录树、右侧正文、章节 URL 规律明显。这意味着它天然适合用脚本批量抓取,而不是一页页手动复制。问题在于,很多同学卡在第一步——本地 Python 环境装依赖、配解释器、调路径,光是把 requests 和 BeautifulSoup 跑起来就耗掉半天。

Trae CN 内置了 Python 运行环境,打开工作区就能直接建 .py 文件、装依赖、点运行,省掉了本地环境那一堆事。我这次的目标很明确:用 Trae CN 写一个爬虫,把某个 Gitbook 电子书的章节 HTML 抓下来,清洗成 Markdown,按目录层级合并成一份可读的电子书,最后把清洗结果通过 TaoToken 的统一 Key 通道接入后续处理流程。

适合谁看:有基础 Python 语法认知、想快速上手爬虫但不想折腾环境的人;已经在用 Trae CN 做日常开发、想把抓取和清洗串成一条流水线的人;以及需要把 Gitbook 内容转成 Markdown 做二次加工(比如喂给模型做摘要、做知识库)的人。

核心检索词先摆出来:Trae CN 内置 Python 环境跑爬虫、Gitbook 章节抓取转 Markdown、requests + BeautifulSoup 目录遍历限速、TaoToken 统一 Key 通道接入。这几个词贯穿全文,你照着做就能复现。

先说清楚整体思路,避免上来就贴代码你看得云里雾里。Gitbook 的站点一般有两种形态:一种是老版 Gitbook,URL 形如/chapter/page.html,目录在页面里以<ul>嵌套;另一种是新版 Gitbook(gitbook.com 托管),内容通过 API 返回 JSON。本文聚焦前者,因为它的 HTML 结构稳定、抓取门槛低,适合作为练手和落地。

流程分四步:第一步,拿到目录树,确定每个章节的 URL 和层级;第二步,逐个请求章节页面,限速、重试、保存原始 HTML;第三步,用 BeautifulSoup 清洗正文,转成 Markdown,处理图片相对路径和代码块语言;第四步,按目录层级合并成单个 md 文件,并做一次完整性校验。最后一步,把合并好的内容通过 TaoToken 的 API 通道送进后续处理(比如让模型做章节摘要或格式规整)。

这里有个坑我提前说:Gitbook 页面里经常混着导航、页脚、"results matching" 这类搜索残留文本,直接get_text()会把它们全带进来。所以清洗阶段必须做白名单式提取,只取正文容器,而不是整页文本。这个细节决定了你最后拿到的 Markdown 干不干净。

2. TaoToken 前置:统一 Key 通道怎么准备

抓取和清洗是本地动作,但后续处理(摘要、格式规整、语义校验)需要调用模型。如果每个环节都单独配一套 Key 和 Base URL,维护成本会很高。TaoToken 的作用是把这些调用收敛到一个统一通道:一个 Key、一个 Base URL,兼容 OpenAI 风格的接口,模型 ID 按需切换。

你需要先拿到 Key。进入控制台创建 API Key,路径是 console 页面,创建后复制保存,注意它只显示一次。然后确认你要用的模型 ID,比如做文本规整可以用通用对话模型,做代码相关处理可以选 coding 类模型。Base URL 统一用https://taotoken.net/api,注意这个地址不带任何查询参数,直接作为 OpenAI SDK 的base_url使用。

如果你用的是 Claude Code 这类工具,配置方式略有不同,需要设置ANTHROPIC_BASE_URL和对应的 Key。但本文的主线是 Python 脚本调用,所以用 OpenAI SDK 的写法最直接。下面这段是环境变量准备,建议写进.env或者直接在 Trae CN 的运行配置里设置:

export TAOTOKEN_API_KEY="你的Key" export TAOTOKEN_BASE_URL="https://taotoken.net/api"

注意不要把 Key 硬编码进脚本再提交到仓库,这是最常见的泄露途径。Trae CN 的运行环境支持读取环境变量,你在脚本里用os.environ.get()取就行。

模型 ID 这块,我建议你先在模型对话页面确认当前可用的模型列表,再填进脚本。不同模型对长文本的处理能力不一样,做电子书章节摘要时,上下文长度是关键参数。如果你要处理的是整本电子书,建议分章节调用,而不是一次性把全文塞进去。

还有一个容易被忽略的点:限速。TaoToken 的接口有速率限制,你在爬虫里如果同时并发调用模型,很容易触发 429。所以我的做法是爬取阶段和模型处理阶段分开,爬取用本地限速(比如每请求间隔 1 秒),模型处理用串行加退避重试。这样两个阶段的压力不会叠加。

Coding Plan 适合长期做这类流水线的场景,如果你只是偶尔跑一次,按量调用即可。接入文档里有完整的参数说明和错误码对照,遇到 401 或 429 先查文档再改代码,比盲目试错快得多。

3. 可复制配置:爬虫脚本与清洗参数

这一节是核心,我把脚本拆成可复制的片段,你按顺序拼起来就能跑。先建一个gitbook_spider.py,然后逐段填。

第一段是依赖和配置。Trae CN 里可以直接在终端pip install requests beautifulsoup4 markdownify,或者用内置的包管理。配置部分用字典集中管理,方便改:

import os import time import json import requests from bs4 import BeautifulSoup from markdownify import markdownify as md from urllib.parse import urljoin, urlparse CONFIG = { "base_url": "https://example-gitbook.com/", "start_path": "index.html", "output_dir": "./output", "assets_dir": "./output/assets", "request_interval": 1.2, "timeout": 15, "max_retries": 3, "user_agent": "Mozilla/5.0 (compatible; GitbookSpider/1.0)", "code_lang": "js", }

request_interval是限速关键,1.2 秒是我实测下来比较稳的值,太快容易被目标站限流,太慢又浪费时间。code_lang设成js是因为我这次抓的文档代码块大多是前端示例,统一语言标记后合并时不会乱。

第二段是请求封装,带重试和退避:

def fetch(url, retries=CONFIG["max_retries"]): headers = {"User-Agent": CONFIG["user_agent"]} for attempt in range(retries): try: resp = requests.get(url, headers=headers, timeout=CONFIG["timeout"]) resp.raise_for_status() resp.encoding = resp.apparent_encoding return resp.text except requests.RequestException as e: wait = 2 ** attempt print(f"[retry {attempt+1}] {url} -> {e}, wait {wait}s") time.sleep(wait) return None

resp.apparent_encoding这行很重要,Gitbook 有些页面不声明 charset,用默认编码会出乱码。让它自动探测能省掉一堆编码问题。

第三段是目录遍历。Gitbook 的目录通常在侧边栏的<nav>或<ul class="summary">里,链接是相对路径。我写一个递归收集函数:

def collect_toc(html, base_url): soup = BeautifulSoup(html, "html.parser") toc = [] nav = soup.find("nav") or soup.find("ul", class_="summary") if not nav: return toc for a in nav.find_all("a", href=True): href = a["href"].split("#")[0] if not href or href.startswith("javascript"): continue full = urljoin(base_url, href) toc.append({"title": a.get_text(strip=True), "url": full}) return toc

去重和层级处理放在后面合并阶段做,这里先把所有链接收全。注意split("#")[0]是为了去掉锚点,同一个页面多个锚点只抓一次。

第四段是正文清洗。这是最容易出问题的地方,我踩过的坑是直接取整页文本,结果导航和页脚全混进来。正确做法是定位正文容器:

def extract_content(html, page_url): soup = BeautifulSoup(html, "html.parser") main = (soup.find("section", class_="normal") or soup.find("div", class_="page-inner") or soup.find("main")) if not main: return None for tag in main.find_all(["script", "style", "nav"]): tag.decompose() for img in main.find_all("img"): src = img.get("src", "") if src: img["src"] = urljoin(page_url, src) text = md(str(main), heading_style="ATX", code_language=CONFIG["code_lang"]) return clean_markdown(text)

heading_style="ATX"保证标题是#形式,code_language统一代码块语言。图片的src转成绝对路径,方便后续下载。

第五段是清洗函数,处理那些搜索残留和多余空行:

def clean_markdown(text): lines = text.splitlines() cleaned = [] for line in lines: s = line.strip() if s.startswith("# results matching") or s.startswith("# No results matching"): continue if s.startswith("[") and s.endswith(")") and "edit" in s.lower(): continue cleaned.append(line) result = "\n".join(cleaned) while "\n\n\n" in result: result = result.replace("\n\n\n", "\n\n") return result.strip()

这段专门干掉 "results matching" 和编辑链接,是我前几版脚本反复出现的问题,现在一次性处理掉。

第六段是图片下载,带完整性校验:

def download_image(url, save_path): try: resp = requests.get(url, timeout=CONFIG["timeout"], stream=True) resp.raise_for_status() content = resp.content if len(content) < 100: return False with open(save_path, "wb") as f: f.write(content) return True except Exception as e: print(f"[img fail] {url} -> {e}") return False

len(content) < 100是防止下载到空文件或错误页,这是图片损坏的常见原因。

把这些拼起来,主流程就是:抓首页 → 收集目录 → 遍历抓取 → 清洗 → 下载图片 → 合并。合并时按目录顺序拼接,标题层级根据目录深度调整,避免出现重复的三级标题。

4. 验证请求:一次完整抓取与结果校验

配置写好后,跑一次完整流程。在 Trae CN 里直接点运行,或者终端python gitbook_spider.py。你会看到类似输出:

[1/42] fetching index.html [2/42] fetching chapter-1/intro.html [3/42] fetching chapter-1/setup.html ... [img] saved assets/webgis.png (24.3 KB) [merge] 42 sections -> output/book.md [done] total 187 KB, 42 images

跑完后先做三项校验。第一项,检查合并后的book.md标题层级是否连续,用 grep 数一下各级标题数量:

grep -c "^# " output/book.md grep -c "^## " output/book.md grep -c "^### " output/book.md

如果二级标题数量异常多(比如等于章节数乘以 3),说明重复标题没去重,回到清洗函数加一层标题去重逻辑。

第二项,检查图片是否都能打开。随机抽几张看文件大小,小于 1KB 的基本是坏的:

find output/assets -type f -size -1k

有输出就说明有损坏图片,重新下载这些 URL 即可。

第三项,检查代码块语言标记是否统一:

grep -c '```js' output/book.md grep -c '```$' output/book.md

第二个命令数的是没有语言标记的代码块,理想情况是 0。如果有,说明code_language参数没生效,检查 markdownify 版本。

校验通过后,把book.md送进 TaoToken 通道做后续处理。下面这段是调用示例,用 OpenAI SDK:

from openai import OpenAI client = OpenAI( api_key=os.environ["TAOTOKEN_API_KEY"], base_url=os.environ["TAOTOKEN_BASE_URL"], ) def summarize(chapter_text): resp = client.chat.completions.create( model="你的模型ID", messages=[ {"role": "system", "content": "你是技术文档编辑,输出简洁的章节摘要。"}, {"role": "user", "content": chapter_text[:6000]}, ], temperature=0.3, ) return resp.choices[0].message.content

注意chapter_text[:6000]是截断保护,避免单次请求超长。实测下来,分章节调用比整本调用稳定得多,也不会因为一次失败丢掉全部结果。

成功的结果是:你得到一个结构清晰的book.md,图片本地化,代码块语言统一,章节摘要按目录顺序生成。整个过程在 Trae CN 里完成,不需要切换工具。

5. 本篇常见错排查

这一节对照真实报错,遇到问题直接查。

401 Unauthorized:Key 没读到或写错了。检查os.environ.get("TAOTOKEN_API_KEY")是否返回 None,Trae CN 的运行配置里环境变量是否真的注入。注意 Base URL 不要带多余路径,https://taotoken.net/api就是完整值。

local proxy failed / connection refused:本地网络或代理配置问题。先确认目标 Gitbook 站点能直接访问,再检查脚本里有没有误设proxies参数。TaoToken 的调用不需要额外代理配置,直接请求即可。

reading choices 报错 / choices 为空:模型返回结构异常,通常是请求体格式不对。检查messages是否是列表、model字段是否填了有效 ID。如果返回体里没有choices,打印完整resp看错误信息。

OAuth / 认证失败:如果你用的是 Claude Code 类工具,检查ANTHROPIC_BASE_URL和 Key 是否配对。本文主线是 Python SDK,不涉及 OAuth 流程,遇到这类报错说明你混用了两套配置。

图片下载后损坏:三种原因。一是 URL 是相对路径没转绝对,检查urljoin是否生效;二是目标站有防盗链,需要在请求头加Referer;三是下载中断,加stream=True和完整性校验。

标题重复三次:Gitbook 页面里同一标题可能出现在导航、正文、页脚三处。清洗时只取正文容器就能避免,如果还有残留,在合并阶段用集合去重。

代码块语言不对:markdownify 的code_language参数只对没有语言标记的代码块生效。如果原 HTML 里<code class="language-python">,它会保留 python。要强制统一,在清洗后做一次正则替换。

CC Switch / Cline MCP / Codex auth.json 配置:如果你用这些工具接入,三件套必须齐全——Base URL 填https://taotoken.net/api,Key 填控制台创建的 Key,Model ID 填确认可用的模型。缺任何一个都会认证失败。auth.json 里字段名要和工具文档一致,不要自己改键名。

排障的核心原则:先看报错原文,再对照文档错误码,最后才改代码。大部分问题出在配置层,不是逻辑层。

6. 把抓取结果接入后续流程

抓取和清洗只是前半段,真正省时间的是把结果接入统一通道做批量处理。我这次的做法是:book.md按章节切分,每章调一次模型做摘要和格式规整,结果写回一个新的book_summary.md。这样你既保留了原始内容,又得到一份精简版。

接入时注意三点。第一,分章节调用,不要整本塞进去,上下文长度和费用都更可控。第二,加重试和退避,网络抖动是常态。第三,把模型返回结果做一次格式校验,确保 Markdown 结构没被破坏。

如果你要长期做这类流水线,Coding Plan 比按量调用更划算,尤其是需要反复调试 prompt 的阶段。接入文档里有完整的参数说明,模型对话页面可以先试跑几个章节确认效果,再批量执行。

最后说一个实用技巧:把爬取配置和模型配置分开成两个文件,爬取部分不依赖任何 Key,这样你可以先离线把内容抓全、校验通过,再接入模型处理。两步分离,出问题时定位范围小一半。Trae CN 的工作区支持多文件管理,这么拆完全没负担。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询