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 を読み込んでぐるぐる回せば終わり。