diff --git a/agent_reach/channels/wechat.py b/agent_reach/channels/wechat.py index 25df67a..050b988 100644 --- a/agent_reach/channels/wechat.py +++ b/agent_reach/channels/wechat.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- """WeChat Official Account articles — read and search. -Read: wechat-article-for-ai (Camoufox stealth browser) -Search: miku_ai (Sogou WeChat search) +Read: Exa crawling (primary) / Camoufox stealth browser (optional) +Search: Exa web_search with includeDomains mp.weixin.qq.com """ import shutil @@ -10,11 +10,25 @@ import subprocess from .base import Channel +def _exa_available() -> bool: + mcporter = shutil.which("mcporter") + if not mcporter: + return False + try: + r = subprocess.run( + [mcporter, "config", "list"], + capture_output=True, text=True, timeout=5, + ) + return "exa" in r.stdout.lower() + except Exception: + return False + + class WeChatChannel(Channel): name = "wechat" description = "微信公众号文章" - backends = ["wechat-article-for-ai (Camoufox)", "miku_ai (搜狗搜索)"] - tier = 2 + backends = ["Exa via mcporter (搜索+阅读)", "Camoufox (可选阅读)"] + tier = 0 def can_handle(self, url: str) -> bool: from urllib.parse import urlparse @@ -22,36 +36,28 @@ class WeChatChannel(Channel): return "mp.weixin.qq.com" in d or "weixin.qq.com" in d def check(self, config=None): - has_read = False - has_search = False - + has_exa = _exa_available() + has_camoufox = False try: import camoufox # noqa: F401 - has_read = True + has_camoufox = True except ImportError: pass - try: - import miku_ai # noqa: F401 - has_search = True - except ImportError: - pass - - if has_read and has_search: - return "ok", "完整可用(搜索 + 阅读公众号文章)" - elif has_read: - return "ok", "可阅读公众号文章(URL → Markdown)。安装 miku_ai 可解锁搜索:pip install miku_ai" - elif has_search: + if has_exa and has_camoufox: + return "ok", "完整可用(Exa 搜索 + Exa/Camoufox 阅读公众号文章)" + elif has_exa: + return "ok", ( + "通过 Exa 搜索和阅读微信公众号文章(免费,无需额外配置)。" + "可选安装 Camoufox 获得更好的全文阅读效果。" + ) + elif has_camoufox: return "warn", ( - "可搜索公众号文章但无法阅读全文。安装阅读工具:\n" - " pip install camoufox[geoip] markdownify beautifulsoup4 httpx mcp" + "Camoufox 可阅读公众号文章,但搜索功能需要 Exa。" + "运行 `agent-reach install --env=auto` 安装 Exa。" ) else: return "off", ( - "需要安装微信公众号工具:\n" - " # 阅读(URL → Markdown):\n" - " pip install camoufox[geoip] markdownify beautifulsoup4 httpx mcp\n" - " # 搜索(关键词 → 文章列表):\n" - " pip install miku_ai\n" - " 详见 https://github.com/bzd6661/wechat-article-for-ai" + "需要 mcporter + Exa MCP 来搜索和阅读微信公众号文章。\n" + "运行 `agent-reach install --env=auto` 安装。" ) diff --git a/agent_reach/skill/references/web.md b/agent_reach/skill/references/web.md index ae5ed02..42f6223 100644 --- a/agent_reach/skill/references/web.md +++ b/agent_reach/skill/references/web.md @@ -31,28 +31,27 @@ mcporter call 'web-reader.webReader(url: "https://example.com", return_format: " ## 微信公众号 / WeChat Articles -**注意**: 微信公众号文章无法用 Jina Reader 或 curl 直接读取,必须使用专用工具。 +### 搜索公众号文章(通过 Exa) -### 搜索文章 (miku_ai) - -```python -python3 -c " -import asyncio -from miku_ai import get_wexin_article -async def s(): - for a in await get_wexin_article('query', 5): - print(f'{a[\"title\"]} | {a[\"url\"]}') -asyncio.run(s()) -" +```bash +# 搜索微信公众号文章 +mcporter call 'exa.web_search_exa(query: "搜索关键词", numResults: 5, includeDomains: ["mp.weixin.qq.com"])' ``` -### 读取文章 (Camoufox - 绕过微信反爬) +### 阅读公众号文章全文(通过 Exa) + +```bash +# 抓取文章全文 +mcporter call 'exa.crawling_exa(urls: ["https://mp.weixin.qq.com/s/ARTICLE_ID"], maxCharacters: 10000)' +``` + +### 可选:Camoufox 阅读(反爬更强) ```bash cd ~/.agent-reach/tools/wechat-article-for-ai && python3 main.py "https://mp.weixin.qq.com/s/ARTICLE_ID" ``` -> **重要**: 微信文章必须用 Camoufox 读取,其他方法会失败。 +> **注意**: Jina Reader 无法读取微信文章(被 CAPTCHA 拦截),推荐用 Exa。 ## RSS (feedparser) @@ -72,6 +71,6 @@ for e in feedparser.parse('FEED_URL').entries[:5]: |-----|---------| | 通用网页 | Jina Reader (`curl r.jina.ai`) | | 需要图片/格式控制 | web-reader MCP | -| 微信公众号 | Camoufox (读取) + miku_ai (搜索) | +| 微信公众号 | Exa (搜索+阅读) / Camoufox (可选阅读) | | RSS 订阅 | feedparser | | 微博/知乎等 | Jina Reader |