一个年费百来块的「稍后读」工具核心能力,我用 AI 从零写了一个出来。过程里翻过车,也看清了一件事:模型之间的差距,不在「能不能写」,而在「能不能陪你改到底」。
Doubao-Seed-Evolving(1M 上下文、主打 Coding 长程任务)约一天零碎时间,就能复刻一个年费百来块「稍后读」工具的网页转 Markdown 核心功能。关键在于它能在多轮调试里记住每一个 bug——第一版修参数冲突,第二轮修微信公众号丢标题、头条动态页空壳,最终 3 类网页全部跑通。这类本地脚本可进一步沉淀进 YesApi Pro,包成一个对外提供、带鉴权与计费的「网页提取」API 能力。
本文里那个本地脚本,最终可以原样搬进 YesApi Pro:服务端跑脚本,对外只暴露一个接口地址加 app_key,鉴权、文档、监控交给平台。如果你也需要把零散需求沉淀成可复用、可计费的 API 能力,Java 版 ¥33,800 起含源码、PHP 版 ¥15,899 起,当天部署上线。
查看 Java 版详情 →我们团队日常要维护几个竞品博客和技术社区的信息雷达,看到有价值的文章就转成 Markdown 存档。市面上的「稍后读」工具不少,但好用的基本都要付费——简悦高级版一年百来块,Cubox 也差不多,Readwise Reader 更贵。
不是说付不起,而是觉得:就一个「网页转 Markdown」的功能,能不能让 AI 帮我写一个?
正好手上用的是 Doubao-Seed-Evolving——火山方舟上周刚升级的模型,上下文窗口扩到了 1M,主打 Coding 和 Agent 场景的长程任务。简单来说,它不只是「能写代码」,而是能在一次很长的对话里记住前前后后的细节,陪你改到底。我决定拿它试试:让模型从头写一个网页正文提取工具,把付费软件的核心功能复刻出来。
小功能不值得年年交钱,但值得用一次 AI 把它彻底变成自己的。
我的第一个提示词很直接:
帮我写一个 Python 脚本,输入一个网页 URL,输出正文内容,格式为 Markdown。
用 readability 或类似算法实现,去掉导航、侧边栏、广告、版权信息等噪音。
Doubao-Seed-Evolving 给出的第一版,架构比我预期的完整。它不只选了 readability 做正文提取,还配了 markdownify 转 Markdown,自动补了 User-Agent、处理了编码和 SSL 异常,连相对链接转绝对路径都写好了。核心结构长这样(节选):
def fetch_url(url, timeout=15, verify_ssl=True):
if not url.startswith(("http://", "https://")):
url = "https://" + url
headers = {"User-Agent": DEFAULT_UA}
resp = requests.get(url, headers=headers, timeout=timeout, verify=verify_ssl)
resp.raise_for_status()
return resp.text
def extract_markdown(html, page_url=""):
soup = BeautifulSoup(html, "lxml")
# 预清理导航/侧边栏/广告等噪音标签
for tag in soup.find_all(["script", "style", "nav", "aside", "footer"]):
tag.decompose()
doc = Document(str(soup), url=page_url)
content_html = doc.summary()
return md(content_html, heading_style="ATX", convert=["table", "pre"])
第一版代码很规整:请求 → 预清理 → 解析 → 转 Markdown,没有多余的东西。它还顺手补了 User-Agent 和相对链接修复,这是很多新手容易漏、导致提取出来链接打不开的细节。这一下超出了我对 Doubao-Seed-Evolving 的预期。
但有个小插曲:第一版代码刚运行就抛出报错——markdownify 不允许同时传 convert 和 strip 两个参数。这成了我们第一轮要修的东西。
能不能把真实网页正文提出来,还得跑了才知道。
我选了 3 个不同类型的网页做测试,如实记录结果:
| 测试网页 | 结果 | 现象 |
|---|---|---|
| 掘金技术博客 | ✅ 成功 | 标题、章节、代码块语言标注、段落全部正常 |
| 自己的公众号文章 | ⚠️ 部分成功 | 正文完整,但标题变成 [no-title] |
| 头条文章 | ❌ 失败 | 只提取到 # [no-title],正文完全没有 |
第一个是掘金的技术博客——代码块还在,语言标注(python/json/yaml)都保留了,章节、表格也没丢。技术博客这类服务端渲染(SSR)的页面,HTML 里就带着完整正文,第一版就基本跑通。
第二个是我的公众号文章——正文提取出来了,但标题变成了一行 [no-title]。标题丢了,存进笔记软件后一眼看不出是什么文章,体验打折扣。
第三个是头条文章——结果直接翻车。打开输出文件,只有一行 # [no-title],下面什么都没有。正文完全没拿到。
三个网页,一个直接成功,一个丢标题,一个彻底空壳。第一版没有框架预设里那么惨,但真实的问题比预设的更有意思,不同的网站暴露出不同的短板。
这是展示它长上下文和代码能力的关键一节。我把失败贴回去,看它怎么处理。
第一版脚本真跑的时候报错了:markdownify 不允许同时传 convert 和 strip。我把报错贴回去,它给出了清晰的修正——删掉 strip 参数,因为前面的预清理已经处理过 script/style 了。改完,脚本从「异常退出」变成「正常执行」。这一轮我自己手动改了,也顺手验证了一件事:它给的修复方向是对的,不是糊弄。
我把公众号丢标题、头条空壳这两个现象一起发过去,附上了网址。它的分析很快,而且说得准:
[no-title]:Python 移植版的 readability-lxml 没有实现 og:title 读取,只硬解析 <title> 标签,而微信标题格式刚好踩了它的 bug。它建议改成语义化提取——优先读 og:title,再退到 twitter:title、h1,最后才用 readability 的结果。<div id="root"> 壳子,正文靠 JS 异步加载。它建议加一个 --render 参数,用 Playwright 无头浏览器等页面渲染完再提取。它还顺手修了两个隐藏问题:微信/头条的图片是懒加载(真实地址在 data-src),不处理会全部裂图;以及国内容器类名适配。
我按它给的新脚本重跑:公众号标题正常了,头条加 --render 后正文也完整提取出来了。两轮对话下来,它始终记得前面提到的每个问题,没有因为换了网站类型就忘掉。这种长程稳定性,也正是 Doubao-Seed-Evolving 升级后主打的 1M 上下文和 Coding 长程能力带来的真实体感。
同样一套需求,我丢给了一个上下文较短的普通免费模型做对照。
| 对比维度 | Doubao-Seed-Evolving | 普通模型 |
|---|---|---|
| 第一版代码质量 | ✅ 完整带预清理、SSL、链接修复 | ⚠️ 能跑但结构松散 |
| 遇到 bug 的修复 | ✅ 准确定位 markdownify 冲突 | ⚠️ 给的改法有时引入新错 |
| 多轮调试稳定性 | ✅ 两轮都记得前面的问题 | ❌ 第 2 轮开始忘记上下文 |
| 最终效果 | ✅ 3 种网页全部通过 | ⚠️ 只修好 1 个,另 2 个仍报错 |
普通模型第一版能跑,但遇到公众号丢标题时,我追问了一轮,它给了个改法,第二轮改的代码又引入了新 bug——把正文里的图片链接全过滤掉了。第三轮我继续问的时候,它已经开始忘记第一轮的需求了,问它「标题问题修了吗」,它回答得和之前完全不一样。
对比下来,Doubao-Seed-Evolving 在多轮调试里的「上下文记忆稳定性」最明显。写代码这种事,很少一次到位,能不能陪你改到底,比第一下写得漂不漂亮更有工程价值。
经过两轮迭代,最终脚本的使用方式很简单:
# 普通网页(掘金等技术博客、公众号)
python extract_article.py https://juejin.cn/post/xxx -o article.md
# 动态渲染站点(头条等),加 --render
python extract_article.py https://www.toutiao.com/article/xxx --render -o toutiao.md
三种类型的网页都能稳定提取,输出标准的 Markdown 文件,可以直接粘贴到笔记软件里存档。动态站点加一个 --render 参数即可,静态站点不需要额外依赖,速度更快。
一个小功能,从「临时跑一次」变成了「随时能用」。
代码跑通之后,我没有让它停在「本地一个脚本」的状态,而是把它作为网页提取能力的一个可复用示例,沉淀进了我们的产品 YesApi Pro——一个面向开发者的 API 开放平台。源码、使用说明、三类站点的测试结论,都整理成了标准的能力描述,以后遇到类似的「复刻工具」需求,可以直接参考这套提示词模板和修复思路。
一个小脚本,从「临时跑一次」变成了「产品里能查、能复用、能迭代的能力」。下次要接类似的提取需求,不用重新从零开始,直接在已有能力上改。
再往前想一步:这个本地脚本,其实可以原样搬进 YesApi Pro,建成一个「网页提取」接口。逻辑和把火山方舟包成对话 API 一样——脚本在服务端跑,对外只暴露一个接口地址加 app_key,谁拿着 key 谁就能调。鉴权、文档、监控交给平台,不用自己搭服务器。
这样它就不只是我电脑里的一个 .py 文件,而是变成了能直接对外提供的能力。
真正让工具值钱的不是代码本身,而是它有没有被沉淀下来、能被下一个人接手。
对「网页转 Markdown 存档」这一核心诉求,基本可以替代。掘金等技术博客、公众号能稳定提取;头条等纯客户端渲染站点加 --render 参数(无头浏览器)后也能完整提取。需要多端同步、标注、OCR 等高级功能的重度用户,仍可按需保留原工具。
失败分两类:① 标题丢失,原因是 readability-lxml 没读 og:title,应改为优先 og:title→twitter:title→h1 的语义化提取;② 正文空壳,原因是站点纯客户端渲染,requests 只抓到空壳 <div id="root">,需加 --render 用 Playwright 等无头浏览器等页面渲染完再提取。图片懒加载(data-src)也需单独处理。
把脚本放到服务端运行,对外只暴露一个接口地址加 app_key,谁拿 key 谁就能调;鉴权、限流、文档、监控交给 API 开放平台统一处理。这正是文章里「沉淀进 YesApi Pro」的做法——本地 .py 脚本可原样封装成平台内的「网页提取」能力,无需自己搭服务器和运维。
差距不在「能不能写出第一版」,而在「能不能陪你改到底」。长上下文模型(如 1M 上下文的 Doubao-Seed-Evolving)能在多轮调试里记住每一个 bug 和网站类型,定位准、不引入新错;上下文较短的普通模型常常第二轮就开始忘记需求、改出新 bug。写代码很少一次到位,多轮稳定性比第一下的漂亮更重要。
以下精选指南助你把握「AI 造能力 → 沉淀成产品」的完整链路