[{"data":1,"prerenderedAt":561},["ShallowReactive",2],{"content-/kindle-pc-capture-app":3,"all-pages-for-dir":559,"og-image-/kindle-pc-capture-app":560},{"id":4,"title":5,"body":6,"category":538,"description":539,"extension":540,"meta":541,"navigation":542,"ogImage":543,"path":544,"project_name":545,"published":546,"publishedAt":547,"seo":548,"stem":549,"tags":550,"todo":543,"unpublished":546,"updatedAt":543,"__hash__":558},"pages/2026-06/2026-06-23/kindle-pc-capture-app.md","Kindle for PC デスクトップ版から全ページキャプチャ＋OCR取り込みパイプラインを組んだ日",{"type":7,"value":8,"toc":523},"minimark",[9,13,25,30,33,36,93,100,111,118,121,140,151,158,165,182,185,199,209,213,216,219,222,271,286,289,314,321,324,327,342,352,355,359,362,393,396,400,411,438,445,448,451,487,490,493,513],[10,11,12],"p",{},"Kindle for PC（デスクトップ版）で開いた本を、ページ送りからスクリーンショット、OCR、Turso DB 投入まで一気通貫で流すパイプラインを組んだ。Cloud Reader で開けない本（固定レイアウトの学術書や、PC アプリにしか降りてこない本）に届かせるための回り道。",[10,14,15,16,20,21,24],{},"途中で ",[17,18,19],"code",{},"C:\\Users\\numbe\\.git"," を踏み抜く事故と、OpenAI API キーを ",[17,22,23],{},"env | grep"," で漏らす事故も同時に処理することになって、最後はだいぶ疲れた。",[26,27,29],"h2",{"id":28},"まず本文-dom-を直接取れないか足掻く","まず本文 DOM を直接取れないか足掻く",[10,31,32],{},"きっかけは「OCR の前に、Kindle アプリの中の本文テキストがそのまま取れたら無駄が省ける」という素朴な期待。アプリの裏側を Claude Code に掘らせた。",[10,34,35],{},"順番にこうなった。",[37,38,39,43,54,68,82],"ul",{},[40,41,42],"li",{},"ネイティブ Windows アプリだから DOM は無いと最初に整理された",[40,44,45,46,49,50,53],{},"UIA で覗くと ",[17,47,48],{},"ReadingArea"," の構造とフッターの ",[17,51,52],{},"Page X of Y"," までは取れる。ただし本文テキストは降りてこない",[40,55,56,57,60,61,60,64,67],{},"Kindle for PC の中身を漁ったら ",[17,58,59],{},"EBWebView/","、",[17,62,63],{},"appBundle.js",[17,65,66],{},"bridge.js"," といったファイルが出てきた。一瞬「React/Webpack の Web アプリで、Chromium 系の埋め込みブラウザで動いてる」と確定したように見えた",[40,69,70,71,74,75,78,79,81],{},"そのあと ",[17,72,73],{},"Qt5Core.dll"," / ",[17,76,77],{},"LibWebCore.dll"," が見つかり「Qt + WebKit 系か」と反転。さらに ",[17,80,66],{}," の中身で再反転",[40,83,84,85,60,89,92],{},"最終的に ",[86,87,88],"strong",{},"旧 Kindle（Legacy）は Qt + WebKit + KRF（Kindle Reader Framework）",[86,90,91],{},"新 Kindle（MSIX）は React Native for Windows + XAML ネイティブ UI（Hermes bytecode のバンドル magic で確定）"," という結論に着地した",[10,94,95,96,99],{},"新 Kindle に至っては XAML ネイティブで描画していて、そもそも DOM が存在しない。",[17,97,98],{},"WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS"," を設定して CDP に繋いだら旧 Kindle のライブラリ画面までは見えたが、リーダー領域は最後まで空のまま。",[10,101,102,103,106,107,110],{},"ここで OCR 路線に確定。Cloud 版で動かしている既存の「読み解く-Kindle」スキルと同じ出力形式（",[17,104,105],{},"~/Downloads/kindle-captures/\u003CASIN>/page_NNNN.png"," ＋ ",[17,108,109],{},"done.json","）に揃える方針にした。",[26,112,114,115,117],{"id":113},"事故その1cusersnumbegit-がいた","事故その1：",[17,116,19],{}," がいた",[10,119,120],{},"ここで横やり。VS Code の Git タブが「1万件変更」と言ってきた。",[10,122,123,124,127,128,131,132,135,136,139],{},"調べていくと、犯人はホームディレクトリ直下の ",[17,125,126],{},".git","。いつ作ったか覚えがないが ",[17,129,130],{},"C:/Users/numbe/.git"," がいて、",[17,133,134],{},"Git_repo/"," 配下の各プロジェクトの ",[17,137,138],{},".git/objects/"," の中身が、親リポジトリから見ると未追跡ファイルとして10K件積み上がっていた、という構図。",[10,141,142,143,146,147,150],{},"最初の対処は素直に削除する方針で進めたが、PowerShell に ",[17,144,145],{},"-rf"," が無くてエラー。最終的に ",[17,148,149],{},"mv C:/Users/numbe/.git C:/Users/numbe/.git.bak"," でリネームして無効化。万一中身が必要になっても戻せる形にして、後始末を終わらせた。",[10,152,153,154,157],{},"ユーザー（自分）がやったのは「VS Code が 1 万件と言ってるんだけど」と違和感を投げたことと、",[17,155,156],{},"mv"," を一発打ったこと。原因の特定と回避手順は Claude Code に組み立てさせた。",[26,159,161,162,164],{"id":160},"事故その2openai-api-キーが-env-grep-で漏れた","事故その2：OpenAI API キーが ",[17,163,23],{}," で漏れた",[10,166,167,168,171,172,181],{},"OCR 路線が決まった直後、Qt WebKit Inspector を起動できないか調査していたとき、Claude が ",[17,169,170],{},"env | grep -iE \"qt|...\""," を打った。",[86,173,174,177,178,180],{},[17,175,176],{},"qt"," が 2 文字なので、文字列の中にたまたま ",[17,179,176],{}," を含む環境変数の値まで全部マッチする。"," OpenAI API キーが画面に流れた。",[10,183,184],{},"Claude 側から「APIキー漏洩しました」と即座に申告が出た。LINE の通知トークンも一緒に流れていた。",[37,186,187,190,193],{},[40,188,189],{},"OpenAI 側はキーをリボーク済み。",[40,191,192],{},"LINE は通知トークンの単体漏れなので、できることが限定的（自分のチャネルへの通知が打てる程度）。実害評価だけ済ませて止めた。",[40,194,195,196,198],{},"後始末として、レジストリから ",[17,197,98],{}," も完全削除させた。",[10,200,201,204,205,208],{},[17,202,203],{},"grep"," の 2 文字パターンは危ない、というのを身体で覚えた。次から ",[17,206,207],{},"grep -iE \"qt[a-z_]*key|qt[a-z_]*url\""," のように、隣接する文字も含めて絞らせる癖をつけたい。",[26,210,212],{"id":211},"ocr-路線矢印キー送信から物理マウスクリックへ","OCR 路線：矢印キー送信から「物理マウスクリック」へ",[10,214,215],{},"ここから本筋の実装に戻る。",[10,217,218],{},"最初の設計は素直なもの。「ユーザーがスタートを押す → 自動で先頭ページに戻る → 右矢印キーを送ってページ送り → 末尾までキャプチャ → done.json 書き出し」。CLI と GUI の両方で動くようにした。",[10,220,221],{},"詰まったのは新 Kindle 側のページ送り。",[37,223,224,237,250,261],{},[40,225,226,227,230,231,60,234],{},"新 Kindle MSIX は ",[86,228,229],{},"SendInput でのキー入力を完全にブロック","してくる。",[17,232,233],{},"SetForegroundWindow FAILED",[17,235,236],{},"SendInput VK_RIGHT returned: 0",[40,238,239,74,242,245,246,249],{},[17,240,241],{},"PostMessage WM_KEYDOWN",[17,243,244],{},"SendMessage"," も無視。",[17,247,248],{},"DoDefaultAction()"," も効かない",[40,251,252,253,256,257,260],{},"マウスの方も ",[17,254,255],{},"mouse_event","（旧 API）は無視。",[17,258,259],{},"SendInput"," でマウスイベントを送る方式に切り替えてもダメに見えた",[40,262,263,264],{},"唯一効いたのが、",[86,265,266,267,270],{},"ReadingArea 右端 100px の ",[17,268,269],{},"page-chevron-container-right"," 領域への物理クリック",[10,272,273,274,277,278,281,282,285],{},"ここで切り分けに苦労した。「クリックは効いているのにページが進まない」と思い込んだ瞬間が何度かあったが、実際には ",[86,275,276],{},"UIA キャッシュが古い値を返していて、ページは進んでいた","。スクショを撮って目視で ",[17,279,280],{},"Location"," を確認したら、自分の ",[17,283,284],{},"read_page_status"," が返す値より先に進んでいた、という瞬間がブレイクスルーになった。",[10,287,288],{},"最終的にこういう構図に落ち着いた。",[37,290,291,294,297,306],{},[40,292,293],{},"スタートと書籍切り替えは自分（人間）がやる。新 Kindle はキーもクリックも synthetic input を弾いてくるので、Library 画面の本表紙クリックや Aa 設定（1列・Light・先頭）は手で済ませる",[40,295,296],{},"キャプチャ開始のボタンを押したら、あとは Python スクリプトが ReadingArea 右端をクリックしてページを送り続ける",[40,298,299,300,74,302,305],{},"フッターの ",[17,301,52],{},[17,303,304],{},"Location X of Y"," を UIA で読み、末尾に達するか同じ位置で 5 回連続止まったら停止",[40,307,308,310,311,313],{},[17,309,105],{}," を吐いて、最後に ",[17,312,109],{}," を書く",[10,315,316,317,320],{},"ページ送りの間隔は 1.5 秒で始めて、ユーザー判断で 1.0 秒まで縮めた。固定レイアウト本は 1.0 秒で問題なく走ったが、リフロー本は 1.0 秒だとレンダリングが追いつかず ",[17,318,319],{},"no_advance"," で即停止することがあって、停止判定を「3 回連続で位置変化なし」に緩めた。",[26,322,323],{"id":323},"ローマ数字ページの罠",[10,325,326],{},"何冊か撮っているうちに、税理士向けの実用書系（前付に i, ii, iii, iv... のローマ数字、本文に 1, 2, 3... のアラビア数字）で詰まった。",[37,328,329,339],{},[40,330,331,334,335,338],{},[17,332,333],{},"_PAGE_PATTERN_EN"," が ",[17,336,337],{},"Page\\s+\\d+\\s+of\\s+\\d+"," でアラビア数字しか拾わない",[40,340,341],{},"前付の i, ii を取れないまま「進んでないと判定して停止」していた",[10,343,344,345,347,348,351],{},"修正は単純で、ローマ数字（大文字／小文字両対応）も ",[17,346,52],{}," と同じ枠で拾えるようにしてから、",[86,349,350],{},"停止判定はアラビア数字と location 形式の本文ページに限定","することにした。ローマ数字のページは「撮るだけ、止めない」。",[10,353,354],{},"結果、修正後の走行で「前付 i〜viii ＋ 本文 1〜299 ＝ 307 枚、11.5 分、status: completed」が出た。",[26,356,358],{"id":357},"役割分担自分が判断する係python-と-claude-が回す係","役割分担：自分が判断する係、Python と Claude が回す係",[10,360,361],{},"今回はっきり線が引けた。",[37,363,364,374,380],{},[40,365,366,369,370,373],{},[86,367,368],{},"自分",": Kindle で本を開く、Aa で 1 列・Light・先頭ページを揃える、GUI の START を押す、撮れた PNG を 3 枚ほど目視で確認する、",[17,371,372],{},"B009U4ZX1I"," 池上彰のお金の学校みたいに「PC アプリでも開けない本」を発見してフラグを足す指示を出す",[40,375,376,379],{},[86,377,378],{},"Python スクリプト",": ReadingArea 右端を物理クリックしてページを送り、UIA でフッターを読んで終端判定、PNG と done.json を吐く",[40,381,382,385,386,74,389,392],{},[86,383,384],{},"Claude Code",": 仕様変更（停止判定の緩和、ローマ数字対応、座標調整）、OCR を yomitoku で回し、md と figures を整理して Turso の ",[17,387,388],{},"kindle_highlights",[17,390,391],{},"book_chunks"," 系に投入、FTS の検索テストまで一気通貫",[10,394,395],{},"「人間が判断する係、AI が実行する係」の構図そのまま。ページ送りが効いてないように見える瞬間や、座標がズレた瞬間に違和感を拾うのは自分の役目で、修正の手は Claude が動かす。",[26,397,399],{"id":398},"サンプル本-16-冊とdesktop-app-で開ける本のフラグ整理","サンプル本 16 冊と「Desktop App で開ける本」のフラグ整理",[10,401,402,403,406,407,410],{},"撮影パイプラインが安定したあと、Turso の ",[17,404,405],{},"kindle_library"," テーブルで「Cloud Reader で開けなかった本」を洗い直した。",[17,408,409],{},"excluded_reason"," 列に過去の Cloud Reader 失敗理由が積んであって、これが Desktop App ルートの取り込み候補リストになる。",[37,412,413,419,426,429],{},[40,414,415,418],{},[17,416,417],{},"is_sample = 1"," のサンプル本 16 冊が混ざっていたので、これは買い直さない限り対象外として除外",[40,420,421,422,425],{},"Kindle Unlimited で借りているだけの本（",[17,423,424],{},"is_kindle_unlimited = 1","）も、返却済み／返却予定があるので原則除外",[40,427,428],{},"Cloud Reader 不可・購入済み・未処理の本 16 冊 → 14 冊 → 7 冊と絞り込んだ",[40,430,431,432,434,435,437],{},"池上彰のお金の学校（",[17,433,372],{},"）は PC アプリでも開けなかった。新しい ",[17,436,409],{}," タグ「Desktop App でも未サポート（モバイル専用）」を立てた",[10,439,440,441,444],{},"撮影計画書は ",[17,442,443],{},"book-knowledge-base/memo/2026-06-23/kindle-desktop-bulk-capture-plan.md"," に固定して、明日以降の自分への引き継ぎはこのファイルに集約する形にした。",[26,446,447],{"id":447},"今日撮れた本",[10,449,450],{},"実走行できたのはこのあたり。",[37,452,453,459,465,478],{},[40,454,455,458],{},[86,456,457],{},"システムの科学 第3版（ハーバート・A・サイモン）",": 415 ページ、140 枚、6 分 20 秒。最初の本格走行。1 クリックで Kindle 内部のページカウンタが 2〜3 進む現象に気づいて、1 スプレッド ≒ 1 内容で問題ないと結論づけた",[40,460,461,464],{},[86,462,463],{},"税理士のためのプログラミング",": 221 ページ、220 枚、11 分。固定レイアウト本のリファレンス挙動として安定",[40,466,467,470,471,473,474,477],{},[86,468,469],{},"新・現代会計入門 第3版",": リフロー本。Location 10689 のうち 377 枚を撮影。",[17,472,319],{}," の停止判定を 5 回 → 3 回に緩めた修正と、座標を ",[17,475,476],{},"right - 30","（chevron 領域内）に戻した修正がここで効いた",[40,479,480,483,484,486],{},[86,481,482],{},"ソフトウェア開発失敗集（B0CW1KZ5N3）",": 425 ページ、206 枚、11.85 分。",[17,485,424],{}," と判明したので扱いを継続検討に回した",[10,488,489],{},"OCR と DB 投入は最初の「システムの科学」だけ通して、Step C（mv → yomitoku OCR → DB 投入 → FTS 確認 → restructure-book サブエージェント）が動くことを確認した。残りはまとめて OCR バッチで流す予定。",[26,491,492],{"id":492},"一日の終わりに残ったもの",[37,494,495,498,501,507,510],{},[40,496,497],{},"Kindle for PC（旧／新両方）の中身がどうなっているか、UIA／CDP／物理マウスのどれが効くかが頭に入った",[40,499,500],{},"ローマ数字ページや、Location 形式のフッター（リフロー本）も扱える形になった",[40,502,503,504,506],{},"ホームディレクトリ直下の ",[17,505,126],{}," という地雷を1個踏み抜いて回避手順を学んだ",[40,508,509],{},"環境変数を雑に grep してはいけない、という痛い教訓を 1 件追加した",[40,511,512],{},"翌日に積む候補のリストが計画書に整理された",[10,514,515,518,519,522],{},[17,516,517],{},"memo/"," に過去経緯の HTML、",[17,520,521],{},"book-knowledge-base/memo/2026-06-23/"," に撮影計画書を残して終わり。明日は撮影フェーズの残り 6 冊を片付けてから、まとめて yomitoku を走らせる。",{"title":524,"searchDepth":525,"depth":525,"links":526},"",2,[527,528,530,532,533,534,535,536,537],{"id":28,"depth":525,"text":29},{"id":113,"depth":525,"text":529},"事故その1：C:\\Users\\numbe\\.git がいた",{"id":160,"depth":525,"text":531},"事故その2：OpenAI API キーが env | grep で漏れた",{"id":211,"depth":525,"text":212},{"id":323,"depth":525,"text":323},{"id":357,"depth":525,"text":358},{"id":398,"depth":525,"text":399},{"id":447,"depth":525,"text":447},{"id":492,"depth":525,"text":492},"dev","DOM抽出を諦めてOCR路線に倒し、矢印キーやマウスクリックでページ送りしながら本文を全自動で撮る仕組みを組み立てた。途中で .git 事故と APIキー漏洩を踏み抜いた1日の記録。","md",{},true,null,"/kindle-pc-capture-app","book-knowledge-base",false,"2026-06-23T00:00:00.000Z",{"title":5,"description":539},"2026-06/2026-06-23/kindle-pc-capture-app",[551,552,553,554,555,556,557],"kindle","ocr","yomitoku","python","uia","windows","事故対応","v65_s02Oco4l_GCSz-fwKXDhz_fHMF-haIDs-zrz03M",[],"https://log.eurekapu.com/og/blog/kindle-pc-capture-app.png?v=2026-06-23T00%3A00%3A00.000Z&title=Kindle%20for%20PC%20%E3%83%87%E3%82%B9%E3%82%AF%E3%83%88%E3%83%83%E3%83%97%E7%89%88%E3%81%8B%E3%82%89%E5%85%A8%E3%83%9A%E3%83%BC%E3%82%B8%E3%82%AD%E3%83%A3%E3%83%97%E3%83%81%E3%83%A3%EF%BC%8BOCR%E5%8F%96%E3%82%8A%E8%BE%BC%E3%81%BF%E3%83%91%E3%82%A4%E3%83%97%E3%83%A9%E3%82%A4%E3%83%B3%E3%82%92%E7%B5%84%E3%82%93%E3%81%A0%E6%97%A5&author=Kei%20Komatsu&sig=9a22e26748495e03",1782364625461]