Agent-Reach 网页阅读实战:Jina Reader、web-reader MCP 与 RSS 三工具组合
本文基于 Agent-Reach 的网页阅读参考文档 web.md,系统讲解「通用网页 / 需要格式控制的网页 / RSS 订阅源」三类读取场景下分别选用的工具、完整命令与适用边界,并结合 WebChannel、RSSChannel 与 URL 安全校验源码,说明每条命令背后的实现约束与安全防线。读完后可直接在 Agent 工作流中按选择指南选用合适的网页读取路径,并理解其兜底机制、反爬识别与内网地址拦截等底层行为。
一、定位:web 是 Agent-Reach 的零配置兜底渠道
在 Agent-Reach 的渠道体系里,每个平台对应一个 Channel,按配置成本分为 tier 0(零配置)/ 1(需免费 key)/ 2(需登录态),语义定义在 base.py 中。web 渠道被设计为最底层的兜底:
# agent_reach/channels/web.py
class WebChannel(Channel):
name = "web"
description = "任意网页"
backends = ["Jina Reader"]
tier = 0
def can_handle(self, url: str) -> bool:
return True # Fallback — handles any URL
从源码结构看,can_handle 恒返回 True,意味着当其他渠道(YouTube、B站、小红书等)无法处理某个 URL 时,任何链接最终都会落到 web 渠道,用 Jina Reader 读取。其 check() 不做任何网络探测,直接返回 "ok",保证 agent-reach doctor 检查该渠道时零开销——这一契约由 test_web_channel.py 明确验证:test_check_is_ok_and_touches_no_network 断言 check() 期间 urlopen 从未被调用。
二、通用网页:Jina Reader
文档给出的基础用法是:
# 读取任意网页内容
curl -s "https://r.jina.ai/URL"
# 示例
curl -s "https://r.jina.ai/https://example.com/article"
适用场景:大多数网页可以直接用 Jina Reader 读取。这也是 SKILL.md 路由表中「网页/文章/RSS」分类推荐的零配置命令。
源码级实现:一次 read() 调用的完整链路
CLI 侧的 curl 与 Python 侧的 WebChannel.read() 走的是同一个上游服务,后者在 web.py 中实现了更完整的防御性逻辑:
def read(self, url: str) -> str:
"""通过 Jina Reader 读取网页,返回 Markdown 全文。"""
url = normalize_public_http_url(url)
jina_url = f"https://r.jina.ai/{url}"
req = urllib.request.Request(
jina_url,
headers={"User-Agent": _UA, "Accept": "text/plain"},
)
with urllib.request.urlopen(req, timeout=30) as resp:
body = resp.read(_MAX_RESPONSE_BYTES + 1)
...
关键约束逐项拆解:
| 约束 | 源码常量 | 行为 |
|---|---|---|
| URL 归一化 | normalize_public_http_url |
无 scheme 时补 https://;非法 URL 直接抛 ValueError,不发起网络请求 |
| 请求头 | _UA、Accept: text/plain |
以浏览器 UA 请求,声明接收纯文本(Jina Reader 默认返回 Markdown 全文) |
| 超时 | timeout=30 |
30 秒硬超时,避免 Agent 卡在慢速请求上 |
| 响应上限 | _MAX_RESPONSE_BYTES = 5 * 1024 * 1024 |
响应超过 5MB 抛 ValueError,防止超大页面撑爆上下文 |
| 反爬识别 | _ANTIBOT_SCAN_BYTES = 4096 |
扫描响应前 4KB,识别高置信度验证页 |
对应测试 test_web_channel.py 验证了:无 scheme 的 example.com/article 会被补全为 https://r.jina.ai/https://example.com/article;http:// 与 https:// 前缀分别原样保留、不会被强制升级或二次拼接;响应恰好 5MB 时放行、5MB+1 字节时报 response exceeds;反爬页(如 "Just a moment..." + CAPTCHA 警告、Cloudflare "Attention Required!" 含 Ray ID)抛出中文 RuntimeError,提示改用站点专用工具或浏览器读取。
反爬识别:只拦截「高置信度」验证页
_is_antibot_page() 的判定逻辑并非简单关键词匹配,而是要求组合特征同时出现:
- Jina CAPTCHA 警告(
warning:+requiring captcha)且存在挑战结构标记(title: just a moment...、## performing security verification或 Cloudflare 标题);或 - Cloudflare 拦截标题 且 含
ray id或/cdn-cgi/challenge-platform/路径。
测试用例专门覆盖了「单个通用词不应误杀」的场景:标题为 "A guide to security verification" 的正常文章、以及验证特征出现在 4096 字节窗口之外的长文,都会正常返回。这避免了把谈安全话题的正常文章误判为验证页。
URL 安全防线:只读公开公网地址
read() 的第一步 normalize_public_http_url 实现在 url.py,是对不可信 URL 的严格白名单校验。它会拒绝(全部在测试中被参数化断言、且确认未发起任何网络请求):
- 非 HTTP(S) scheme:
file:///etc/passwd、ftp://; - 内网/本机目标:
localhost、intranet、home.arpa、metadata.google.internal、127.0.0.1、[::1]、链路本地169.254.169.254(云元数据地址)、192.168.x.x; - 各种「换皮」IP 写法:十进制
2130706433、十六进制0x7f000001、八进制0177.0.0.1、IPv4-mapped IPv6[::ffff:127.0.0.1]; - userinfo 伪装:
https://user:password@example.com/private; - 含反斜杠、空白或控制字符的畸形输入。
放行条件同时要求 host 为真实公网域名或全球单播 IP(literal_address.is_global)。这条防线意味着:让 Agent 通过 web 渠道读取链接时,攻击者无法借 URL 参数把请求引向本机服务或内网资产。
三、Web Reader(MCP):精确控制输出格式
当需要更精确控制输出格式(保留图片、切换纯文本)时,文档给出 mcporter 调用形式:
# 读取网页内容 (Markdown 格式)
mcporter call web-reader.webReader url="https://example.com"
# 保留图片
mcporter call web-reader.webReader url="https://example.com" retain_images=true
# 纯文本格式
mcporter call web-reader.webReader url="https://example.com" return_format="text"
适用场景:需要更精确控制输出格式时使用。
前提:mcporter 配置里要有 web-reader 服务
mcporter call <server>.<tool> 要求 <server> 已在 mcporter 的 mcpServers 中登记。仓库自带的示例配置 config/mcporter.json 目前只包含 exa 与 xiaohongshu 两个服务:
{
"mcpServers": {
"exa": { "baseUrl": "https://mcp.exa.ai/mcp" },
"xiaohongshu": { "baseUrl": "http://localhost:18060/mcp" }
},
"imports": []
}
因此使用 web-reader 前,需要按同样的格式把 web-reader 服务加入本机 mcporter 配置(mcporter 0.7.3 的加载顺序为 ~/.mcporter/mcporter.json / mcporter.jsonc,再叠加 <项目目录>/config/mcporter.json,后者同名覆盖前者;也可用环境变量 MCPORTER_CONFIG 显式指定单层配置)。仓库中 mcporter.py 的 inspect_mcporter_config() 正是按这套层级规则只读解析配置、提取 mcpServers 的 server 名,doctor 检查即依赖它判断哪些 MCP 服务可用——所以配置完成后跑 agent-reach doctor 可以确认 web-reader 是否被识别。
四、RSS 阅读:feedparser
订阅博客、新闻源、播客等 RSS feed 时,文档推荐 Python 一行式:
python3 -c "
import feedparser
for e in feedparser.parse('FEED_URL').entries[:5]:
print(f'{e.title} — {e.link}')
"
适用场景:订阅博客、新闻源、播客等 RSS feed。
feedparser 是 Agent-Reach 的硬依赖(pyproject.toml 中声明 feedparser>=6.0),因此安装 Agent-Reach 后即可直接使用,无需额外安装。对应的 RSSChannel 定义了 feed 的识别与自检逻辑:
def can_handle(self, url: str) -> bool:
return any(x in url.lower() for x in ["/feed", "/rss", ".xml", "atom"])
从源码结构看,当 URL 中包含 /feed、/rss、.xml 或 atom 特征时会被路由到 RSS 渠道而非通用网页渠道。其 check() 会在导入失败时给出两条修复路径:未安装返回 pip install feedparser;已安装但导入期崩溃(半残安装/版本冲突)则返回 pip install --force-reinstall feedparser。实际使用时建议按 test.sh 或 pip 环境确认依赖完整后,再对目标 feed URL 执行上面的片段。
五、选择指南
综合文档的选择表与源码行为,三工具的取舍如下:
| 场景 | 推荐工具 | 特点与边界(源码印证) |
|---|---|---|
| 通用网页 | Jina Reader(curl r.jina.ai 或 WebChannel.read) |
tier 0 零配置兜底;30 秒超时、5MB 上限、反爬验证页会显式报错 |
| 需要图片/格式控制 | web-reader MCP | retain_images=true 保留图片、return_format="text" 纯文本;依赖本机 mcporter 已配置该服务 |
| RSS 订阅 | feedparser | URL 含 /feed、/rss、.xml、atom 特征时自动路由到 RSS 渠道;feedparser>=6.0 为内置依赖 |
补充两条实操判断:
- 先用 doctor 确认路由。
agent-reach doctor --json会输出每个渠道当前的active_backend;web 渠道恒为Jina Reader,RSS 渠道在 feedparser 缺失时会显示off并附带安装指令,据此决定是否需要先修环境。 - Jina Reader 报反爬验证页时不要重试。
read()对高置信度验证页抛出RuntimeError并提示「请改用站点专用工具或浏览器读取」——此时应切换到对应平台的专用渠道(如 social、video 分类),而不是反复 curl。
六、验证与进一步阅读
- 渠道实现:agent_reach/channels/web.py、agent_reach/channels/rss.py、渠道基类与 tier/后端路由语义见 agent_reach/channels/base.py
- 安全校验:agent_reach/utils/url.py(
normalize_public_http_url/host_matches) - 行为契约测试:tests/test_web_channel.py(URL 规范化、大小限制、反爬识别、非公网地址拦截)
- Skill 路由表:agent_reach/skill/SKILL.md(「网页/文章/RSS」分类入口)
适用前提说明:Jina Reader 为外部公共服务,需可访问外网;web-reader 依赖本机 mcporter 与对应 MCP 服务可用;以上命令在 Agent-Reach 1.5.0(见 pyproject.toml)代码库中均有对应实现或配置依据。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0622
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00