twitter-reader について
Twitter/X の投稿や長文記事を Markdown として取得するスキルです。テキスト抽出、記事メタデータの取得、画像の自動ダウンロードに対応し、API の制限や拒否応答の扱いも説明します。
主な機能
- 01投稿テキストと記事本文の取得
- 02投稿者とエンゲージメント情報の取得
- 03記事画像のローカル保存
- 04YAML frontmatter 付き Markdown の生成
- 05Jina API による投稿の一括取得
活用シーン
- 01画像付き X 記事の保存
- 02単一投稿のテキスト抽出
- 03投稿 URL の一括取得
- 04PKM 用の記事メタデータの記録
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ daymade/ claude-code-skills --skill twitter-readerインストール後、Claude Code で/twitter-readerを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
scripts/fetch_article.pyfetch_tweet.pyfetch_tweets.sh詳細
Twitter リーダー
メディアを完全にサポートして、Twitter/X の投稿や記事の内容を取得します。
単一の投稿テキストを読む:まず fxtwitter を使用(2026-08-30)
投稿のテキストのみを取得する場合は、fxtwitter のミラー API を優先してください。ログインもキーも不要で、直接利用でき、tweet.text に note_tweet の本文全体が返されます(full_text キーは存在しません。2,324 文字の長文告知も完全な状態で取得できました)。
curl -sS --max-time 20 "https://api.fxtwitter.com/<user>/status/<id>" \
| python3 -c "import json,sys; t=json.load(sys.stdin)['tweet']; print(t['created_at']); print(t['text'])"
replies は返信数であり、返信スレッドではありません。画像付きの X Articles には、以下の fetch_article.py を使用してください。fxtwitter では記事本文を取得できません。
画像付きの X Articles:fetch_article.py
uv run --with pyyaml python scripts/fetch_article.py <article_url> [output_dir]
例:
uv run --with pyyaml python scripts/fetch_article.py \
https://x.com/HiTw93/status/2040047268221608281 \
./Clippings
このスクリプトは以下を行います。
twitter-cliで構造化データ(いいね、リツイート、ブックマーク)を取得しますjina.aiAPI で画像付きのコンテンツを取得します- すべての画像を
attachments/YYYY-MM-DD-AUTHOR-TITLE/にダウンロードします - 画像参照を埋め込んだ完全な Markdown を生成します
- メタデータを含む YAML フロントマターを追加します
メタデータと記事のテキストは twitter-cli から取得し、画像 URL は Jina のリーダーが返す Markdown に含まれています。Jina が拒否した場合(以下のセクションを参照)、スクリプトは標準エラー出力に警告を表示し、twitter-cli のテキストを保持して、Images: 0 と報告します。Markdown 自体に問題はなく、画像が含まれないだけです。目に見える画像がある記事で Images: 0 と表示される場合、それは Jina に拒否されたことを示します。
出力例
Fetching: https://x.com/HiTw93/status/2040047268221608281
--------------------------------------------------
Getting metadata...
Title: 你不知道的大模型训练:原理、路径与新实践
Author: Tw93
Likes: 1648
Getting content and images...
Images: 15
Downloading 15 images...
✓ 01-image.jpg
✓ 02-image.jpg
...
✓ Saved: ./Clippings/2026-04-03-文章标题.md
✓ Images: ./Clippings/attachments/2026-04-03-HiTw93-.../ (15 downloaded)
Jina のリーダーは不安定で、拒否されても成功したように見えます
サードパーティの呼び出し元がドメインを悪用すると、匿名の r.jina.ai による x.com へのアクセスは数時間にわたってブロックされます。このブロックはすべての匿名呼び出し元に適用され、その後自動的に解除されます。この2つの状態は、2026-09-12 に数分の間隔で発生しました。
拒否は失敗のようには見えません。curl は終了コード 0 を返し、本文は JSON のラッパーです。
{"data":null,"code":403,"name":"AbuseAlleviationError","status":40305,
"message":"Anonymous access to domain x.com blocked until <date> ..."}
期限切れまたは残高不足のキーも、"code":402, "name":"InsufficientBalanceError" を含む同じ形式を返します。curl --fail でも、どちらも検出できません。このエンドポイントは、ラッパーを本文に含めたまま HTTP 200 で応答しました。確実な唯一の判定材料は、Jina のリーダーが記事本文の前に付ける Markdown Content: マーカーです。マーカーがなければ記事もありません。fetch_article.py は応答を受け入れる前にこのマーカーを検査するため、拒否を示すラッパーが生成 Markdown に混入するのを防ぎます。
scripts/fetch_tweets.sh と scripts/fetch_tweet.py はどちらも JINA_API_KEY を必要とし、代替ソースがないため、キーの有効期限が切れると動作しなくなります。両方とも同じマーカーを確認し、拒否された場合は明確なエラーを返します。Python 版は出力ファイルを書き込まずに例外を発生させ、シェル版は標準エラー出力に URL を表示して、ゼロ以外の終了コードで終了します。投稿を装ったラッパーを返すことはありません。このリポジトリにはキーは含まれていません。
テキストのみを簡単に取得する場合:
# Single tweet
curl "https://r.jina.ai/https://x.com/USER/status/TWEET_ID" \
-H "Authorization: Bearer ${JINA_API_KEY}"
# Batch fetching
scripts/fetch_tweets.sh url1 url2 url3
機能
完全な記事モード(fetch_article.py)
- ✅ 構造化されたメタデータ(投稿者、日付、エンゲージメント指標)
- ✅ 画像の自動ダウンロード(埋め込みメディアすべて)
- ✅ ローカル画像参照を含む完全な Markdown
- ✅ PKM システム向けの YAML フロントマター
- ✅ X Articles(長文コンテンツ)に対応
シンプルモード(Jina API)
- テキストのみのコンテンツ
- 利用可能な状態が不安定(上記のセクションを参照)。どちらのスクリプトも
JINA_API_KEYを必要とし、代替手段はありません - Jina が応答している間は、テキストをすばやく抽出する用途に使用できます
前提条件
完全な記事モードの場合
uv(Python パッケージマネージャー)- 追加のセットアップは不要です(twitter-cli は自動でインストールされます)
シンプルモード(Jina)の場合
export JINA_API_KEY="your_api_key_here"
# Get from https://jina.ai/
出力構成
output_dir/
├── YYYY-MM-DD-article-title.md # Main Markdown file
└── attachments/
└── YYYY-MM-DD-author-title/
├── 01-image.jpg
├── 02-image.jpg
└── ...
返される内容
完全な記事モード
- YAML フロントマター:ソース、投稿者、日付、いいね、リツイート、ブックマーク
- Markdown コンテンツ:ローカル画像参照を含む記事全文
- 添付ファイル:専用フォルダーにダウンロードされたすべての画像
シンプルモード
- タイトル:投稿者と投稿内容のプレビュー
- URL ソース:元のツイートへのリンク
- 公開時刻:GMT のタイムスタンプ
- Markdown コンテンツ:リモートメディア URL を含むテキスト
対応している URL 形式
https://x.com/USER/status/ID(投稿)https://x.com/USER/article/ID(長文記事)https://twitter.com/USER/status/ID(旧形式)
スクリプト
fetch_article.py
画像のダウンロードに対応した高機能な記事取得ツール:
uv run --with pyyaml python scripts/fetch_article.py <url> [output_dir]
fetch_tweet.py
Jina API を使用するシンプルなテキスト専用取得ツール:
python scripts/fetch_tweet.py <tweet_url> [output_file]
fetch_tweets.sh
複数のツイートを一括取得します(Jina API):
scripts/fetch_tweets.sh <url1> <url2> ...
twitter-cli の 500 件上限は、X ではなくツール側の制限です
このスキルは twitter-cli を通じてメタデータを読み取るため、ツール独自の制限が適用されます。
twitter bookmarks やその他のタイムラインコマンドは、設定の内容にかかわらず 500 件で停止します。この上限はクライアント内のモジュール定数です。
twitter_cli/client.py の _ABSOLUTE_MAX_COUNT = 500 が、クライアントの構築時に min(maxCount, 500) として適用されます。どちらの記述もバージョン 0.8.5 から確認したものです。X のブックマークタイムラインは、これよりはるか先まで取得できます。
誤解しやすい点が 2 つあります。
- ちょうど 500 件で終了した場合、次のカーソルを読み取る段階に到達する前に、独自のカウンターによって処理が停止しています。「プラットフォームが次のページを返さなかった」と「自分のループが終了した」は別の主張であり、証拠となるのは前者だけです。きりのよい数字は、境界ではなく、さらに確認する理由です。
maxCountは設定のrateLimit:セクションの下に置く必要があります。fetch:の下に置くと、クライアントは何も通知せずに無視し、既定値の 200 に戻ります。
さらに先まで取得するには、GraphQL エンドポイントを直接呼び出します。クライアント独自の機能フラグを使う Bookmarks オペレーションを実行し、twitter_cli.parser.parse_timeline_response で解析して、プラットフォームがカーソルを返さなくなるか、同じカーソルを 2 回返すまでページングします。件数ではなく、プラットフォームからのシグナルを基準に停止します。
Jina API からの移行
以前のワークフロー:
curl "https://r.jina.ai/https://x.com/..."
# Manual image extraction and download
新しいワークフロー:
uv run --with pyyaml python scripts/fetch_article.py <url>
# Automatic image download, complete Markdown