ByteNoteByteNote

字节笔记本

2026年2月16日

开源项目分享:Reader , 专为 LLM 设计的生产级网页抓取引擎

API中转
¥120

本文介绍 Reader,一个专为 LLM 和 AI Agent 设计的开源生产级网页抓取引擎,支持 Cloudflare 绕过、智能内容提取和批量抓取。

项目简介

Reader 是一款基于 TypeScript 开发的开源网页抓取引擎,由 vakra-dev 团队开发维护。截至目前,该项目在 GitHub 上已获得 320 stars,采用 Apache 2.0 开源协议。

该工具解决了构建需要网络访问的 AI Agent 时的痛点。传统的 Puppeteer + 反检测插件方案在面对 Cloudflare、TLS 指纹检测、代理管理等生产级挑战时往往力不从心。Reader 基于 Ulixee Hero 构建,提供了开箱即用的企业级抓取能力。

核心特性

反检测能力

  • Cloudflare 绕过:TLS 指纹模拟、DNS over TLS、WebRTC IP 掩码
  • 多信号检测:通过 DOM 元素和文本模式检测挑战
  • 动态等待:自动轮询挑战解决状态

内容提取

  • 智能清理:自动移除导航、页眉、页脚、弹窗、Cookie 横幅
  • 主内容提取:自动识别并提取页面主要内容
  • 多格式输出:支持 Markdown、HTML、JSON、Text

企业级功能

  • 浏览器池:自动回收、健康监控、队列管理
  • 并发抓取:并行 URL 处理与进度跟踪
  • 代理支持:数据中心和住宅代理,支持粘性会话和轮询
  • 网站爬取:BFS 链接发现,支持深度和页面限制

技术栈

  • TypeScript - 主要开发语言
  • Ulixee Hero - 高级无头浏览器(反检测核心)
  • supermarkdown - Rust 编写的 HTML 转 Markdown 引擎
  • Node.js - 运行时环境(>= 18)

安装指南

前置要求

  • Node.js >= 18
  • Linux 服务器需安装 Chrome 系统依赖(见下文)

安装

bash
npm install @vakra-dev/reader

Linux 服务器依赖

在 headless Linux 服务器(VPS、EC2 等)上需要安装 Chrome 的系统依赖:

bash
# Debian/Ubuntu
sudo apt-get install -y libnspr4 libnss3 libatk1.0-0 libatk-bridge2.0-0 \
  libcups2 libxcb1 libatspi2.0-0 libx11-6 libxcomposite1 libxdamage1 \
  libxext6 libxfixes3 libxrandr2 libgbm1 libcairo2 libpango-1.0-0 libasound2

快速开始

基础抓取

typescript
import { ReaderClient } from "@vakra-dev/reader";

const reader = new ReaderClient();

const result = await reader.scrape({
  urls: ["https://example.com"],
  formats: ["markdown", "html"],
});

console.log(result.data[0].markdown);
await reader.close();

批量并发抓取

typescript
const result = await reader.scrape({
  urls: ["https://example.com", "https://example.org"],
  formats: ["markdown"],
  batchConcurrency: 3,
  onProgress: (progress) => {
    console.log(`${progress.completed}/${progress.total}: ${progress.currentUrl}`);
  },
});

网站爬取

typescript
const result = await reader.crawl({
  url: "https://example.com",
  depth: 2,
  maxPages: 20,
  scrape: true,
});

console.log(`发现 ${result.urls.length} 个页面`);

使用代理

typescript
const result = await reader.scrape({
  urls: ["https://example.com"],
  formats: ["markdown"],
  proxy: {
    type: "residential",
    host: "proxy.example.com",
    port: 8080,
    username: "username",
    password: "password",
    country: "us",
  },
});

CLI 使用

守护进程模式

bash
# 启动守护进程
npx reader start --pool-size 5

# 后续命令自动连接守护进程
npx reader scrape https://example.com
npx reader crawl https://example.com -d 2

# 查看状态
npx reader status

# 停止守护进程
npx reader stop

抓取命令

bash
# 抓取单个 URL
npx reader scrape https://example.com

# 多格式输出
npx reader scrape https://example.com -f markdown,html

# 并发抓取多个 URL
npx reader scrape https://example.com https://example.org -c 2

# 保存到文件
npx reader scrape https://example.com -o output.md

爬取命令

bash
# 基础爬取
npx reader crawl https://example.com

# 深度爬取并抓取内容
npx reader crawl https://example.com -d 3 -m 50 --scrape

# URL 过滤
npx reader crawl https://example.com --include "blog/*" --exclude "admin/*"

高级用法

浏览器池配置

typescript
const reader = new ReaderClient({
  browserPool: {
    size: 5,                    // 5 个浏览器实例
    retireAfterPages: 50,       // 50 页后回收
    retireAfterMinutes: 15,     // 15 分钟后回收
  },
  verbose: true,
});

代理轮询

typescript
const reader = new ReaderClient({
  proxies: [
    { host: "proxy1.example.com", port: 8080, username: "user", password: "pass" },
    { host: "proxy2.example.com", port: 8080, username: "user", password: "pass" },
  ],
  proxyRotation: "round-robin", // 或 "random"
});

生产环境部署

typescript
import HeroCore from "@ulixee/hero-core";
import { TransportBridge } from "@ulixee/net";
import { ConnectionToHeroCore } from "@ulixee/hero";
import { scrape } from "@vakra-dev/reader";

// 启动时初始化一次
const heroCore = new HeroCore();
await heroCore.start();

// 每个请求创建连接
function createConnection() {
  const bridge = new TransportBridge();
  heroCore.addConnection(bridge.transportToClient);
  return new ConnectionToHeroCore(bridge.transportToCore);
}

// 在请求中使用
const result = await scrape({
  urls: ["https://example.com"],
  connectionToCore: createConnection(),
});

工作原理

Cloudflare 绕过机制

  1. TLS 指纹模拟:模拟真实 Chrome 浏览器指纹
  2. DNS over TLS:使用 Cloudflare DNS (1.1.1.1) 模拟 Chrome 行为
  3. WebRTC IP 掩码:防止 IP 泄露
  4. 多信号检测:通过 DOM 元素和文本模式检测挑战
  5. 动态等待:轮询挑战解决状态,检测 URL 重定向

浏览器池

  • 自动回收:100 次请求或 30 分钟后自动回收浏览器
  • 健康监控:每 5 分钟后台健康检查
  • 请求队列:池满时排队请求(最大 100)

HTML 转 Markdown

Reader 使用 supermarkdown 进行转换,这是一个用 Rust 从头编写的专用引擎:

  • Rust 编写:通过 napi-rs 提供 Node.js 绑定,原生性能
  • 完整 GFM 支持:表格、任务列表、删除线、自动链接
  • LLM 优化:专为 AI 消费设计的干净输出
  • 实战测试:处理真实网页的畸形 HTML
  • CSS 选择器:转换时可包含/排除元素

API 参考

ReaderClient 配置

选项类型默认值说明
verbosebooleanfalse启用详细日志
showChromebooleanfalse显示浏览器窗口
browserPoolBrowserPoolConfig-浏览器池配置
proxiesProxyConfig[]-代理数组
proxyRotationstring"round-robin"轮询策略

scrape 方法

选项类型必需默认值说明
urlsstring[]-URL 数组
formatsArray<"markdown" | "html">["markdown"]输出格式
onlyMainContentbooleantrue仅提取主内容
batchConcurrencynumber1并发数
proxyProxyConfig-代理配置

注意事项

  • 生产环境建议使用共享 Hero Core 避免重复启动 Chrome
  • Linux 服务器必须安装 Chrome 系统依赖
  • 浏览器池大小根据服务器资源合理配置
  • 代理配置支持数据中心和住宅代理

项目链接

分享: