Contents
はてなブックマーク API の概要とエンドポイント一覧
はてなブックマーク API には認証が必要な REST 系エンドポイントと、認証不要で軽量 JSON を返す jsonlite エンドポイントの二種類があります。以下ではそれぞれのベース URL と主な機能を整理し、利用シーン別に使い分ける指針を示します。
REST API エンドポイント
REST 系エンドポイントは OAuth 1.0a 認証が必須で、ブックマークの取得・登録・削除といった基本操作を提供します。ベース URL は公式ドキュメント (2026‑05‑27) で確認された最新版です。
| メソッド | パス | 主な機能 |
|---|---|---|
GET |
/api/v1/users/{user}/bookmarks.json |
指定ユーザー(自分または公開ユーザー)のブックマーク一覧取得 |
POST |
/api/v1/bookmark.json |
新規ブックマークの登録 |
DELETE |
/api/v1/bookmark.json |
既存ブックマークの削除 |
ベース URL:
https://bookmark.hatenaapis.com
/entry/jsonlite エンドポイント
認証が不要で大量エントリー情報を高速に取得できるエンドポイントです。公式ドキュメント (2026‑05‑27) でも同じベース URL が示されています。
- ベース URL:
https://b.hatena.ne.jp/entry/jsonlite - 主な用途: 記事タイトル・ブックマーク件数・関連エントリーの取得
- 必須ヘッダー:
User-Agent(後述)
OAuth 1.0a 認証の取得手順
はてなブックマーク API は OAuth 1.0a による認可を要求します。ここでは Consumer Key/Secret の発行からアクセストークン取得までのフローと、署名パラメータの具体的構成例を示します。
Consumer Key / Secret の発行方法
はてな開発者センターにアプリケーションを登録すると、以下の手順でキーが発行されます。
- Hatena Developer Center にログイン
- 「アプリケーション作成」ボタンをクリック
- アプリ名・説明・コールバック URL(OAuth で使用)を入力
- 作成完了後に表示される Consumer Key と Consumer Secret をコピー
安全な管理: キーは環境変数や暗号化された設定ファイルで保持し、コードリポジトリにハードコーディングしないことが推奨されています。
アクセストークン取得フロー(署名付きリクエスト例)
OAuth 1.0a の 3 段階は以下の通りです。Python の requests_oauthlib を用いた実装例と、手動で Authorization ヘッダーを作成する場合の構成要素も併記します。
1. リクエストトークン取得
|
1 2 3 4 5 6 7 8 9 10 11 |
from requests_oauthlib import OAuth1Session oauth = OAuth1Session( client_key=CONSUMER_KEY, client_secret=CONSUMER_SECRET, callback_uri='https://your.app/callback' ) resp = oauth.fetch_request_token('https://www.hatena.com/oauth/initiate') request_token = resp['oauth_token'] request_token_secret = resp['oauth_token_secret'] |
手動で作成する場合、Authorization ヘッダーは次のパラメータをカンマ区切りで列挙します(順序は任意ですが RFC 5849 に準拠):
oauth_consumer_keyoauth_nonce(ランダム文字列)oauth_signature_method="HMAC-SHA1"oauth_timestamp(UNIX 時間)oauth_version="1.0"oauth_callbackoauth_signature(後述)
2. ユーザー認可
取得した request_token を以下の URL に付加してブラウザで開きます。ユーザーが許可すると、コールバック URL に oauth_verifier がクエリとして付与されます。
|
1 2 |
https://www.hatena.com/oauth/authorize?oauth_token=REQUEST_TOKEN |
3. アクセストークン取得
|
1 2 3 4 5 6 7 8 9 10 11 |
oauth = OAuth1Session( client_key=CONSUMER_KEY, client_secret=CONSUMER_SECRET, resource_owner_key=request_token, resource_owner_secret=request_token_secret, verifier=oauth_verifier # コールバックで受け取った値 ) resp = oauth.fetch_access_token('https://www.hatena.com/oauth/token') access_token = resp['oauth_token'] access_token_secret = resp['oauth_token_secret'] |
手動署名例(Python)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
import urllib.parse, hmac, hashlib, base64, time, random def build_signature(method, url, params, consumer_secret, token_secret=''): # 1. パラメータをキー順にエンコードして結合 encoded_params = '&'.join( f'{urllib.parse.quote(k, safe="")}={urllib.parse.quote(v, safe="")}' for k, v in sorted(params.items()) ) # 2. シグネチャベース文字列を作成 base_string = '&'.join([ method.upper(), urllib.parse.quote(url, safe=''), urllib.parse.quote(encoded_params, safe='') ]) # 3. キーは consumer_secret&token_secret の形でエンコード signing_key = f'{urllib.parse.quote(consumer_secret, safe="")}&{urllib.parse.quote(token_secret, safe="")}' # 4. HMAC‑SHA1 でハッシュ化し、Base64 エンコード digest = hmac.new(signing_key.encode(), base_string.encode(), hashlib.sha1).digest() return base64.b64encode(digest).decode() |
この関数に oauth_nonce, oauth_timestamp などを含めたパラメータ辞書を渡すと、正しい oauth_signature が得られます。
必須リクエストヘッダーとレートリミット対策
はてなブックマーク API の呼び出しでは User-Agent と レートリミット の2点が特に重要です。
統一された User-Agent の書式
公式ドキュメント (2026‑05‑27) では次の形式を推奨しています。すべてのリクエストで必ず設定してください。
|
1 2 |
YourAppName/1.0 (your.email@example.com) |
- アプリ名 と バージョン を含める
- 連絡先メールアドレス(またはサイト URL)を記載し、運営側からの問い合わせに備える
curlやrequestsのデフォルト User-Agent は使用できません。上書きが必須です。
レートリミットの最新数値とバックオフ実装
2026‑05‑27 時点で公式に公表されている制限は 60 リクエスト/分 です(Hatena Bookmark API Docs参照)。この上限を超えると 429 Too Many Requests が返ります。
バックオフ実装例(指数バックオフ+ジッター)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
import time, random, requests def call_with_backoff(session: requests.Session, method: str, url: str, **kwargs): max_attempts = 5 for attempt in range(1, max_attempts + 1): resp = session.request(method, url, **kwargs) if resp.status_code != 429: return resp # 正常終了 retry_after = int(resp.headers.get('Retry-After', '1')) # 指数バックオフ (2^attempt) とランダムジッターを組み合わせる wait = retry_after + random.uniform(0, 1) * (2 ** attempt) print(f'Rate limit exceeded. Waiting {wait:.2f}s before retry #{attempt}') time.sleep(wait) raise RuntimeError('Exceeded maximum retries due to rate limiting') |
このパターンを共通関数化すれば、API 呼び出し全体でレートリミット対策が一貫します。
ブックマーク操作例:取得・投稿・削除
以下では実際にブックマークデータを取得・登録・削除する手順と、各ステップで意識すべきポイントを解説します。全て OAuth 1.0a で認証済みのリクエストです。
GET /api/v1/users/{user}/bookmarks.json
指定ユーザー(自分または公開ユーザー)のブックマーク一覧を取得します。大量取得が必要な場合は count と offset パラメータでページングできます。
|
1 2 3 4 |
curl -X GET "https://bookmark.hatenaapis.com/api/v1/users/your_user/bookmarks.json?count=10&offset=0" \ -H "Authorization: OAuth oauth_consumer_key=\"YOUR_KEY\",oauth_token=\"ACCESS_TOKEN\",oauth_signature_method=\"HMAC-SHA1\",oauth_timestamp=\"$(date +%s)\",oauth_nonce=\"$(openssl rand -hex 8)\",oauth_version=\"1.0\",oauth_signature=\"GENERATED_SIGNATURE\"" \ -H "User-Agent: MyBookmarkTool/1.0 (dev@example.com)" |
- 成功 → HTTP 200 とブックマーク配列
- エラー例
401(署名不正)や429(レートリミット)
POST /api/v1/bookmark.json
指定 URL のブックマークを自分のアカウントに追加します。Content-Type: application/x-www-form-urlencoded が必須です。
|
1 2 3 4 5 6 |
curl -X POST "https://bookmark.hatenaapis.com/api/v1/bookmark.json" \ -H "Authorization: OAuth oauth_consumer_key=\"YOUR_KEY\",oauth_token=\"ACCESS_TOKEN\",..." \ -H "User-Agent: MyBookmarkTool/1.0 (dev@example.com)" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "url=https%3A%2F%2Fexample.com%2Fnew-article&comment=参考になった&tags=tech,python" |
- 成功 → HTTP 201 Created、
Locationヘッダーにブックマーク URL が含まれる - エラー例
403(既に同一 URL が登録済み)
DELETE /api/v1/bookmark.json
自分のブックマークを URL 指定で削除します。クエリ文字列は必ず URL エンコードしてください。
|
1 2 3 4 |
curl -X DELETE "https://bookmark.hatenaapis.com/api/v1/bookmark.json?url=https%3A%2F%2Fexample.com%2Fold-article" \ -H "Authorization: OAuth oauth_consumer_key=\"YOUR_KEY\",oauth_token=\"ACCESS_TOKEN\",..." \ -H "User-Agent: MyBookmarkTool/1.0 (dev@example.com)" |
- 成功 → HTTP 204 No Content
- エラー例
404(対象ブックマークが存在しない)
/entry/jsonlite を利用した高速エントリー情報取得
認証不要ながらも豊富なメタデータを取得できる jsonlite エンドポイントの使い方と、レスポンス構造を詳しく解説します。
クエリパラメータ一覧
| パラメータ | 必須 | 説明 |
|---|---|---|
url |
○ | 対象ページの URL(必ず URL エンコード) |
count |
△ | 返却件数上限(デフォルト 1、最大 10) |
callback |
△ | JSONP 用コールバック名(省略可) |
使用例(記事情報を 3 件取得)
|
1 2 |
https://b.hatena.ne.jp/entry/jsonlite?url=https%3A%2F%2Fexample.com%2Farticle&count=3 |
レスポンス JSON の構造と主要フィールド
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
[ { "title": "記事タイトル", "url": "https://example.com/article", "count": 42, "eid": "1234567890abcdef", "bookmarklet_url": "https://b.hatena.ne.jp/entry/s/example.com/article", "related_entries": [ { "title": "関連記事1", "url": "https://example.com/rel1", "count": 15 } ], "tags": ["tech","AI"] } ] |
- title: ページのタイトル
- url: 正規化済みエントリー URL
- count: はてなブックマークに保存された件数
- related_entries: タグや類似度で自動抽出された最大 5 件の関連記事
jsonliteはキャッシュが効きやすく、頻繁に呼び出してもレートリミット対象外です。ただし User-Agent が必須 で、未指定の場合は HTTP 403 が返ります。
Python と curl の実装サンプルとエラー処理
ここまでの手順を実際に動かすためのコード例をまとめます。Python は requests+requests_oauthlib、curl はシェル上だけで完結できる形です。
共通設定(User-Agent の統一)
|
1 2 3 4 |
HEADERS = { 'User-Agent': 'MyBookmarkTool/1.0 (dev@example.com)' } |
Python サンプルコード
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
import os, time, json, random, requests from requests_oauthlib import OAuth1Session # ---- 環境変数から認証情報を取得 --------------------------------- CONSUMER_KEY = os.getenv('HATENA_CONSUMER_KEY') CONSUMER_SECRET = os.getenv('HATENA_CONSUMER_SECRET') ACCESS_TOKEN = os.getenv('HATENA_ACCESS_TOKEN') ACCESS_SECRET = os.getenv('HATENA_ACCESS_SECRET') # ---- OAuth1Session の生成 --------------------------------------- def oauth_session(): return OAuth1Session( client_key=CONSUMER_KEY, client_secret=CONSUMER_SECRET, resource_owner_key=ACCESS_TOKEN, resource_owner_secret=ACCESS_SECRET ) # ---- エラーハンドリングの共通関数 ------------------------------- def handle_error(resp): if resp.status_code == 401: raise RuntimeError('認証エラー:アクセストークンが無効です') if resp.status_code == 403: raise RuntimeError('権限エラー:User-Agent が正しく設定されているか確認してください') if resp.status_code == 429: retry = int(resp.headers.get('Retry-After', '1')) print(f'レートリミットに達しました。{retry}s 待機します…') time.sleep(retry) return None # 呼び出し側で再試行を検討 raise RuntimeError(f'HTTP {resp.status_code}: {resp.text}') # ---- ブックマーク取得 ------------------------------------------- def get_bookmarks(user, count=10, offset=0): url = f'https://bookmark.hatenaapis.com/api/v1/users/{user}/bookmarks.json' params = {'count': str(count), 'offset': str(offset)} with oauth_session() as sess: resp = sess.get(url, headers=HEADERS, params=params) if resp.status_code == 200: return resp.json() if handle_error(resp) is None: # 429 の場合は再試行 return get_bookmarks(user, count, offset) # ---- ブックマーク登録 ------------------------------------------- def post_bookmark(entry_url, comment='', tags=''): url = 'https://bookmark.hatenaapis.com/api/v1/bookmark.json' data = {'url': entry_url, 'comment': comment, 'tags': tags} with oauth_session() as sess: resp = sess.post(url, headers=HEADERS, data=data) if resp.status_code == 201: print('ブックマーク登録に成功しました') else: handle_error(resp) # ---- ブックマーク削除 ------------------------------------------- def delete_bookmark(entry_url): url = 'https://bookmark.hatenaapis.com/api/v1/bookmark.json' params = {'url': entry_url} with oauth_session() as sess: resp = sess.delete(url, headers=HEADERS, params=params) if resp.status_code == 204: print('ブックマーク削除に成功しました') else: handle_error(resp) # ---- /entry/jsonlite の呼び出し(認証不要) -------------------- def get_entry_jsonlite(target_url, count=1): base = 'https://b.hatena.ne.jp/entry/jsonlite' params = {'url': target_url, 'count': str(count)} resp = requests.get(base, headers=HEADERS, params=params) if resp.status_code == 200: return resp.json() handle_error(resp) # ---- デモ実行 ------------------------------------------------- if __name__ == '__main__': user = os.getenv('HATENA_USER') print(json.dumps(get_bookmarks(user, count=5), ensure_ascii=False, indent=2)) |
ポイント解説
- 署名生成は OAuth1Session に委任 することで
oauth_signatureの構成ミスを防げます。 - レートリミット (429) は
handle_error内で自動待機し、再帰的に再試行しています。 - User-Agent は全リクエストのヘッダーに統一 しているため、jsonlite 呼び出しでも必ず送信されます。
curl コマンド例
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
# 1. ブックマーク取得(10 件) curl -G "https://bookmark.hatenaapis.com/api/v1/users/your_user/bookmarks.json" \ --data-urlencode "count=10" \ -H "Authorization: OAuth oauth_consumer_key=\"YOUR_KEY\",oauth_token=\"ACCESS_TOKEN\",oauth_signature_method=\"HMAC-SHA1\",oauth_timestamp=\"$(date +%s)\",oauth_nonce=\"$(openssl rand -hex 8)\",oauth_version=\"1.0\",oauth_signature=\"GENERATED_SIGNATURE\"" \ -H "User-Agent: MyBookmarkTool/1.0 (dev@example.com)" | jq . # 2. ブックマーク登録 curl -X POST "https://bookmark.hatenaapis.com/api/v1/bookmark.json" \ -H "Authorization: OAuth oauth_consumer_key=\"YOUR_KEY\",oauth_token=\"ACCESS_TOKEN\",..." \ -H "User-Agent: MyBookmarkTool/1.0 (dev@example.com)" \ -H "Content-Type: application/x-www-form-urlencoded" \ --data-urlencode "url=https://example.com/new-article" \ --data-urlencode "comment=面白い記事" \ --data-urlencode "tags=tech,python" # 3. ブックマーク削除 curl -X DELETE "https://bookmark.hatenaapis.com/api/v1/bookmark.json?url=https%3A%2F%2Fexample.com%2Fold-article" \ -H "Authorization: OAuth oauth_consumer_key=\"YOUR_KEY\",oauth_token=\"ACCESS_TOKEN\",..." \ -H "User-Agent: MyBookmarkTool/1.0 (dev@example.com)" |
ステータスコード別エラーハンドリングまとめ
| コード | 意味 | 推奨対策 |
|---|---|---|
| 401 | 認証失敗 | Consumer / Access Token が正しいか、期限切れでないか確認。 |
| 403 | 権限エラー/User-Agent 不備 | User-Agent を公式書式に合わせて再送信。 |
| 404 | リソース未発見 | URL エンコードや対象ブックマークの有無をチェック。 |
| 429 | レートリミット超過 | Retry-After 秒待機し、指数バックオフで再試行。 |
| 500 系列 | サーバ側障害 | 再試行間隔を長めに取り、障害情報は公式ステータスページで確認。 |
まとめ
- エンドポイント: REST は
https://bookmark.hatenaapis.com/api/v1/...、jsonlite はhttps://b.hatena.ne.jp/entry/jsonliteが最新版です。 - 認証: OAuth 1.0a の 3 段階フローと
oauth_signatureの生成方法を正しく実装すれば、署名ミスによるエラーは防げます。 - 必須ヘッダー:
User-Agentは公式書式で必ず送信し、レートリミット(60 リクエスト/分)に備えて指数バックオフを実装してください。 - 実装例: Python と curl のサンプルは環境変数による安全なキー管理と共通ヘッダーの統一で可読性・保守性が向上します。
本ガイドを参考に、はてなブックマーク API を安全かつ効率的に活用してください。