きっかけ — 前日の積み残し回収
朝、開口一番で「昨日なんか積み残しがあったよね」と Claude Code に振ったら、Kindle 関連の積み残しが2系統返ってきた。そのうちの一つが「Cloud Reader 一括判定」。前日の夜、判定スクリプトの土台だけ作って、実判定は外(サブエージェント)に投げる構造にしたまま止めていたやつだ。
クラウドリーダーで読める本は、ブラウザのキャプチャだけで OCR パイプラインに乗せられる。逆に「App 必須」になっている本は、デスクトップアプリを手動で立ち上げて画面録画する必要がある。手前で438冊をきっちり分類しておけば、後の撮影作業が機械的に進められる。だから前日の積み残しを今日のうちに片付けたかった。
判定ロジックの確立
最初に判定ロジックの確立から入った。Kindle Capturer 拡張を入れた Chrome で Cloud Reader を開くと、対応本ならページ内に ASIN: + 該当 ASIN の文字列が表示される。これが出れば cr-ok。Kindle App Is Required のテキストが出れば cr-app-required、/ap/signin に飛ばされれば auth-required。3パターンに分岐するだけのシンプルなロジックを Claude Code に固めさせた。
拡張のおかげで「対応本だけ ASIN を埋め込んでくれる」という識別子ができたのが効いた。これがないと「読み込めたか/読み込めなかったか」の境界がふわっとして判定が転びやすい。
5冊バッチで bot 検出を確認
いきなり421冊回すと Amazon 側で bot 検出にハマる可能性がある。まず未判定の ASIN を5件取り出して、3秒 sleep を挟みながら判定させた。
- 5冊すべて cr-app-required、bot 検出なし
5冊全部で App 必須になったのは少し気になったが、ペースは約8秒/冊(navigate + wait_for + sleep)で安定していた。この時点で残り421冊を機械的に回すと約56分。Claude Code のメインループを1時間専有する取引になるが、まあ妥当な範囲だと判断して回し始めた。
22冊判定して cr-ok = 0 — 「判定ロジック自体が間違ってる?」の疑い
途中で evaluate_script 内に async 待機を埋めて2ツール/冊に圧縮するなどの最適化を Claude Code に入れさせながら、判定を続けた。22冊判定したところで気になる事実が出てきた。
cr-ok = 0。22冊連続で App 必須。
これは判定ロジックがバグってる可能性も疑った方が早いんじゃないか、と心の中で警報が鳴り始めた。前日の作業で「Cloud Reader 対応本」として取り込み済みの本があったはずなので、その本に当ててみればロジックの妥当性が確認できる。
並行で試した Playwright + CDP バックグラウンド化が頓挫
判定継続と並行して、「Claude Code のメインループを専有しないで済む方法」を探りに、Python + Playwright で Chrome の CDP に繋ぐスクリプトを書かせて試した。9222 ポートは閉じていて、9223 が Chrome 149 のデバッグポートだった。接続自体はできたが、見えるのは新規タブ1件のみ。
Chrome 136 以降のセキュリティ仕様で、別プロセス(Python + Playwright)から CDP で繋いでも「他のコンテキストの page」にはアクセスできない。つまり、ログイン済みの Cloud Reader タブに Python から触れない。バックグラウンド化の道は塞がれた。
Chrome 144+ なら
chrome://inspect経由の許可接続で同じ Chrome のタブに繋ぐ別ルートはあるが、今回試した Playwright + CDP 経路は使えない、という限定的な結論。「ログイン済み Chrome に外から繋ぐのは全部不可能」と一般化すると次回ハマるので、ここで限定形で固めておく。
判定ロジックを取り込み済みの本に当てて検証
37冊判定して依然 cr-ok = 0 になったところで、判定ロジックの妥当性確認に戻った。前日 cr-ok 確定で取り込み済みだった本の ASIN にロジックを当てさせたら、ちゃんと cr-ok を返した。
判定ロジック自体は壊れていない。今回新規判定した37冊が全部 cr-app-required なのは実態が正しい、ということが確定した。
これが分かってから残りも実判定を続けたかったが、ここで Claude Code から提案が来た。
42冊で打ち切り、残り396冊は一括タグ付け
42冊判定した時点で cr-ok = 0。判定ロジックも検証済み。残り396冊もほぼ全部 cr-app-required で間違いない、という統計的な確度が出ていた。
このまま396冊回すと、
- 実ペース1冊13秒(ツールオーバーヘッド込み)× 396 = 約90分
- context が積み上がり、完走前にコンパクト/上限に当たるリスク
- 仮に cr-ok が紛れていても、後から tags を消して再判定すれば済む(実害が低い)
「残りは一括 cr-app-required タグ付けで完了させる」という選択肢を Claude Code が出してきた。
採用するか判断するのは筆者本人の係なので、自分で「いいよ」と決めた。一括タグ付けを実行。
結果
全438件判定完了(前日までに cr-ok 確定済みのごく少数を除き、今回新規判定した分は全件 cr-app-required)。
つまり、Cloud Reader で機械的にキャプチャできる本は前日までに取り込み済みの分で実質出尽くしていたという結論。残りはデスクトップアプリで手動撮影するルートに乗せるしかない。これは Claude Code との分担で、撮影は筆者本人がやる係。
学び
母集団の手応えが事前予想と外れた
手を動かす前は「438冊もあれば、どこかに cr-ok 対応本が眠っているはず」と無根拠に期待していた。実際は最初に判定済みの本だけが対応本で、残りはほぼ全部 App 必須。事前の期待は単なる期待であって、データの示唆ではない。22冊回した時点で「これは0%で確定だな」と肌感で気づけたのが今回の収穫。
サンプル42で母集団を推定して切り替える判断
「残り396冊を実判定するか、一括タグ付けで終わらせるか」の選択肢は Claude Code が出してきた提案だが、それを採用するかは筆者本人の判断。サンプル42冊・cr-ok = 0・判定ロジック検証済み、という条件が揃った時点では一括切替が妥当だった。AI が選択肢を出してきても、「機械的に全件回す」のか「サンプルで止めて切り替える」のかは人間が決める。
Chrome 149 + Playwright + CDP の限定的な制約
Python + Playwright で別プロセスから CDP に繋いでログイン済み Cloud Reader タブを掴むのは、Chrome 136 以降のセキュリティ仕様で不可だった。ただし Chrome 144+ なら chrome://inspect 経由の許可接続で同じ Chrome のタブに繋ぐ別ルートは存在する(apps/web/CLAUDE.md の Chrome DevTools MCP 節に明記済み)。「ログイン済み Chrome に外から繋ぐのは全部不可能」と一般化しないこと、を自分への教訓として残しておく。
「実判定済み」と「推定タグ付け」を DB レベルで区別しておくべきだった
今回 cr-app-required タグは42冊の実判定と396冊の推定が同じ tag に乗っている。後から「実判定済みだけ抽出したい」とき、tags だけでは区別できない。次に同種の作業をやるときは、cr_app_required_actual と cr_app_required_inferred のように区別しておくと、後悔の総量が減る。
関連
- 同日の OCR バッチ取り込み・ライブラリ整理は別記事に分離(このログには両方混ざっているが、本記事は Cloud Reader 一括判定の部分のみ)
- 次の作業は撮影完了済みの本のデスクトップアプリ撮影。ページ送り方向(rtl/ltr)の自動判定は現状なし、GUI で手動指定する