ローカルに記事が54本あった。
1cto.jpのデータベースにはまだ入っていない。ファイルとしては存在しているが、サイトから読めない。1本ずつ管理画面から入力するという選択肢もあったが、54本は現実的ではない。
スクリプトで一括投入することにした。
まず方針を決めた。
記事ファイルはローカルのDropboxフォルダに保存されている。Dropboxはリアルタイム同期しているが、EC2サーバーにはDropboxが入っていない。記事ファイルをEC2に転送してから、EC2上でスクリプトを実行する。
転送にはSCPを使う。SCPはSSH経由でファイルをコピーするコマンドだ。EC2への接続にはpemキーを使っているので、SCPでも同じキーを指定する。
最初にPowerShellからSCPを実行した。失敗した。
エラーメッセージはこうだった。「Bad permissions. Try removing permissions for user: UNKNOWN\\UNKNOWN」
Windowsのssh-agentがpemキーのパーミッションを厳しくチェックする。PowerShellが使うSSHクライアントはOpenSSHの実装だが、キーのアクセス権が「自分だけ」でないと弾かれる。
Claude Codeにも同じことが起きたが、Bashツールから実行すると動いた。Claude CodeはWindowsとWSL/bash双方のツールを持っていて、Bashツールはパーミッションの扱いが違う。原因を調べるより先に、Bashツールに切り替えた方が早かった。
記事ディレクトリのパスに日本語が含まれていた。
D:/シンプルシステム株式会社 Dropbox/伊藤勝彦/000claude/1cto/articles/
Windowsのパスに日本語が入ることは珍しくないが、コマンドラインで扱うときは注意が必要だ。シングルクォートで括って渡した。Bashはダブルクォートでも動くが、スペースが含まれるパスはどちらかで括らないとエラーになる。
転送自体は成功した。13シリーズ分のディレクトリとmdファイルが/home/ubuntu/1cto/articles_import/にコピーされた。
次にEC2上でPythonスクリプトを実行した。insert_articles.pyというファイルだ。
スクリプトの設計はシンプルだ。ボリュームの定義(vol_no・名称・説明・シリーズ名・価格・対象ディレクトリ・記事番号の範囲)を配列に持つ。各ボリュームについて、対象ディレクトリからファイルを取得し、タイトルと要約を抽出して、データベースに投入する。
既に存在する記事はスキップする。べき等性を持たせてあるので、何度実行しても重複しない。
def insert_article(cur, vol_no, article_no, title, content, summary, is_free):
cur.execute('SELECT article_id FROM articles WHERE volume_no=%s AND article_no=%s',
(vol_no, article_no))
if cur.fetchone():
print(f'vol{vol_no} art{article_no} SKIP: {title[:40]}')
return
cur.execute('''INSERT INTO articles (...) VALUES (...)''', (...))
実行結果は49本の投入だった。54本と思っていたが、一部のシリーズで記事数が予定より少なかった。スキップは0件だったので重複もない。
DBの総記事数が49から98になった。
1ランすると全ボリュームの進捗が流れる。vol11 INSERT: 入退室管理システム制作記 Vol.1、vol12 INSERT: 予約システム制作記 Vol.1、というログが続く。どのボリュームが入ったか確認しながら眺めた。
記事の数が増えることと、記事が読まれることは別の話だ。
98本がDBに入った。サイトからアクセスすれば読める。次の課題はStripeのprice_idだ。各ボリュームに対応する価格IDをStripe管理画面で設定しないと、購入フローが動かない。
記事を書いて、DBに入れて、Stripeに繋ぐ。プラットフォームとしての完成は、この順序で進む。
次回は、insert_articles.pyがタイトルと要約をどう抽出したか、スクリプトの内部設計を書く。
シンプルシステム株式会社 代表 伊藤勝彦