1仕組みと動作原理
単一投稿のプレーンテキスト取得の優先ルートは、ログイン不要・APIキー不要でfxtwitterミラーAPIを直接curlし、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を許容)はr.jina.aiを直接curlしBearerトークンを透過します。
for url in "$@"; do if [[ ! "$url" =~ ^https?://(x\.com|twitter\.com)/ ]]; then
2コア機能
3外部依存関係
| Kind | Dependency / Endpoint |
|---|---|
| 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推奨統制措置と判定根拠
- scripts/: ローカルスクリプトまたはコマンドの実行: scripts/fetch_article.py —— `uv run --with pyyaml python scripts/fetch_arti
- scripts/ 或 SKILL.md: 外部言語パッケージ依存の動的インストールの宣言
- 网络端点: 外部ネットワークアクセスの宣言: https://api.fxtwitter.com/<user>/status/<id>(APIキー不要のミラー、SKILL.mdのfxtwitterセクション)
- 本地工作目录: ファイルの読み書きと成果物の出力: fetch_article.py: <output_dir>/YYYY-MM-DD-<safe_title>.md および <output_dir>/a への書き込み
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…