0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はてな API を Python から利用する

Last updated at Posted at 2025-03-22

Mozilla のブックマークサービス Pocket のブラウザ拡張機能が使用できなくなってしまった。そもそも Pocket 公式のブラウザ拡張のページ1 そのものが消えてしまっている。おそらく Google Chrome 127 から拡張機能の Manifest V2 が使用できなくなった2 ことに伴い、現時点で Manifest V3 に対応する気がない Mozilla はブラウザ拡張を非公開にしてしまったのだろう。

ブラウザ拡張はかなり使っていたので困るが、待っていても対応される気がしないので、ひとまず暫定的にでもブックマークサービスを「はてなブックマーク」へ移行することにした。

データ移行するにあたり Pocket データを CSV エクスポートするのは簡単にできた。3 あとははてなブックマークにインポートするだけで終わり、と思ったらなんとインポート機能が死んでいる。4

仕方ないので API を使って移行するかと思ったのだが、調べたところはてな API は OAuth 1.0 だった。なんてこった。心が折れそうになったが、Python でゴニョゴニョしていたらなんだかんだで動いたのでここにメモしておく。

環境

  • Python 3.13
  • oauthlib 3.2.2

Jupyter Notebook で作業した。

アクセストークンを入手するまで

以下にいろいろと Python コードを書いているが、この公式ドキュメントに従ってやっているだけではある。

アプリケーションを作る

割愛。

初期設定

使うライブラリを読み込む。

from urllib.request import Request, urlopen
from urllib.parse import parse_qs, quote, urlencode
from urllib.error import HTTPError
from oauthlib.oauth1 import Client

ConsumerKey, ConsumerSecret, Scope を指定する。

今回は「ブックマークを追加する」のに write_private 権限が必要であった。

HATENA_OAUTH_CLIENT_KEY = "..."
HATENA_OAUTH_CLIENT_SECRET = "..."
HATENA_OAUTH_SCOPE = ["write_private"]

リクエストトークンを取得する

client = Client(
    client_key=HATENA_OAUTH_CLIENT_KEY,
    client_secret=HATENA_OAUTH_CLIENT_SECRET,
    callback_uri="oob",
)
uri, headers, body = client.sign(
    uri="https://www.hatena.com/oauth/initiate",
    http_method="POST",
    body=f"scope={",".join(HATENA_OAUTH_SCOPE)}",
    headers={"Content-Type": "application/x-www-form-urlencoded"},
)
try:
    req = Request(uri, body.encode(), headers=headers)
    with urlopen(req) as res:
        results = parse_qs(res.read().decode())
        request_token = results["oauth_token"][0]
        request_token_secret = results["oauth_token_secret"][0]
except HTTPError as exc:
    print(f"ERROR: {exc.read().decode()}")
    raise

Verifier を取得する

print(f"https://www.hatena.ne.jp/oauth/authorize?oauth_token={quote(request_token)}")

ここで組み立てた URL に Web ブラウザでアクセスする。権限リクエストを許可する画面が表示される。許可すると「以下のコードをアプリケーションに入力して下さい。」とコードが表示されるので、変数 verifier にいれる。

verifier = "..."

アクセストークンを取得する

client = Client(
    client_key=HATENA_OAUTH_CLIENT_KEY,
    client_secret=HATENA_OAUTH_CLIENT_SECRET,
    resource_owner_key=request_token,
    resource_owner_secret=request_token_secret,
    verifier=verifier,
)
uri, headers, _ = client.sign("https://www.hatena.com/oauth/token")
try:
    req = Request(uri, headers=headers)
    with urlopen(req) as res:
        results = parse_qs(res.read().decode())
        access_token = results["oauth_token"][0]
        access_token_secret = results["oauth_token_secret"][0]
except HTTPError as exc:
    print(f"ERROR: {exc.read().decode()}")
    raise

ようやくアクセストークンが取得できた。

ブックマークを追加する

公式ドキュメントによると、ブックマークを追加するには url だけ指定すればいいらしい。

こんな感じでブックマークを追加できた。

import json


def add_bookmark(url: str):
    client = Client(
        client_key=HATENA_OAUTH_CLIENT_KEY,
        client_secret=HATENA_OAUTH_CLIENT_SECRET,
        resource_owner_key=access_token,
        resource_owner_secret=access_token_secret,
    )
    params = {"url": url, "private": True}
    uri, headers, _ = client.sign(
        uri=f"https://bookmark.hatenaapis.com/rest/1/my/bookmark?{urlencode(params)}",
        http_method="POST",
    )
    try:
        req = Request(uri, method="POST", headers=headers)
        with urlopen(req) as res:
            return json.loads(res.read())
    except HTTPError as exc:
        print(url)
        body = json.loads(exc.read())
        print(f"ERROR: {body}")
        raise
add_bookmark("https://qiita.com/hoto17296/")

あとは Pocket からエクスポートしてきた CSV を読み込んでぐるぐる回せば終わり。

  1. https://getpocket.com/apps/link/pocket-chrome ※ 2025年3月時点で 404 Not Found

  2. 「Google Chrome」で多数の拡張機能が利用不能に--新仕様「Manifest V3」の影響を考察 - ZDNET Japan

  3. Pocket: エクスポート

  4. はてなブックマークのインポート機能を、スパム対策のため一時的に停止します - はてなブックマーク開発ブログ

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?