@trendtech33566: 【已保存版本】 给想将 URL 或 PDF 转换为干净 Markdown 的人,PullMD,约 400。以下是它能做的・C…

X AI KOLs Timeline 工具

摘要

PullMD 是一个开源、可自托管的服务,可将网页、PDF、Office 文档、EPUB、图片、音频和 YouTube 视频转换为干净的 Markdown,并提供 REST API、MCP 服务器和 PWA 前端。

【已保存版本】 给想将 URL 或 PDF 转换为干净 Markdown 的人 PullMD,约 400。 以下是它能做的 ・将网页转换为 Markdown,去除广告和装饰 ・支持 PDF/Office/EPUB/图片/音频/YouTube 等 ・包含 REST API / MCP 服务器 / PWA ・可自托管,并且易于与 AI 智能体集成 一个能瞬间完成“将信息标准化为 Markdown”的开源项目。 它与构建 RAG 预处理或 AI 工作流的人会产生共鸣。
查看原文
查看缓存全文

缓存时间: 2026/08/05 12:23

【已保存版本】 对于那些想把 URL 或 PDF 转换为整洁 Markdown 的人,PullMD,约 400。它能做到的事情: ・将网页转换为 Markdown,无广告或装饰 ・支持 PDF/Office/EPUB/图片/音频/YouTube 等 ・包含 REST API / MCP 服务器 / PWA ・可自托管,且易于与 AI 智能体集成 一个能瞬间处理“将信息标准化为 Markdown”的开源项目。它会引起那些构建 RAG 预处理或 AI 工作流的人的共鸣。


AeternaLabsHQ/pullmd

源码:https://github.com/AeternaLabsHQ/pullmd

PullMD 发布(https://github.com/AeternaLabsHQ/pullmd/releases) Docker 拉取(https://hub.docker.com/r/aeternalabshq/pullmd) CI(https://github.com/AeternaLabsHQ/pullmd/actions/workflows/docker.yml) 许可证(https://github.com/AeternaLabsHQ/pullmd/blob/main/LICENSE) MCP(https://github.com/AeternaLabsHQ/pullmd#mcp-server) 自托管的 URL 转 Markdown 服务,面向人类和 AI 智能体。

PullMD 接受任意网页 URL,返回干净、可读的 Markdown——没有导航、没有广告、没有样板内容。它能自动识别 Reddit 和 Hacker News 帖子(包含完整评论树),在可用时使用 Cloudflare 原生 Markdown,对静态 HTML 运行 Mozilla Readability + Trafilatura,最后的手段是通过无头 Chromium(Playwright 辅助容器)渲染 JavaScript 重页面后再提取。

v3 开始,PullMD 不再局限于网页:它还能将文档(PDF、Office、EPUB)、图片、音频和 YouTube 视频转换为 Markdown,并默认输出更精简、更省 token 的正文。参见下文 v3 新特性

它以以下形式提供:

  • 一个 PWA 前端,带有原始/渲染视图和实时 frontmatter 视图切换、一键分享输出到其他应用(Web Share API)、一个按服务器建议文件名保存结果为 .md 文件的下载按钮、深色/纸张主题、历史记录、归档、分享链接,以及本地 HTML 文件的转换(桌面端拖放、桌面端和移动端文件选择器)
  • 一个 REST API,位于 GET /api?url=...
  • 一个 MCP 服务器,位于 POST /mcp(Streamable-HTTP 传输,无状态)
  • 一个 Claude Code 技能,可下载 zip 包

每次转换都会获得一个 8 位十六进制 分享 ID,它可以作为一个稳定的实时端点:GET /s/:id 返回缓存的 markdown,并在超过一小时未更新时从源站重新获取。将分享 ID 用作固定 URL,始终返回新鲜内容——对 subreddit 订阅源等场景很有用。


v3 新特性

PullMD v3 从一个网页阅读器成长为一个通用的 任何内容转 Markdown 服务,面向智能体,并采用更精简的默认输出。超出纯网页提取的一切都是 可选启用并且优雅降级 的——未配置时,v3 对网页的处理与 v2 完全一致,只是在默认情况下正文更干净。

  • 默认使用干净正文 - Markdown 正文现在只有 # 标题 + 内容。来源 URL、抓取日期和所有元数据都移入 YAML frontmatter,因此不会重复,也为你节省 token。Reddit 帖子的规则相同:subreddit、作者、点赞数和发布日期位于 frontmatter(subreddit, author, upvotes, published)中,而非正文。这是唯一一个破坏性变更:设置 PULLMD_SOURCE_HEADER=true 可恢复旧的内联头部,并使用 PULLMD_FRONTMATTER_FIELDS 来裁剪输出的字段。参见 MIGRATION.md
  • 文档 → Markdown - 支持 PDF、Word、PowerPoint、Excel、EPUB 等,通过 URL 或上传POST /api/file,PWA 中可拖放)。
  • 高质量 PDF 表格(OCR) - 一个可选的、与供应商无关的 OCR 层?pdf=ocr),用于表格级 PDF 转换,自动回退到免费路径。
  • 图片和音频 → Markdown - 通过任何兼容 OpenAI 的或本地模型,可选启用字幕生成与转写;在 pullmd 内部运行,无需额外容器。
  • YouTube 转录 - 标题、描述和转录,带可点击时间码,无需 API 密钥。
  • 更丰富的 frontmatter - 提取来源、质量,以及(对于媒体/OCR)模型 + token/页数使用量,用于成本追踪,另加一个可配置的字段白名单。

从 v2.x 升级的自托管用户:干净正文变更是唯一的破坏性变更 - MIGRATION.md 提供了一行关闭配置。其他一切都是新增功能。

自 3.x 版本以来新增的内容:

  • Hacker News 管道(3.1)- 通过专门构建的转换器处理条目、评论永久链接和列表,并在 PWA 中提供 Web Share 和即时 frontmatter 切换。
  • X-Transcript-Status(3.2)- 区分瞬时 YouTube 速率限制与真正的转录缺失。
  • SSRF 防护(3.3)- 默认拒绝私有、回环、链路本地、CGNAT 和云元数据目标,覆盖每个抓取路径和每个重定向跳转。
  • 查询范围提取(3.4)- ?query= 仅返回与问题相关的章节,并带有 max_tokens 预算。
  • 开放站点配方(3.5/3.6)- JSON-LD 转换为 frontmatter、贡献者指南,以及 select.content,让配方可以直接指定文章正文。
  • 覆盖率保护(3.7)- 当提取仅保留正文的一小部分时恢复页面;参见 PULLMD_COVERAGE_GUARD
  • 账户控制(3.8)- 非管理员可以从自己的历史记录中清除条目,可以通过 PULLMD_ALLOW_SIGNUP 关闭自助注册,scripts/admin.js create-user 可从 shell 创建账户。
  • 下载按钮(3.9)- PWA 将结果保存为 .md 文件,文件名由服务器通过 X-Suggested-Filename 指定,并可选择添加日期前缀。

快速开始

预构建的多架构镜像(linux/amd64, linux/arm64)位于 Docker Hub 上。将 compose 文件放到某个位置并运行:

``bash mkdir pullmd && cd pullmd curl -O https://raw.githubusercontent.com/AeternaLabsHQ/pullmd/main/docker-compose.yml docker compose up -d

→ http://localhost:3000

``

就这么简单。不需要 .env:每个变量都有合理的默认值,PullMD 在 3000 端口监听。在 compose 文件旁边添加 .env 可覆盖任何设置(参见 配置)。

docker-compose.yml(零配置,节选)

``yaml services: pullmd: image: aeternalabshq/pullmd:latest container_name: pullmd restart: unless-stopped ports: - “{PORT:-3000}:3000" environment: - PUBLIC_URL={PUBLIC_URL:-http://localhost:${PORT:-3000}} - TRAFILATURA_URL=http://trafilatura:8001/extract - PLAYWRIGHT_URL=http://playwright:8002/render - MARKITDOWN_URL=http://markitdown:8003/convert - CACHE_DB=/data/cache.db volumes: - ./data:/data networks: - pullmd-internal depends_on: - trafilatura - playwright - markitdown

trafilatura: image: aeternalabshq/pullmd-trafilatura:latest container_name: pullmd-trafilatura restart: unless-stopped networks: - pullmd-internal

playwright: image: aeternalabshq/pullmd-playwright:latest container_name: pullmd-playwright restart: unless-stopped networks: - pullmd-internal

markitdown: image: aeternalabshq/pullmd-markitdown:latest container_name: pullmd-markitdown restart: unless-stopped mem_limit: ${MARKITDOWN_MEM_LIMIT:-1g} networks: - pullmd-internal

networks: pullmd-internal: driver: bridge ``

为可读性而节选 — 仓库中的 docker-compose.yml 会将每个可选的 .env 变量透传给容器(Reddit 凭据、认证、媒体/OCR 密钥、YouTube 选项、输出整形)。请使用上面的 curl -O 命令,而不是复制此代码块,否则超出基础项的 .env 覆盖不会到达容器。

注意: Playwright 辅助容器会给你的镜像缓存增加 约 3.7 GB(Chromium + Firefox + WebKit 二进制文件来自官方 Playwright 基础镜像)。它是可选的——不设置 PLAYWRIGHT_URL 并移除 playwright 服务块,PullMD 会静默降级为静态提取,并在元数据中添加一条降级说明。

注意: MarkItDown 辅助容器是可选的。不设置 MARKITDOWN_URL 并移除 markitdown 服务块即可禁用文档转换。网页 URL 始终可以在没有它的情况下工作。

GHCR 镜像: ghcr.io/aeternalabshq/{pullmd,pullmd-trafilatura,pullmd-playwright,pullmd-markitdown}。如果你更喜欢 GitHub 的镜像仓库,可以替换 image: 行。

在 Traefik 后面

对于使用 TLS 的 Traefik 部署,请改用 docker-compose.traefik.yml。镜像相同,但带有 Traefik 标签和 proxy 外部网络。在 .env 中设置 HOST_DOMAIN

bash curl -O https://raw.githubusercontent.com/AeternaLabsHQ/pullmd/main/docker-compose.traefik.yml echo "HOST_DOMAIN=pullmd.example.com" > .env docker compose -f docker-compose.traefik.yml up -d

本地开发(无需 Docker)

``bash git clone https://github.com/AeternaLabsHQ/pullmd.git cd pullmd npm install npm start

http://localhost:3000

npm test

node –test

``


配置

所有变量都放在 .env 中(从 .env.example 复制):

v3.0.0 输出格式变更: markdown 正文默认是干净的——只有 # 标题 后跟内容。来源 URL、抓取日期和所有提取元数据仍保留在 YAML frontmatter 中,与之前一样——正文不再重复它们。设置 PULLMD_SOURCE_HEADER=true 可恢复旧的内联头部。使用 PULLMD_FRONTMATTER_FIELDS 来选择输出哪些 frontmatter 字段(在智能体管道中节省 token 非常方便)。

变量是否必须用途
HOST_DOMAIN仅 Traefik 变体不带协议的公网主机名。供 Traefik 路由使用,并作为 PUBLIC_URL 的回退值。默认 compose 不使用。
PUBLIC_URL嵌入 /help 和技能 zip 中的完整公网源地址。默认为 https://${HOST_DOMAIN}
TRAFILATURA_URLTrafilatura 辅助容器 /extract 端点的 URL。未设置 → 跳过 Trafilatura,仅使用 Readability。
PLAYWRIGHT_URLPlaywright 辅助容器 /render 端点的 URL。未设置 → 跳过对 JS 页面的 Playwright 回退。
MARKITDOWN_URLMarkItDown 辅助容器 /convert 端点的 URL。未设置 → 禁用文档转换路径;POST /api/file 返回 502
PULLMD_VISION_API_KEY / ..._BASE_URL / ..._MODEL通过兼容 OpenAI 的视觉端点进行图像字幕生成。设置密钥即启用。_MODEL 默认为 gpt-4o-mini
PULLMD_STT_API_KEY / ..._BASE_URL / ..._MODEL通过兼容 OpenAI 的 /audio/transcriptions 端点进行音频转写。设置密钥即启用。_MODEL 默认为 whisper-1
PULLMD_LLM_API_KEY / ..._BASE_URL当各模态变量未设置时,作为视觉 + 语音转写共享的回退凭据。只有密钥和基础 URL——没有 PULLMD_LLM_MODEL,设置了也会被忽略(服务器启动时会给出警告)。
PULLMD_PDF_OCR_API_KEY / ..._BASE_URL / ..._MODEL通过保留表格的 OCR 提供商实现可选的高质量 PDF→Markdown(参考:Mistral OCR mistral-ocr-latest)。通过请求参数 ?pdf=ocr 或配方 fetch.pdf: ocr 触发。默认 PDF 处理仍使用免费的 markitdown 路径。_MODEL 默认为 mistral-ocr-latest
MARKITDOWN_YOUTUBE设置为 true 可将 YouTube URL 路由到 markitdown 辅助容器(返回标题 + 描述 + 转录)。无需 API 密钥。默认关闭。
MARKITDOWN_YT_TIMECODES否(辅助容器)转录中的默认时间码格式:links(YouTube 时间戳链接,默认)、plain(纯 [MM:SS] 标签)、none(仅转录文本)。可通过请求参数 ?yt_timecodes= 覆盖。
MARKITDOWN_YT_CHUNK否(辅助容器)转录块大小,以秒为单位(默认 30)。0 保持原始逐片段粒度。可通过请求参数 ?yt_chunk= 覆盖。
MARKITDOWN_YT_LANGS否(辅助容器)逗号分隔的首选转录语言(例如 de,en)。如果首选语言不存在,则回退到第一个可用语言。
MARKITDOWN_YT_PROXY否(辅助容器)YouTube 请求的 HTTP(S) 代理 URL。数据中心 IP 地址经常被 YouTube 的转录 API 限流;住宅或 ISP 代理可能有所帮助。
REDDIT_CLIENT_IDReddit 的 OAuth 凭据。没有它们,PullMD 使用公共 JSON API(速率限制较低)。
REDDIT_CLIENT_SECRET
REDDIT_USER_AGENTReddit 要求唯一的 UA。默认:PullMD/1.0 (URL-to-Markdown service)
DISABLE_PUBLIC_HISTORY当为 true 时,隐藏全局最近转换列表和归档(/api/history + /api/archive 返回 403,前端隐藏该部分)。/s/:id 分享链接继续工作。默认:false
PULLMD_USER_AGENT为每次 Web 抓取固定一个出站 User-Agent。禁用轮换。适用于 CI 或已知特定 UA 可用的情况。
PULLMD_UA_FEED_URL当前真实世界 UA 的 JSON 订阅源 URL。默认:WinFuture23/real-world-user-agents(https://github.com/WinFuture23/real-world-user-agents)。设置为空字符串可禁用实时刷新,并依赖内置的初始种子池。
PULLMD_AUTH_MODEdisabled(默认)/ single-admin / multi-user。参见下方的“认证”。
PULLMD_ALLOW_SIGNUPmulti-user 模式下的自助注册。默认开启。false / 0 / no / off 会关闭 /signup(返回 404)并从登录页移除“创建账户”链接。仍可通过 node scripts/admin.js create-user 创建账户。
PULLMD_ADMIN_EMAIL当 AUTH_MODE != disabled 时,首次启动时需要第一个管理员的引导邮箱。
PULLMD_ADMIN_PASSWORD当 AUTH_MODE != disabled 时,首次启动时需要引导密码(最少 8 个字符)。
PULLMD_AUTH_TOKEN旧的 bearer token 兼容(仅 single-admin 模式,已弃用)。
PULLMD_SOURCE_HEADER设置为 true 可在正文中恢复旧的内联来源头部(# 标题 + **域名** · 日期 + url;对于 Reddit 是 **r/sub** · u/user · N ↑ 行)。默认(未设置):干净正文 - 仅 H1 标题;来源/日期/帖子元数据位于 frontmatter 中。
PULLMD_FRONTMATTER_FIELDS逗号分隔的 frontmatter 字段白名单(例如 title,url,source,llm_tokens)。未设置 = 全部字段。可裁剪 token。未知名称会被忽略,并在启动时给出警告。
PULLMD_ALLOWED_HOSTS逗号分隔的 CIDR 和/或精确主机名,即使它们解析到被阻止的范围内也允许抓取。默认空 = 每个内部目标都被阻止。参见 SSRF 防护
PULLMD_SITE_RECIPES额外站点配方的 JSON 文件路径,会合并到内置配方之上。替代 data/site-recipes.json
PULLMD_FILENAME_DATE_PREFIX建议下载文件名(X-Suggested-Filename)的前缀模板。未设置 = 无前缀。令牌 YYYY MM DD HH mm ss 按本地时间替换,所有其他字符直接传递;A-Za-z0-9._- 之外的任何字符最终会成为连字符。示例:YYYY-MM-DD-HH-mm-ss- 会得到 2026-08-01-13-33-42-YT-some-talk-dQw4w9WgXcQ.md
PULLMD_COVERAGE_GUARD设置为 off 可禁用覆盖率保护。默认(未设置):开启。该保护会在提取仅保留页面的一小部分时注意到问题——这是页面构建器单页应用的失败模式,其章节存在于扁平的兄弟容器中,而 Readability 的单一候选评分会丢弃这些容器——并重新转换包含正文的容器。它只会增加结果,记录 source: coverage-guard,并在 metadata.extractorReason 中解释原因。

PUBLIC_URL 对自托管很重要:帮助页面和可下载技能将其作为规范端点嵌入。正确设置它,你的用户将获得一个指向你的实例的复制粘贴设置。PullMD 会轮换其出站 Use

相似文章

@GitHub_Daily: 想把网页内容喂给 AI,结果抓回来一堆导航栏、广告和乱码,上下文窗口浪费大半,AI 还读不明白。 于是找到 PullMD 这个开源项目,可以把任意网页内容提取转成干净的 Markdown 文件。 只需提供网页链接,自动识别页面类型,层层提…

X AI KOLs Timeline

PullMD 是一个开源的 URL 转 Markdown 服务,可以自动提取网页正文内容,去除导航、广告等杂物,支持无头浏览器和多种接口(网页、REST API、MCP),便于 AI 工具和用户获取干净的网页文本。

tweet.md

Product Hunt

tweet.md 是一款将 X(Twitter)帖子转换为简洁 Markdown 格式的工具,可简化内容复用。