fix(reddit): switch to Exa-only for search and read, remove proxy dependency

Reddit blocks nearly all non-browser access at IP level (including ISP proxies).
Switch Reddit channel to use Exa exclusively:
- Search: web_search_exa with includeDomains: ["reddit.com"]
- Read: crawling_exa for full post + comments
- check() now verifies Exa availability instead of probing Reddit API
- tier changed from 1 (needs config) to 0 (zero config)
- Removed reddit_proxy from config, CLI, and setup guide
- Updated all docs (README, README_en, install.md, SKILL.md, references)
- Fixed xreach→bird references in references/social.md

Fixes #218, Fixes #222, Fixes #221

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Pnant
2026-03-31 14:21:31 +08:00
parent b4ed28e48f
commit 5d046ecb61
10 changed files with 95 additions and 136 deletions
+22 -24
View File
@@ -1,30 +1,31 @@
# -*- coding: utf-8 -*-
"""Reddit — check connectivity and proxy configuration."""
"""Reddit — search and read via Exa (no direct Reddit API needed)."""
import os
import urllib.request
import shutil
import subprocess
from .base import Channel
_UA = "agent-reach/1.0"
_TIMEOUT = 10
def _reddit_reachable() -> bool:
"""Return True if Reddit JSON API responds with 200 (带 User-Agent)."""
url = "https://www.reddit.com/r/linux.json?limit=1"
req = urllib.request.Request(url, headers={"User-Agent": _UA})
def _exa_available() -> bool:
"""Return True if mcporter is installed and Exa MCP is configured."""
mcporter = shutil.which("mcporter")
if not mcporter:
return False
try:
with urllib.request.urlopen(req, timeout=_TIMEOUT) as resp:
return resp.status == 200
r = subprocess.run(
[mcporter, "config", "list"], capture_output=True,
encoding="utf-8", errors="replace", timeout=5
)
return "exa" in r.stdout.lower()
except Exception:
return False
class RedditChannel(Channel):
name = "reddit"
description = "Reddit 帖子和评论"
backends = ["JSON API", "Exa"]
tier = 1
description = "Reddit 帖子和评论(通过 Exa 搜索和阅读)"
backends = ["Exa via mcporter"]
tier = 0
def can_handle(self, url: str) -> bool:
from urllib.parse import urlparse
@@ -32,13 +33,10 @@ class RedditChannel(Channel):
return "reddit.com" in d or "redd.it" in d
def check(self, config=None):
proxy = (config.get("reddit_proxy") if config else None) or os.environ.get("REDDIT_PROXY")
if proxy:
return "ok", "代理已配置,可读取帖子。搜索走 Exa"
# 实际探测连通性(带 User-Agent,符合 Reddit API 要求)
if _reddit_reachable():
return "ok", "直连可用(JSON API 响应正常)。搜索走 Exa"
return "warn", (
"无代理且 Reddit JSON API 无响应。服务器 IP 可能被封锁。配置代理:\n"
" agent-reach configure proxy http://user:pass@ip:port"
if _exa_available():
return "ok", "通过 Exa 搜索和阅读 Reddit 内容(免费,无需代理)"
return "off", (
"需要 mcporter + Exa MCP。安装:\n"
" npm install -g mcporter\n"
" mcporter config add exa https://mcp.exa.ai/mcp"
)
+7 -36
View File
@@ -186,11 +186,10 @@ def _cmd_install(args):
# Apply explicit flags
if args.proxy:
if dry_run:
print(f"[dry-run] Would configure proxy for Reddit + Bilibili")
print(f"[dry-run] Would configure proxy for Bilibili")
else:
config.set("reddit_proxy", args.proxy)
config.set("bilibili_proxy", args.proxy)
print(f"✅ Proxy configured for Reddit + Bilibili")
print(f"✅ Proxy configured for Bilibili")
# ── Install system dependencies ──
print()
@@ -987,26 +986,9 @@ def _cmd_configure(args):
return
if args.key == "proxy":
config.set("reddit_proxy", value)
config.set("bilibili_proxy", value)
print(f"✅ Proxy configured for Reddit + Bilibili!")
# Auto-test
print("Testing Reddit access...", end=" ")
try:
import requests
resp = requests.get(
"https://www.reddit.com/r/test.json?limit=1",
headers={"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36"},
proxies={"http": value, "https": value},
timeout=10,
)
if resp.status_code == 200:
print("✅ Reddit works!")
else:
print(f"[!] Reddit returned {resp.status_code}")
except Exception as e:
print(f"[X] Failed: {e}")
print(f"✅ Proxy configured for Bilibili!")
print(" Note: Reddit 已改为通过 Exa 访问,无需代理。")
elif args.key == "twitter-cookies":
# Accept two formats:
@@ -1466,20 +1448,9 @@ def _cmd_setup():
print(" 跳过。公开 API 也能用")
print()
# Step 3: Reddit proxy
print("可选】Reddit 代理 — 完整阅读 Reddit 帖子+评论")
print(" Reddit 封锁很多 IP,需要 ISP 代理才能直接访问")
print(" 格式: http://用户名:密码@IP:端口")
current = config.get("reddit_proxy")
if current:
print(f" 当前状态: ✅ 已配置")
else:
proxy = input(" REDDIT_PROXY (回车跳过): ").strip()
if proxy:
config.set("reddit_proxy", proxy)
print(" ✅ Reddit 完整阅读已开启!")
else:
print(" 跳过。仍可通过搜索获取 Reddit 内容")
# Step 3: Reddit — no config needed (uses Exa)
print("信息】Reddit — 通过 Exa 搜索和阅读,无需配置")
print(" 搜索和阅读 Reddit 内容已通过 Exa 自动完成,免费无需代理。")
print()
# Step 4: Groq (Whisper)
-1
View File
@@ -21,7 +21,6 @@ class Config:
# Feature → required config keys
FEATURE_REQUIREMENTS = {
"exa_search": ["exa_api_key"],
"reddit_proxy": ["reddit_proxy"],
"twitter_xreach": ["twitter_auth_token", "twitter_ct0"], # legacy key name; used by bird CLI
"groq_whisper": ["groq_api_key"],
"github_token": ["github_token"],
+29 -44
View File
@@ -1,60 +1,45 @@
# Reddit 代理配置指南
# Reddit 配置指南
## 功能说明
Reddit 封锁了大量服务器 IP,直接访问会返回 403。需要 ISP 代理(Residential/ISP Proxy)才能读取完整的 Reddit 帖子和评论。
**注意**:即使没有代理,也可以通过 Exa 搜索找到 Reddit 内容(只需要配 Exa API key)。代理只是用于读取完整帖子+评论
Reddit 封锁了几乎所有非浏览器的直接访问(包括数据中心和 ISP 代理 IP),JSON API 返回 403
Agent Reach 通过 **Exa** 实现 Reddit 的搜索和阅读功能:
- **搜索**`web_search_exa` + `includeDomains: ["reddit.com"]`
- **阅读完整帖子+评论**`crawling_exa` 读取 Reddit URL 的缓存内容
免费,无需代理,无需 API Key。
## Agent 可自动完成的步骤
1. 检查当前状态
1. 检查 Exa 是否可用
```bash
agent-reach doctor | grep "Reddit"
agent-reach doctor | grep -E "Reddit|Exa"
```
2. 如果用户提供了代理,测试连通性
2. 如果 Exa 未安装,自动安装
```bash
curl -s --proxy "用户提供的代理" \
-H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36" \
"https://www.reddit.com/r/test.json?limit=1" \
-o /dev/null -w "%{http_code}"
npm install -g mcporter
mcporter config add exa https://mcp.exa.ai/mcp
```
返回 200 = 可用,403 = 代理被封,其他 = 配置错误
3. 写入配置
```python
from agent_reach.config import Config
c = Config()
c.set("reddit_proxy", "http://用户名:密码@IP:端口")
或一键安装
```bash
agent-reach install --env=auto
```
## 使用示例
搜索 Reddit 内容:
```bash
mcporter call 'exa.web_search_exa(query: "python best practices", numResults: 5, includeDomains: ["reddit.com"])'
```
阅读完整帖子和评论:
```bash
mcporter call 'exa.crawling_exa(urls: ["https://www.reddit.com/r/python/comments/xxx/"], maxCharacters: 10000)'
```
## 需要用户手动做的步骤
请告诉用户:
> 要完整阅读 Reddit 帖子和评论,需要一个 ISP 代理(约 $3-10/月)。
>
> 推荐代理服务商(选一个就行):
> 1. **Smartproxy** (https://smartproxy.com) — ISP 代理,按流量计费
> 2. **Bright Data** (https://brightdata.com) — 大厂,ISP 代理
> 3. **IPRoyal** (https://iproyal.com) — 便宜,适合入门
> 4. **ProxyEmpire** (https://proxyempire.io) — 有 Reddit 专用代理
>
> 购买时选择:
> - 类型:**ISP Proxy**(不要选 Datacenter,会被封)
> - 地区:**美国**
> - 协议:**HTTP**
>
> 购买后你会得到一个代理地址,格式类似:
> `http://用户名:密码@IP地址:端口号`
>
> 把这个地址发给我就行。
>
> ⚠️ 如果不想花钱,可以跳过。我仍然可以通过搜索引擎找到 Reddit 上的内容,只是不能读完整的帖子和评论。
## Agent 收到代理后的操作
1. 测试代理:用 curl 测试 reddit.com 是否返回 200
2. 如果成功,写入配置:`config.set("reddit_proxy", proxy_url)`
3. 反馈:"✅ Reddit 完整阅读已开启!现在我可以读取 Reddit 帖子和所有评论了。"
4. 如果失败,告诉用户:"❌ 这个代理无法访问 Reddit,请检查代理是否有效,或换一个试试。"
无。Exa 通过 `agent-reach install --env=auto` 自动配置。
+6
View File
@@ -63,6 +63,12 @@ bird search "query" -n 10
# YouTube/B站字幕
yt-dlp --write-sub --skip-download -o "/tmp/%(id)s" "URL"
# Reddit 搜索(通过 Exa,免费无需代理)
mcporter call 'exa.web_search_exa(query: "query", numResults: 5, includeDomains: ["reddit.com"])'
# Reddit 读帖(通过 Exa
mcporter call 'exa.crawling_exa(urls: ["https://www.reddit.com/r/.../comments/.../"], maxCharacters: 10000)'
# V2EX 热门
curl -s "https://www.v2ex.com/api/topics/hot.json" -H "User-Agent: agent-reach/1.0"
```
+18 -13
View File
@@ -35,24 +35,23 @@ mcporter call 'douyin.extract_douyin_text(share_link: "https://v.douyin.com/xxx/
> **无需登录**
## Twitter/X (xreach CLI)
## Twitter/X (bird CLI)
```bash
# 搜索推文
xreach search "query" -n 10 --json
bird search "query" -n 10
# 读取单条推文 (支持 /status/ 和 /article/ URL)
xreach tweet URL_OR_ID --json
bird read URL_OR_ID
# 用户时间线
xreach tweets @username -n 20 --json
bird user-tweets @username -n 20
# 读取完整 thread
xreach thread URL_OR_ID --json
bird thread URL_OR_ID
```
> **需要配置**: `agent-reach configure twitter-auth ...` 或通过环境变量配置。
> 如果 fetch 失败,确保安装了 undici: `npm install -g undici`
## 微博 / Weibo
@@ -136,14 +135,20 @@ user = ch.get_user("Livid")
> **节点列表**: https://www.v2ex.com/planes
## Reddit (公开 API)
## Reddit (通过 Exa)
Reddit 封锁了几乎所有非浏览器访问(包括代理 IP)。搜索和阅读全部通过 Exa 完成,免费且无需代理。
### 搜索 Reddit 内容
```bash
# 获取 subreddit 热门帖子
curl -s "https://www.reddit.com/r/SUBREDDIT/hot.json?limit=10" -H "User-Agent: agent-reach/1.0"
# 搜索
curl -s "https://www.reddit.com/search.json?q=QUERY&limit=10" -H "User-Agent: agent-reach/1.0"
mcporter call 'exa.web_search_exa(query: "your search query", numResults: 5, includeDomains: ["reddit.com"])'
```
> **注意**: 服务器 IP 可能遇到 403 错误。搜索建议使用 Exa 代替,或配置代理。
### 阅读完整帖子和评论
```bash
mcporter call 'exa.crawling_exa(urls: ["https://www.reddit.com/r/SUBREDDIT/comments/POST_ID/TITLE/"], maxCharacters: 10000)'
```
> **零配置**: 只需安装 Exa MCP`agent-reach install --env=auto` 自动完成)。无需代理,无需 API Key。