単に Qiita API v2 から自分の最新の Qiita 記事を取得する Python スクリプトです。
/authenticated_user/items (認証ありの場合) または /users/{user_id}/items (認証なしの場合) のレスポンスをそのまま JSON ファイルにキャッシュします。
レスポンスには記事本文 (HTML/マークダウン) も含まれます (上記リンク先参照)。
スクリプトを実行すると以下のように出力されます。
$ python qiita_items.py
[INFO] キャッシュファイルを確認します
----- 01 -----
2026-03-10T15:34:59+09:00
Beamer で allowframebreaks フレームのタイトルに「何枚目/何枚中」を表示する
LaTeX, TeX, Beamer
----- 02 -----
2026-03-08T14:38:26+09:00
PuTTY 付属 CLI ツール plink / pscp でリモート処理をバッチ実行する
SSH, Putty, pyenv, plink
(略)
スクリプト
使い方はスクリプト冒頭コメントにありますが、補足します。
- パッケージ
requestsとkeyringが必要です (keyringはアクセストークン管理用なので、別の手段で管理するか、認証なしでしかアクセスしない場合は不要です)。 -
get_items()のデフォルト引数を適宜変更してください。
qiita_items.py
"""
Qiita API から自分の Qiita 記事 (最新 n_item 件) を取得します。
### 使い方
```
python qiita_items.py # キャッシュファイルがあればそこから読み込む
python qiita_items.py -f # 強制的に新規取得する
```
### 備考
Qiita のアクセストークンがあればまず認証ありでリクエストします。
Qiita のアクセストークンがある場合は以下で登録しておいてください。
```
python -c "$(cat <<'EOF'
import keyring
keyring.set_password('token@qiita', 'token', 'YOUR_TOKEN')
EOF
)"
```
Qiita のアクセストークンがあるかどうかは以下で確認してください。
```
python -c "$(cat <<'EOF'
import keyring
token = keyring.get_password('qiita', 'token')
print(token is not None)
EOF
)"
```
"""
from contextlib import suppress
import keyring # 認証なしでしかリクエストしない場合は削れます (該当箇所も削ってください)
import requests
import json
import argparse
import logging
logging.basicConfig(level=logging.INFO, format='[%(levelname)s] %(message)s')
def get_items(
force=False,
n_item=20,
cache_file='cache_qiita_items.json',
user_id='CookieBox26',
):
"""
Qiita API から自分の Qiita 記事 (最新 n_item 件) を取得します。
Args:
force: True ならキャッシュファイルがあっても強制的に新規取得
n_item: 取得する記事数 (Qiita API の仕様上 100 超なら 100 にします)
cache_file: キャッシュファイルパス
user_id: 自分の Qiita ユーザ ID (認証なしリクエストで使用)
"""
items = None
n_item = min(n_item, 100)
if not force:
logging.info('キャッシュファイルを確認します')
with suppress(FileNotFoundError, json.JSONDecodeError):
with open(cache_file, 'r', encoding='utf-8') as f:
items = json.load(f)
if isinstance(items, list):
return items
logging.info('最新の記事を取得します')
params = {'per_page': n_item}
# 認証なしでしかリクエストしない場合はこのブロックを削ってください
token = keyring.get_password('qiita', 'token')
if token is not None:
logging.info('認証ありでリクエストします')
with suppress(requests.RequestException, ValueError):
# https://qiita.com/api/v2/docs#get-apiv2authenticated_useritems
url = 'https://qiita.com/api/v2/authenticated_user/items'
headers = {'Authorization': f'Bearer {token}'}
resp = requests.get(url, headers=headers, params=params)
items = resp.json()
if not isinstance(items, list):
logging.info('認証なしでリクエストします')
# https://qiita.com/api/v2/docs#get-apiv2usersuser_iditems
url = f'https://qiita.com/api/v2/users/{user_id}/items'
resp = requests.get(url, params=params)
items = resp.json()
if not isinstance(items, list):
logging.error('記事の取得に失敗しました')
return None
with open(cache_file, 'w', encoding='utf-8') as f:
json.dump(items, f, ensure_ascii=False, indent=2)
return items
def main():
parser = argparse.ArgumentParser()
parser.add_argument('-f', '--force', action='store_true')
args = parser.parse_args()
items = get_items(args.force)
for i, item in enumerate(items):
print(f'----- {(i + 1):02} -----')
print(item['created_at'])
print(item['title'])
print(', '.join([tag['name'] for tag in item['tags']]))
if __name__ == '__main__':
main()