[{"data":1,"prerenderedAt":545},["ShallowReactive",2],{"content-/2026-04-30-tac-cpa-textbooks-batch-import":3,"all-pages-for-dir":543,"og-image-/2026-04-30-tac-cpa-textbooks-batch-import":544},{"id":4,"title":5,"body":6,"category":524,"description":525,"extension":526,"meta":527,"navigation":528,"path":529,"project_name":530,"published":531,"publishedAt":532,"seo":533,"stem":534,"tags":535,"todo":541,"updatedAt":541,"__hash__":542},"pages/2026-04/2026-04-30/tac-cpa-textbooks-batch-import.md","TAC公認会計士テキスト11冊を書籍ナレッジベースに一括取り込み",{"type":7,"value":8,"toc":512},"minimark",[9,13,17,27,39,49,67,71,91,98,112,116,127,130,134,149,152,250,253,257,264,274,347,354,358,365,372,383,386,417,423,427,437,455,464,468,471,474,485,489,499,505,508],[10,11,5],"h1",{"id":12},"tac公認会計士テキスト11冊を書籍ナレッジベースに一括取り込み",[14,15,16],"p",{},"朝の積み残し（著者取得444件）を片付けてから、TAC公認会計士テキスト【計算】シリーズ11冊（合計3,488ページ）を yomitoku で OCR 化して Turso DB に格納した。さらに章節整理（restructure）を11冊全部に流して、3,167チャンクを約1,000セクションに統合した。途中で Windows の cp932 クラッシュ、DB の idle timeout、Embedded Replica の WAL ロック、shelf の表示0冊問題に当たり、それぞれ手当をしながら夜までに11冊揃えて shelf に「済」バッジを並べた。",[18,19,21,22,26],"h2",{"id":20},"朝イチの積み残し著者取得444件を-missing-author-で回す","朝イチの積み残し：著者取得444件を ",[23,24,25],"code",{},"--missing-author"," で回す",[14,28,29,30,33,34,38],{},"昨日のセッションで CAPTCHA で止まっていた著者取得の続きから入った。",[23,31,32],{},"--retry"," フラグで全788件を再走査するスクリプトを動かしたが、80件くらい走らせたところで気づいた。",[35,36,37],"strong",{},"file_no 順で頭から舐めるので、最初の300件あたりは「既に著者取得済み」を再処理しているだけ","だった。新規取得は0件のまま、未取得444件には到達していなかった。",[14,40,41,42,45,46,48],{},"無駄を切るため、",[23,43,44],{},"author IS NULL"," のレコードのみを対象にする ",[23,47,25],{}," フラグを追加して回し直した。今度は target=444 で開始し、CAPTCHA を約23%の確率で挟みながら、約1時間で 350件を新規取得（DB上 344→694件）。残り94件は CAPTCHA で取れなかった分なので、また別日に回す。",[14,50,51,52,55,56,59,60,62,63,66],{},"進捗メモを ",[23,53,54],{},"memo/2026-04-30/progress.md"," に書いて、ついでに ",[23,57,58],{},"/books"," ページのタイトル右に「書棚を見る →」リンクを追加した。今までは ",[23,61,58],{}," から ",[23,64,65],{},"/shelf"," に飛ぶ動線がなかったので、青字で1行リンクを置いた。",[18,68,70],{"id":69},"ユーザー依頼公認会計士テキストも入れたい","ユーザー依頼：「公認会計士テキストも入れたい」",[14,72,73,75,76,79,80,86,87,90],{},[23,74,65],{}," の動線が整ったあと、ユーザーから Dropbox の ",[23,77,78],{},"00連番で管理するフォルダ"," に入っている公認会計士テキスト27冊が DB に取り込まれていない、という指摘が来た。確認すると、書籍ナレッジベースの取り込みスクリプトは ",[35,81,82,85],{},[23,83,84],{},"NoXXX_"," でナンバリングされた PDF だけを対象","にしており、",[23,88,89],{},"2023_公認会計士_..."," 命名のファイル群は素通りしていた。",[14,92,93,94,97],{},"27冊全部を一気に流すと所要時間が読めないので、まずは ",[35,95,96],{},"【計算】シリーズ11冊","（合計3,488ページ）に絞って取り込むことにした。優先順位はサイズ小→大→次にCF/連結 のハイブリッド順。所要時間を読みやすくするのと、CFWS プロジェクトとの連携で連結関係の本が後で効くため。",[14,99,100,101,104,105,62,108,111],{},"最小の1冊（35MB・追加論点 収益認識）でパイロットして、所要時間を測ることにした。PDF 先頭ページを読んでメタデータを判定したところ、表紙ロゴから判明したのは「これは CPA ではなく ",[35,102,103],{},"TAC"," の公認会計士講座テキスト」ということ。book_id のプレフィックスを ",[23,106,107],{},"cpa-",[23,109,110],{},"tac-"," に直した。",[18,113,115],{"id":114},"パイロット1冊yomitokudb格納まで2分37秒で完走","パイロット1冊：yomitoku→DB格納まで2分37秒で完走",[14,117,118,119,122,123,126],{},"GPU モードで yomitoku を回したら、120ページを ",[35,120,121],{},"約2分37秒"," で OCR し終えた。1ページあたり1秒強。図ファイル（27枚）をリネームして、",[23,124,125],{},"yomitoku_import.py"," でメタデータ登録 + DB 格納を実行し、95チャンクが Turso に入った。FTS 検索で「収益認識」を引いてヒットすることを確認して、パイロット完了。",[14,128,129],{},"3,488ページを1ページ≒1.5秒換算で見積もると、残り10冊で約87分。pymupdf でページ数を機械的に拾い、メタデータ案を10冊分一括生成して、ユーザー承認を取って連続実行に進んだ。",[18,131,133],{"id":132},"windows-cp932クラッシュutf-8unbuffered-対応版に修正","Windows cp932クラッシュ：UTF-8/unbuffered 対応版に修正",[14,135,136,137,140,141,148],{},"10冊を順次処理する ",[23,138,139],{},"batch_import.py"," を書いて、Windows の分離プロセス（90分級なので Bash タイムアウトを避ける）でバックグラウンド起動した。直後にエラー判明：",[35,142,143,144,147],{},"Windows の cp932 が ",[23,145,146],{},"✓"," を出力できずクラッシュ","。最初の1冊（09 個別CF）はメタデータ登録までは終わっていたが、yomitoku 実行は中断していた。",[14,150,151],{},"スクリプトの先頭で stdout/stderr を UTF-8 unbuffered に切り替え、再起動した。",[153,154,159],"pre",{"className":155,"code":156,"language":157,"meta":158,"style":158},"language-python shiki shiki-themes vitesse-light vitesse-light","import sys\nsys.stdout.reconfigure(encoding=\"utf-8\")\nsys.stderr.reconfigure(encoding=\"utf-8\")\n# 起動側: python -u batch_import.py で unbuffered\n","python","",[23,160,161,174,215,243],{"__ignoreMap":158},[162,163,166,170],"span",{"class":164,"line":165},"line",1,[162,167,169],{"class":168},"sHkkW","import",[162,171,173],{"class":172},"sG7-3"," sys\n",[162,175,177,180,184,187,189,192,195,199,202,206,210,212],{"class":164,"line":176},2,[162,178,179],{"class":172},"sys",[162,181,183],{"class":182},"shFtX",".",[162,185,186],{"class":172},"stdout",[162,188,183],{"class":182},[162,190,191],{"class":172},"reconfigure",[162,193,194],{"class":182},"(",[162,196,198],{"class":197},"s4oTP","encoding",[162,200,201],{"class":182},"=",[162,203,205],{"class":204},"sMJiu","\"",[162,207,209],{"class":208},"sdGka","utf-8",[162,211,205],{"class":204},[162,213,214],{"class":182},")\n",[162,216,218,220,222,225,227,229,231,233,235,237,239,241],{"class":164,"line":217},3,[162,219,179],{"class":172},[162,221,183],{"class":182},[162,223,224],{"class":172},"stderr",[162,226,183],{"class":182},[162,228,191],{"class":172},[162,230,194],{"class":182},[162,232,198],{"class":197},[162,234,201],{"class":182},[162,236,205],{"class":204},[162,238,209],{"class":208},[162,240,205],{"class":204},[162,242,214],{"class":182},[162,244,246],{"class":164,"line":245},4,[162,247,249],{"class":248},"sxvE3","# 起動側: python -u batch_import.py で unbuffered\n",[14,251,252],{},"09 CF は yomitoku が既に完走済みだったので、図リネーム + DB 格納だけで34秒で完了。後続の04（負債・純資産、268p）は4分52秒、02（棚卸・固定資産、272p）は4分26秒。当初想定の1ページ1.5秒より速く、1秒/ページのペースで進み始めた。",[18,254,256],{"id":255},"db-idle-timeoutreconnect-を各冊冒頭で呼ぶ","DB idle timeout：reconnect() を各冊冒頭で呼ぶ",[14,258,259,260,263],{},"5冊目（07 連結財務諸表3）まで進んだところで、また止まった。エラーログを見ると ",[35,261,262],{},"DB 接続のidle timeoutで38分超で stream が切れていた","。バッチを起動したときに張ったコネクションが長時間使われなくて、Turso 側で勝手にクローズされていた。",[14,265,266,269,270,273],{},[23,267,268],{},"db.py"," に ",[23,271,272],{},"reconnect()"," を追加して、各冊の冒頭で呼ぶ修正を入れた。",[153,275,277],{"className":155,"code":276,"language":157,"meta":158,"style":158},"def reconnect():\n    global _client\n    if _client:\n        _client.close()\n    _client = create_client(...)  # 新しい接続を張り直す\n",[23,278,279,292,300,311,324],{"__ignoreMap":158},[162,280,281,285,289],{"class":164,"line":165},[162,282,284],{"class":283},"stQ0i","def",[162,286,288],{"class":287},"senZ8"," reconnect",[162,290,291],{"class":182},"():\n",[162,293,294,297],{"class":164,"line":176},[162,295,296],{"class":283},"    global",[162,298,299],{"class":172}," _client\n",[162,301,302,305,308],{"class":164,"line":217},[162,303,304],{"class":168},"    if",[162,306,307],{"class":172}," _client",[162,309,310],{"class":182},":\n",[162,312,313,316,318,321],{"class":164,"line":245},[162,314,315],{"class":172},"        _client",[162,317,183],{"class":182},[162,319,320],{"class":172},"close",[162,322,323],{"class":182},"()\n",[162,325,327,330,332,335,337,341,344],{"class":164,"line":326},5,[162,328,329],{"class":172},"    _client ",[162,331,201],{"class":182},[162,333,334],{"class":172}," create_client",[162,336,194],{"class":182},[162,338,340],{"class":339},"snbK4","...",[162,342,343],{"class":182},")",[162,345,346],{"class":248},"  # 新しい接続を張り直す\n",[14,348,349,350,353],{},"PID を新しく取り直して再起動。再格納フェーズ（既に DB に入っていた4冊分の差分埋め）が30〜57秒/冊で流れ、続けて残り5冊の本格処理に入った。03（リース・税効果）6分19秒、06（連結2）7分29秒、08（企業結合）7分55秒、01（金融商品・外貨）7分46秒、05（本支店・連結1）が最後。",[35,351,352],{},"11冊全部の取り込みが13:11頃に完了","した。",[18,355,357],{"id":356},"restructure-11冊subagent並列でwalロック頻発http直接接続に切り替え","restructure 11冊：subagent並列でWALロック頻発、HTTP直接接続に切り替え",[14,359,360,361,364],{},"取り込みが終わった次は章節整理（restructure）。yomitoku がページ単位で切ったチャンクを、目次に沿って節レベルに統合する処理を11冊全部に流す。最初は subagent を11並列で起動した。",[35,362,363],{},"Embedded Replica の WAL ファイルが14MB残ったままロックされ、復旧に時間がかかる事象が頻発","。subagent が起動した Python subprocess が完了通知後も残って DB ロックを保持していた。",[14,366,367,368,371],{},"WAL 復旧のコストが大きすぎたので、アプローチを変えた。restructure コマンドの中身を ",[35,369,370],{},"HTTP 直接接続版","に書き換え、subagent も Embedded Replica を経由せず直接 Turso の HTTP API を叩く形にした。9冊を subagent で順次起動し直す（並列ではなく直列）。",[14,373,374,375,378,379,382],{},"その前に、Tursoのバックアップを取ってから restructure を流すことにした。",[23,376,377],{},"turso-replicas/scripts/backup_turso.py"," を見つけて実行し、",[23,380,381],{},"backups/2026-04-30/"," に books 43行 + chunks 6,500行を CSV で保存。",[14,384,385],{},"ここから9冊を直列で回した。各冊の削減量は以下：",[387,388,389,393,396,399,402,405,408,411,414],"ul",{},[390,391,392],"li",{},"04 負債・純資産: 229→63（166削除）",[390,394,395],{},"02 棚卸・固定資産: 224→69（155削除）",[390,397,398],{},"10 商品売買: 285→56（229削除）",[390,400,401],{},"07 連結3: 277→80",[390,403,404],{},"03 リース・税効果: 302→85",[390,406,407],{},"06 連結2: 321→114",[390,409,410],{},"08 企業結合・事業分離: 334→51（283削除、第4章II分離元企業46チャンクを1セクションに統合）",[390,412,413],{},"01 金融商品・外貨: 385→107",[390,415,416],{},"05 本支店・連結1: 423→（最大冊）",[14,418,419,422],{},[35,420,421],{},"11冊で約70%チャンク削減","（3,167→約1,000セクション）。",[18,424,426],{"id":425},"shelf-0冊問題fetch_statusmanual_register-でnull除外を免除","shelf 0冊問題：fetch_status='manual_register' でNULL除外を免除",[14,428,429,430,432,433,436],{},"DB 格納が終わったので、",[23,431,65],{}," ページで TAC 教材11冊が並んでいるか確認しに行ったら、",[35,434,435],{},"「コンテンツ: 公認会計士試験」chip をクリックしても表示0冊","になっていた。",[14,438,439,442,443,446,447,450,451,454],{},[23,440,441],{},"library.get.ts"," の絞り込みロジックを読むと、",[35,444,445],{},"「★以上 4.0 / レビュー5件以上」のフィルタ","が入っていた。TAC 教材は ",[23,448,449],{},"star_rating"," も ",[23,452,453],{},"review_count"," も NULL なので、このフィルタで全部除外されていた。",[14,456,457,460,461,463],{},[23,458,459],{},"fetch_status='manual_register'"," で識別して、星評価フィルタを免除する条件分岐を入れた。手動登録した本は星評価のしきい値を見ない、という運用ルール。修正後、Chrome DevTools MCP で ",[23,462,65],{}," を開いて11冊全部の表示を確認した。",[18,465,467],{"id":466},"連結タグの集計確認とma組織再編タグの追加","連結タグの集計確認とM&A・組織再編タグの追加",[14,469,470],{},"ユーザーから「連結会計の本が全部『連結』タグで集計されているか確認してほしい」と言われた。shelf で「連結」chip をクリックすると現状13冊。タイトルに「連結」を含むがタグが付いていない本を抽出すると22件出てきた。分類して、明らかに連結会計の本にタグを追加。",[14,472,473],{},"合わせて、関連書籍として「M&A」タグ10冊、「組織再編」タグ7冊を新規にコンテンツ軸へ追加した。No834 のように両方付く本もある。",[14,475,476,477,480,481,484],{},"最後に shelf でスクリーンショットを撮って、11冊全部に ",[35,478,479],{},"緑「済」バッジ"," + ",[35,482,483],{},"青「📖 DB」バッジ"," が並んでいるのを確認した。コンテンツ chips にも「M&A 10」「組織再編 7」が並んだ。",[18,486,488],{"id":487},"教訓restructure-は-http-直接接続で動かす","教訓：restructure は HTTP 直接接続で動かす",[14,490,491,492,498],{},"このセッションの最大の学びは、",[35,493,494,497],{},[23,495,496],{},"/restructure-book"," コマンドは subagent 経由の Embedded Replica より HTTP 直接接続のほうが安定する","こと。subagent が起動した Python subprocess は完了通知後も生き残り、WAL ロックを持ったまま離さない。WAL 復旧のたびにレプリカ作り直しが必要になり、コストが大きすぎる。",[14,500,501,502,504],{},"教訓は ",[23,503,496],{}," スキルの md に追記した。今後 restructure を流すときは、subagent 経由ではなく HTTP 直接接続版のスクリプトを直接動かす。",[14,506,507],{},"明日は CAPTCHA で取れなかった著者94件の再取得と、残りの公認会計士テキスト16冊（【計算】シリーズ以外）の取り込み判断から入る。",[509,510,511],"style",{},"html pre.shiki code .sHkkW, html code.shiki .sHkkW{--shiki-default:#1E754F;--shiki-dark:#1E754F}html pre.shiki code .sG7-3, html code.shiki .sG7-3{--shiki-default:#393A34;--shiki-dark:#393A34}html pre.shiki code .shFtX, html code.shiki .shFtX{--shiki-default:#999999;--shiki-dark:#999999}html pre.shiki code .s4oTP, html code.shiki .s4oTP{--shiki-default:#B07D48;--shiki-dark:#B07D48}html pre.shiki code .sMJiu, html code.shiki .sMJiu{--shiki-default:#B5695977;--shiki-dark:#B5695977}html pre.shiki code .sdGka, html code.shiki .sdGka{--shiki-default:#B56959;--shiki-dark:#B56959}html pre.shiki code .sxvE3, html code.shiki .sxvE3{--shiki-default:#A0ADA0;--shiki-dark:#A0ADA0}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .stQ0i, html code.shiki .stQ0i{--shiki-default:#AB5959;--shiki-dark:#AB5959}html pre.shiki code .senZ8, html code.shiki .senZ8{--shiki-default:#59873A;--shiki-dark:#59873A}html pre.shiki code .snbK4, html code.shiki .snbK4{--shiki-default:#A65E2B;--shiki-dark:#A65E2B}",{"title":158,"searchDepth":176,"depth":176,"links":513},[514,516,517,518,519,520,521,522,523],{"id":20,"depth":176,"text":515},"朝イチの積み残し：著者取得444件を --missing-author で回す",{"id":69,"depth":176,"text":70},{"id":114,"depth":176,"text":115},{"id":132,"depth":176,"text":133},{"id":255,"depth":176,"text":256},{"id":356,"depth":176,"text":357},{"id":425,"depth":176,"text":426},{"id":466,"depth":176,"text":467},{"id":487,"depth":176,"text":488},"dev","朝イチで著者取得の積み残し350件を回しきった後、TAC公認会計士テキスト【計算】シリーズ11冊（3,488ページ）を yomitoku→Turso DB 格納で一気通貫処理。Windows cp932クラッシュ、DB idle timeout、Embedded Replica WALロック、shelf 0冊問題に当たりながら、最終的に11冊全部の章節整理まで通した。","md",{},true,"/2026-04-30-tac-cpa-textbooks-batch-import","book-knowledge-base",false,"2026-04-30T00:00:00.000Z",{"title":5,"description":525},"2026-04/2026-04-30/tac-cpa-textbooks-batch-import",[536,537,538,539,540],"書籍デジタル化","TursoDB","yomitoku","並列処理","Windows",null,"brZLcXEJ-kGTNkzMcPoyJWQVSvhAWEetOrRZgBv3OPo",[],"https://log.eurekapu.com/favicon.svg",1777617050546]