1实现原理 · 为什么它能做到
单帖纯文本首选路径是免登录、免 key 直接 curl fxtwitter 镜像 API,全文取自 tweet.text(文档注明 full_text 键不存在)——这一路径零凭证、零配置,2026-08-30 起取代 Jina 成为默认
works direct, and returns the **full note_tweet body in `tweet.text`** (the `full_text` key does not exist; a 2,324-char long-form announcement came back complete):
X Articles(长文带图)主路径由 fetch_article.py 承接:先用 `uv run --with twitter-cli` 现场安装并执行 PyPI 包 twitter-cli 的 `twitter article` 子命令,拿到含 author/metrics/articleText 的结构化 YAML
def run_twitter_cli(url: str) -> dict: """Fetch article data using twitter-cli via uv run.""" cmd = ["uv", "run", "--with", "twitter-cli", "twitter", "article", url]
正文(含图)经 Jina Reader(r.jina.ai)抓取:有 JINA_API_KEY 就带 Bearer,没有就匿名;随后按 'Markdown Content:' 标记切出正文,若 Jina 失败则回退用 twitter-cli 返回的 articleText
api_key = os.getenv("JINA_API_KEY", "") jina_url = f"https://r.jina.ai/{url}" cmd = ["curl", "-s", jina_url] if api_key: cmd.extend(["-H", f"Authorization: Bearer {api_key}"])
图片本地化是脚本核心增值:从抓回的 Markdown 里用正则抽出 pbs.twimg.com/media 链接 → 去重并统一改为 ?format=jpg&name=large → curl 逐个下载到 attachments/日期-作者-标题/ → 再把正文中的远程图 URL 正则替换为本地相对路径
pattern = r'https://pbs\.twimg\.com/media/[^\s\)"\']+'
输出纪律:YYYY-MM-DD-标题.md(含 YAML frontmatter:source/author/date/likes/retweets/bookmarks)+ 同名附件目录;日期取 createdAtLocal 前 10 位,标题与作者经 sanitize_filename 消毒截断 60 字符
md = f"""--- source: {source_url} author: {author.get("name", "")} date: {date_str} likes: {metrics.get("likes", 0)}
Jina 文本模式作为旁路:fetch_tweet.py(单条、硬性要求 JINA_API_KEY、仅 HTTPS)与 fetch_tweets.sh(bash 批量循环,正则允许 http/https)直接 curl r.jina.ai 并透传 Bearer
for url in "$@"; do if [[ ! "$url" =~ ^https?://(x\.com|twitter\.com)/ ]]; then
2核心能力
3外部依赖
| 类型 | 依赖 |
|---|---|
| cli | curl |
| cli | uv (Python 包管理器) |
| cli | python3(含内联 -c 解析) |
| package | twitter-cli(PyPI,uv 现场安装并执行 twitter article 子命令,未 pin 版本) |
| package | pyyaml |
| api | Jina Reader API |
| network | fxtwitter 镜像 API |
| network | Twitter 图片 CDN(图片下载目标) |
| network | x.com / twitter.com(被抓取目标,经 fxtwitter/Jina 代理访问) |
4风险提醒 风险提醒:橙色 · 评估后使用
- 运行时自动安装并执行未 pin 的第三方 PyPI 包 twitter-cli(uv run --with),代码在审计范围之外——供应链/可复现性面 — fetch_article.py: `cmd = ["uv", "run", "--with", "twitter-cli", "twitter", "article", url]`
- JINA_API_KEY 环境变量凭证读取且被外发(fetch_tweet.py/fetch_tweets.sh 硬性要求) — 外发目的地唯一(r.jina.ai 本体)、无硬编码密钥,但 key 在宿主环境中存在被注入指令诱导滥用的可能(宿主权限约束面)
- 抓取类技能固有:远程正文原样写入 .md,宿主随后让 Claude 读取时正文可携带 prompt-injection;对 x.com 高频抓取有平台风控与 ToS 灰区(文档自证第三方滥用已致匿名 Jina 被全局 ban) — SKILL.md: 'anonymous `r.jina.ai` access to x.com gets **403-globally-banned for hours** when *third-party* users abuse the domain'
- 健壮性细节:脚本内 curl 无 --max-time、图片下载串行无上限、URL 仅前缀白名单(bash 版放行 http://) — 仅 SKILL.md fxtwitter 配方有 20s 超时;fetch_tweets.sh: `^https?://(x\.com|twitter\.com)/`
5第二遍独立确认
- [ok] fxtwitter API(api.fxtwitter.com)调用点真实存在 — SKILL.md fxtwitter 段内联 curl 配方原文命中;文档自述 2026-08-30 实测过 2,324 字符 note_tweet 完整返回。仅验证调用点,端点当前可达性未在线复核
- [ok] Jina r.jina.ai 调用点真实存在 — 三个脚本各自命中:fetch_tweet.py `jina_api_url = f"https://r.jina.ai/{url}"`、fetch_tweets.sh `curl -s "https://r.jina.ai/${url}"`、fetch_article.py run_jina_api;Bearer 头与 JINA_API_KEY 读取逐处对上
- [ok] twitter-cli 依赖真实存在(uv run --with) — fetch_article.py run_twitter_cli 的 argv 原文命中;SKILL.md Quick Start 另以 `uv run --with pyyaml` 启动脚本,与 parse_yaml_output 的 yaml 导入一致
- [ok] pbs.twimg.com 图片下载路径真实存在且仅此 CDN — extract_image_urls 正则仅匹配 pbs\.twimg\.com/media/ 前缀;download_images 用 curl -sL 落盘。未发现其他图片域名
- [ok] JINA_API_KEY 读取点全覆盖、无硬编码密钥 — grep JINA_|sk- 于 twitter-reader/ 命中仅 3 处 env 读取(无字面量);全仓库 CHANGELOG 记录 2026-01-05 前后『Removed hardcoded API keys』。SKILL.md 所述『shared key 402 余额尽』系作者侧市场共享 key,仓库内无对应字符串
- [ok] URL 校验形态:前缀白名单而非权威解析 — fetch_tweet.py/fetch_article.py 用 startswith(("https://x.com/","https://twitter.com/"));fetch_tweets.sh 用正则 ^https?://(x\.com|twitter\.com)/。三处均要求主机后紧跟 /,可挡 https://x.com.evil.com 型主机混淆;bash 版放行 http:// 与文档『HTTPS only』表述存在出入(py 版严格)
- [ok] 无隐藏脚本/无混淆/无隐蔽外发 — 目录仅 SKILL.md + 3 脚本 + .security-scan-passed 标记;脚本全部为列表式 subprocess,无 shell=True/eval/curl 之外的网络动词;.security-scan-passed 为纯文本记录,无执行作用
- [ok] 功能声明与代码能力相符性 — 『长文带图 + 元数据 + 自动下载 + Markdown』在 fetch_article.py 中逐项落实;但核心卖点依赖第三方间歇服务:Jina 匿名被全局 ban 时正文只剩 twitter-cli 的 articleText 兜底(可能不含图),文档已如实标注『Preferred over Jina…』仅针对有图场景——无夸大但有外部依赖边界
6结论
6e441b1396143142…63a65c1fcc