Python Show-Me-the-Code 第 0008 题:用 TaoToken 统一 Key 提取 HTML 正文内容

发布时间:2026/9/29 13:59:54

Python Show-Me-the-Code 第 0008 题:用 TaoToken 统一 Key 提取 HTML 正文内容 1. 从一道老题说起HTML 正文提取到底难在哪如果你刷过 Python 的 Show-Me-the-Code 系列第 0008 题大概率让你卡过壳给一个 HTML 文件把里面的正文抠出来。题目描述只有一句话但真动手写才发现网页里塞满了导航栏、侧边栏、评论区、广告位、页脚版权正文往往只占整个 DOM 的百分之十几。用正则去匹配p标签遇到嵌套结构直接崩。用 BeautifulSoup 一把梭soup.get_text()结果把菜单和推荐阅读全带出来了读起来像一锅乱炖。这道题的核心检索词就是Python HTML 正文内容提取它要解决的问题是从一堆标签和噪声里稳定地还原出人眼看到的那段文章。适合谁写爬虫做数据清洗的、做 RAG 需要把网页转成干净文本喂给模型的、以及想批量归档博客文章的人。我试过纯手写规则维护成本高得离谱换个站点就得重调后来转向「解析库 正文算法 模型兜底」的组合才把链路跑顺。这篇文章不讲空理论直接给你一条能复制的完整链路requests 抓页面、BeautifulSoup 做初步清洗、正文提取算法去噪、最后把模型调用 endpoint 统一改到 TaoToken 管理 Key用一组样例页面验证输出是否干净可读。每一步都有代码和参数你可以边看边跑。先说清楚一个认知正文提取没有银弹。不同站点结构差异巨大纯算法方案在新闻站表现好在论坛或文档站可能翻车。所以我的策略是「算法打底 模型补刀」——先用轻量算法拿到 80% 的干净文本剩下结构诡异的页面再交给模型做二次抽取。而模型调用这块如果每个项目都散落着不同的 Key管理起来就是灾难这也是我把 endpoint 统一到 TaoToken 的原因。2. 前置准备requests BeautifulSoup 环境与 TaoToken Key 统一管理动手之前先把环境搭好。正文提取这条链路依赖两个库requests负责发请求拿 HTMLbeautifulsoup4负责解析 DOM再配一个lxml解析器提速。安装命令很直接pip install requests beautifulsoup4 lxml如果你还想用现成的正文提取库做对照可以顺手装trafilatura它在多语言新闻正文上表现稳定后面我会拿它和手写方案对比。安装pip install trafilatura环境好了接下来是 Key 管理。为什么要在正文提取里提模型调用因为纯算法搞不定的页面你需要一个模型来做「这段文本是不是正文」的判断或直接抽取。问题在于如果你同时用 OpenAI、Claude、国产模型Key 散落在各个脚本和环境变量里换台机器就得重新配一遍团队协作更是互相覆盖。我的做法是把所有模型调用统一走一个 endpointKey 只维护一份。TaoToken 在这里扮演的就是统一入口的角色。它的 API 地址是https://taotoken.net/api兼容 OpenAI 的接口格式意味着你原来用openaiSDK 写的代码只需要改base_url和api_key两个参数其余逻辑不动。先去控制台创建一个 Key控制台入口https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewriteAPI Keys 管理https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite创建完 Key 之后把它写进环境变量别硬编码在脚本里export TAOTOKEN_API_KEYsk-你的key export TAOTOKEN_BASE_URLhttps://taotoken.net/api这样你的正文提取脚本里模型调用部分就只认这两个变量。后面无论换模型还是加新模型都只改配置不改代码。对于正文提取这种需要反复调试 prompt 的场景统一 Key 能省掉大量「这个 Key 是哪个账号的」的排查时间。注意Key 属于敏感凭证不要提交到 Git 仓库。建议用.env文件配合python-dotenv加载或者直接用系统环境变量。3. 可复制配置requests 抓取 BeautifulSoup 清洗 模型 endpoint 片段这一节给你可以直接抄的配置。先看抓取和清洗部分。核心思路是requests 拿到 HTML 后先用 BeautifulSoup 干掉 script、style、nav、footer 这些明显不是正文的标签再提取候选文本块。import os import requests from bs4 import BeautifulSoup HEADERS { User-Agent: ( Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0 Safari/537.36 ) } NOISE_TAGS [script, style, nav, footer, header, aside, form, iframe, noscript] def fetch_html(url: str, timeout: int 15) - str: resp requests.get(url, headersHEADERS, timeouttimeout) resp.raise_for_status() resp.encoding resp.apparent_encoding return resp.text def clean_soup(html: str) - BeautifulSoup: soup BeautifulSoup(html, lxml) for tag in soup(NOISE_TAGS): tag.decompose() return soup上面这段是基础。真正决定正文质量的是「候选块打分」。我用的简化版逻辑是遍历所有p和div按文本长度和标点密度打分取分数最高的容器作为正文根节点。完整函数import re def score_block(text: str) - float: if not text: return 0.0 length len(text) punct len(re.findall(r[。,.!?;:], text)) link_density text.count(http) / max(length, 1) return length * 0.5 punct * 2 - link_density * 100 def extract_main_text(soup: BeautifulSoup) - str: candidates soup.find_all([p, div, article, section]) best, best_score None, 0.0 for node in candidates: text node.get_text(stripTrue) s score_block(text) if s best_score: best, best_score node, s if best is None: return soup.get_text(\n, stripTrue) return best.get_text(\n, stripTrue)接下来是模型 endpoint 配置。当算法提取结果不理想时把候选文本丢给模型做二次判断。这里用 OpenAI 兼容格式base_url指向 TaoTokenfrom openai import OpenAI client OpenAI( api_keyos.environ[TAOTOKEN_API_KEY], base_urlos.environ.get(TAOTOKEN_BASE_URL, https://taotoken.net/api), ) MODEL_ID gpt-4o-mini # 按需替换为控制台可用的模型 ID def refine_with_model(raw_text: str) - str: prompt ( 下面是从网页提取的候选文本请只保留文章正文 去掉导航、广告、评论、版权等噪声直接输出正文\n\n raw_text[:6000] ) resp client.chat.completions.create( modelMODEL_ID, messages[{role: user, content: prompt}], temperature0, ) return resp.choices[0].message.content.strip()如果你更习惯用配置文件管理可以写一个settings.toml[taotoken] base_url https://taotoken.net/api api_key_env TAOTOKEN_API_KEY model_id gpt-4o-mini三件套齐了Base URL 是https://taotoken.net/apiKey 从环境变量读Model ID 按控制台可用列表填。这样无论你后面接 Claude Code 还是别的工具配置结构都一致。4. 验证请求跑一组样例页面看正文是否干净可读配置写完必须验证。我准备了三个不同类型的页面一篇技术博客、一个新闻页、一个文档页。跑下面这段主流程def pipeline(url: str, use_model: bool False) - str: html fetch_html(url) soup clean_soup(html) text extract_main_text(soup) if use_model: text refine_with_model(text) return text if __name__ __main__: url https://example.com/blog/some-post result pipeline(url, use_modelFalse) print(result[:800])实测下来技术博客类页面用纯算法就能拿到比较干净的结果正文段落完整导航和页脚被decompose掉了。新闻页因为正文集中在article里打分逻辑能准确命中。文档页稍微麻烦因为侧边栏目录和正文都是长文本链接密度特征帮了忙——目录里链接多得分被压低正文胜出。如果你想看模型二次抽取的效果把use_modelTrue打开对比两次输出。模型版的好处是能处理「正文里混了推荐阅读」这种算法难判断的情况代价是多一次网络请求和 token 消耗。我的建议是批量任务先用算法跑一遍把明显异常的页面文本过短或过长挑出来只对这些页面调模型成本可控。验证时重点看三个指标正文首段是否完整、有没有混入「相关阅读」「版权声明」、段落之间是否保留了换行。如果换行丢了检查get_text的分隔符参数用\n而不是默认空串。5. 常见报错排查401、local proxy failed、reading choices 与 OAuth链路跑起来后报错基本集中在这几类我按真实遇到的顺序列一下。401 Unauthorized最常见。要么 Key 没设进环境变量要么base_url写错了。检查echo $TAOTOKEN_API_KEY是否有值再确认base_url是https://taotoken.net/api而不是带多余路径。注意有些 SDK 会自动拼接/v1如果报 404 而不是 401多半是路径重复了。local proxy failed / connection error这类通常是本机网络环境或代理配置导致的连接失败。先确认你的请求能正常访问外网再检查requests是否被系统代理干扰。可以在代码里显式传proxies{http: None, https: None}排除干扰或者检查环境变量HTTP_PROXY是否指向了失效地址。reading choices of undefined这个报错说明返回体结构和你预期的不一样。常见原因是模型 ID 填错服务端返回了错误对象而不是标准的choices数组。打印完整resp看error字段确认MODEL_ID在控制台可用列表里。另外如果用了流式但没处理 chunk也会出现类似问题。OAuth / 认证失败如果你在 Claude Code 或类似工具里配置注意区分 API Key 认证和 OAuth 认证。走 API Key 时Base URL 填https://taotoken.net/apiKey 填控制台生成的sk-开头字符串。OAuth 流程和 API Key 是两套东西别混用。Claude Code 的接入文档在这里https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite排查时养成习惯先单独用 curl 测通接口再回到 Python 脚本。curl 命令curl https://taotoken.net/api/chat/completions \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d {model:gpt-4o-mini,messages:[{role:user,content:ping}]}curl 通了脚本不通问题就在代码curl 也不通问题在 Key 或网络配置。6. 把链路用起来从单页提取到批量归档单页跑通只是开始。实际场景里你面对的是几百上千个 URL需要批量处理、去重、存盘。我的做法是把上面的pipeline包一层加并发和重试from concurrent.futures import ThreadPoolExecutor import time def safe_pipeline(url: str, retries: int 3) - str: for i in range(retries): try: return pipeline(url, use_modelFalse) except Exception as e: if i retries - 1: return f[FAILED] {url}: {e} time.sleep(1.5 * (i 1)) urls [https://example.com/a, https://example.com/b] with ThreadPoolExecutor(max_workers5) as pool: results list(pool.map(safe_pipeline, urls))并发数别开太大5 到 8 比较稳避免被目标站限流。存盘时按 URL 的 hash 命名方便断点续跑。如果你要把提取结果喂给模型做摘要或问答直接复用第 3 节的 client把refine_with_model换成你的业务 prompt 即可。长期做编码和 Agent 任务的话可以考虑 Coding Plan把模型调用额度集中管理https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite想先验证模型输出质量用模型对话页面快速试 prompthttps://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel-chatutm_campaignrewrite最后给一个实用技巧正文提取的质量七分靠清洗三分靠算法。与其花时间调打分公式不如先把NOISE_TAGS列表按目标站点补全把评论区和推荐模块的 class 名加进黑名单。这一步的收益比换任何库都大。
延伸阅读

更多相关文章

2026/9/29 13:54:54

arm64离线部署Harbor 2.13.1:从踩坑到跑通全指南

简介:这份资源是面向 ARM 架构服务器环境的 Harbor 2.13.1 离线安装包,适合需要在国产化平台或 ARM 服务器上私有化部署容器镜像仓库的运维与 DevOps 人员。包内共 6 个文件,以 shell 脚本、配置模板、压缩镜像包和许可证文件为主&#xff0c…

2026/9/29 13:54:54

从S型曲线到扩散模型:一维demo实战与避坑指南

简介:这是一份面向扩散模型初学者的入门级实践demo,围绕S型曲线(sigmoid函数)的生成过程展开,帮助读者直观理解扩散模型在信息传播、技术扩散等场景中的动态行为。资源以可运行的代码示例为核心,适合具备一…

2026/9/29 13:54:54

ARM64离线部署Harbor 2.13.1:避坑指南与API运维实践

简介:本资源为面向 ARM 架构服务器环境的 Harbor 2.13.1 离线安装包,适合在国产化平台、ARM 服务器或内网隔离场景下部署私有镜像仓库的运维与 DevOps 人员使用。压缩包共包含 6 个文件,以 sh 安装脚本、gz 镜像归档、prepare 预检脚本、tmpl…

2026/9/29 22:31:11

Linux Input子系统:事件中枢架构与驱动开发实战

1. Input子系统不是“键盘鼠标驱动”,而是Linux内核的事件中枢很多人第一次听说Input子系统,是在调试一个USB触摸屏死活不识别、或者红外遥控器按键没反应的时候。翻遍dmesg日志只看到“input: xxx as /devices/...”,却找不到设备节点/dev/i…

2026/9/29 22:31:11

Spring AI 接入 MCP 协议的实战案例:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/29 22:31:11

西安同城拼车软件开发实战:从0到1技术架构与开发指南

西安同城拼车软件开发实战:从0到1技术架构与开发指南 一、项目背景与技术选型 在西安这个历史文化名城,随着城市交通压力增大和共享经济理念普及,同城拼车软件逐渐成为市民出行的新选择。开发一套完整的西安同城拼车软件,不仅需要…

2026/9/29 11:07:23

东莞市品牌网站建设报价常见报错与解决

东莞品牌网站建设报价单背后:一份保姆级建站教程避坑实录 网站做好了没人访问,这大概是很多老板最头疼的事。花了大几万做的品牌站,上线后流量惨淡,比路边摊还冷清。别急着骂外包公司,很多“东莞品牌网站建设报价”里藏着不少猫腻,比如用模板站冒充定制…

2026/9/29 21:48:03

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解 【免费下载链接】spirula-studio Cross-vendor 3D Gaussian Splatting trainer - video to splat to mesh, Vulkan or CUDA. 项目地址: https://gitcode.com/GitHub_Trending/sp/spirula-studio Sp…

2026/9/29 7:00:49

SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南 模板网站太丑不够用?别急着加滤镜,那是治标不治本。很多老板盯着后台流量掉得眼红,却还在纠结首页Banner的圆角是不是3像素。这就像穿着西装去挖土,姿势不对,努力白费。我整理这份 速查手册…

2026/9/29 0:04:04

AI Evals实战指南:从零搭建LLM应用评估体系与CI/CD集成

1. 为什么AI Evals值得你花时间搞明白做LLM应用的人,迟早会撞上同一堵墙:模型输出飘忽不定,今天答得好好的,明天换个问法就胡说八道。你改了一版提示词,感觉好像好了点,但到底好了多少?说不清。…

2026/9/29 0:04:04

Java采购管理系统实战:从数据库设计到事务一致性

简介:这是一套面向Java Web初学者与课程设计者的采购管理系统完整源码,采用JSP技术搭建,配合MySQL数据库,用于解决企业采购信息的管理问题,适合作为毕业设计、课程大作业或进销存类项目的参考模板。系统实现了用户登录…

2026/9/29 3:53:39

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/29 9:46:12

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/29 6:36:14

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑