
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 的站点一般有两种形态一种是老版 GitbookURL 形如/chapter/page.html目录在页面里以ul嵌套另一种是新版 Gitbookgitbook.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_URLhttps://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, retriesCONFIG[max_retries]): headers {User-Agent: CONFIG[user_agent]} for attempt in range(retries): try: resp requests.get(url, headersheaders, timeoutCONFIG[timeout]) resp.raise_for_status() resp.encoding resp.apparent_encoding return resp.text except requests.RequestException as e: wait 2 ** attempt print(f[retry {attempt1}] {url} - {e}, wait {wait}s) time.sleep(wait) return Noneresp.apparent_encoding这行很重要Gitbook 有些页面不声明 charset用默认编码会出乱码。让它自动探测能省掉一堆编码问题。第三段是目录遍历。Gitbook 的目录通常在侧边栏的nav或ul classsummary里链接是相对路径。我写一个递归收集函数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, hrefTrue): href a[href].split(#)[0] if not href or href.startswith(javascript): continue full urljoin(base_url, href) toc.append({title: a.get_text(stripTrue), 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_styleATX, code_languageCONFIG[code_lang]) return clean_markdown(text)heading_styleATX保证标题是#形式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, timeoutCONFIG[timeout], streamTrue) 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 Falselen(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 SDKfrom openai import OpenAI client OpenAI( api_keyos.environ[TAOTOKEN_API_KEY], base_urlos.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]}, ], temperature0.3, ) return resp.choices[0].message.content注意chapter_text[:6000]是截断保护避免单次请求超长。实测下来分章节调用比整本调用稳定得多也不会因为一次失败丢掉全部结果。成功的结果是你得到一个结构清晰的book.md图片本地化代码块语言统一章节摘要按目录顺序生成。整个过程在 Trae CN 里完成不需要切换工具。5. 本篇常见错排查这一节对照真实报错遇到问题直接查。401 UnauthorizedKey 没读到或写错了。检查os.environ.get(TAOTOKEN_API_KEY)是否返回 NoneTrae 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三是下载中断加streamTrue和完整性校验。标题重复三次Gitbook 页面里同一标题可能出现在导航、正文、页脚三处。清洗时只取正文容器就能避免如果还有残留在合并阶段用集合去重。代码块语言不对markdownify 的code_language参数只对没有语言标记的代码块生效。如果原 HTML 里code classlanguage-python它会保留 python。要强制统一在清洗后做一次正则替换。CC Switch / Cline MCP / Codex auth.json 配置如果你用这些工具接入三件套必须齐全——Base URL 填https://taotoken.net/apiKey 填控制台创建的 KeyModel ID 填确认可用的模型。缺任何一个都会认证失败。auth.json 里字段名要和工具文档一致不要自己改键名。排障的核心原则先看报错原文再对照文档错误码最后才改代码。大部分问题出在配置层不是逻辑层。6. 把抓取结果接入后续流程抓取和清洗只是前半段真正省时间的是把结果接入统一通道做批量处理。我这次的做法是book.md按章节切分每章调一次模型做摘要和格式规整结果写回一个新的book_summary.md。这样你既保留了原始内容又得到一份精简版。接入时注意三点。第一分章节调用不要整本塞进去上下文长度和费用都更可控。第二加重试和退避网络抖动是常态。第三把模型返回结果做一次格式校验确保 Markdown 结构没被破坏。如果你要长期做这类流水线Coding Plan 比按量调用更划算尤其是需要反复调试 prompt 的阶段。接入文档里有完整的参数说明模型对话页面可以先试跑几个章节确认效果再批量执行。最后说一个实用技巧把爬取配置和模型配置分开成两个文件爬取部分不依赖任何 Key这样你可以先离线把内容抓全、校验通过再接入模型处理。两步分离出问题时定位范围小一半。Trae CN 的工作区支持多文件管理这么拆完全没负担。