この記事は、以下のような方を想定しています。

  • Adobe Stockの審査状況を一元管理したい方
  • Chrome拡張でWebページのデータを自動収集したい方
  • PythonとExcelを組み合わせた自動化ツールを作りたい方
  • bat + JSON設定で運用を仕組み化したい方

前記事では、Upscayl・CLIPスコア・Ollamaによるメタデータ生成までの自動化フローを紹介しました。 今回はその続きとなるフロー⑤「審査結果の収集とExcel管理」の前半として、 Chrome拡張によるCSV収集とExcelへの自動反映の仕組みを紹介します。

本記事の位置づけ(フロー⑤前半)

全体フローの中で、本記事が担当するのは以下の部分です。

フロー内容本記事
AI画像生成
②③品質選別・高解像度化
品質スコア自動算出・メタデータ生成
⑤前半審査結果CSV収集 → Excel自動反映★本記事
⑤後半history累積管理・STATUS追跡次記事

全体設計の概要

Adobe StockはAPIを一般公開していないため、審査状況のデータを直接取得する手段がありません。 そこで、ログイン済みのChromeブラウザをリモートデバッグで操作し、審査ページのデータをPythonで収集する方法を採用しました。

収集するCSVは3種類です。

CSV種別収集元ページキー列主な情報
EXAM CSV審査中ページfilename / file_id申請中ファイル一覧・経過日数
OK CSVポートフォリオページfile_number承認済みファイル・承認日
NG CSVNGページfile_id / filename非承認ファイル・NG理由

収集したCSVは、Pythonスクリプトで解析結果Excelの「解析結果」シートに書き込まれます。 ExcelのT列にSTATUSとして EXAM / OK / NG / 空白 が記録され、フィルタで一覧管理できます。

設計のポイント:全設定をJSONに集約

ファイルパス・CSV列名・Excel書き込み列・chrome_debug_portまで、すべてstockphoto.jsonに集約しています。 スクリプト本体を触らずにJSONだけで設定変更できるため、環境移行や列の追加が容易です。

Chrome拡張でのCSV収集

収集スクリプトはChromeのリモートデバッグポート(デフォルト: 9222)経由でブラウザを操作します。 事前にChromeを以下のオプションで起動し、Adobe Stockにログインしておく必要があります。

Chrome起動コマンド例

chrome.exe --remote-debugging-port=9222

ログイン後、batメニューから収集を実行します。ポート番号はstockphoto.jsonchrome_debug_portで変更できます。

3種のCSV収集スクリプト(collect_exam.py / collect_ok.py / collect_ng.py)は、 それぞれ対応するページをスクロールしながらデータを収集し、CSVとして出力します。

OK CSVについては、Adobe側の仕様でfilenameが取得できないという制約があります。 承認後のポートフォリオページには file_number(審査後に付与されるID)しか表示されないためです。 この制約がのちの突合設計に大きく影響します(後述)。

3種のCSVとExcelの突合設計

ExcelへのSTATUS書き込みは、ファイル名でCSVとExcelを照合する方式です。ただし3種のCSVはそれぞれ持つキー情報が異なるため、突合方法を工夫しています。

CSV突合キー照合先
EXAMfilenameExcel B列(ファイル名)と直接照合
NGfile_id または filenamefilename → Excel B列、次にfile_id → Excel U列(EXAM FileID)
OKfile_numberExcel U列(EXAM FileID)と照合

OKの突合が特殊な理由は、先述の通りOK CSVにfilenameが存在しないためです。 当初はEXAM CSV経由でfile_idからfilenameを引こうとしましたが、 OKになった画像はEXAMページから消えるというAdobe側の仕様により、EXAM CSVに存在しない = filename解決できない、という問題が発生しました。

OK突合問題の解決策

EXAMスクリプトがExcelに書き込む際、U列にEXAM FileIDを記録します。 OKスクリプトはEXAM CSVを介さず、ExcelのU列と ok_history の file_number を直接照合します。 これにより「5/29にEXAMとして登録 → 5/30にOKになってEXAMから消えた」画像も正しくOKと記録できます。

STATUS優先度の設計

3種のCSVを別々のタイミングで収集・反映するため、STATUSの上書き優先度を明確に定義しています。

STATUS意味上書きルール
NG審査非承認最優先。EXAM行も上書きする
OK審査承認NGでなければ上書きする
EXAM審査申請中OK/NGが未設定の場合のみ書き込む
空白未収録 / 手動保護いずれのCSVにも存在しない行

また、STATUSがすでにOKまたはNGの行は一切更新しないというルールも設けています。 手動でOK/NGを入力した行も自動処理の対象外となるため、過去データを安心して手動管理できます。 NGだった画像を再審査に出した場合は、手動でSTATUSを空白に戻すことで再度更新対象になります。

batメニューによる統合操作

すべての処理は run_collect_exam_ok_ng.bat のメニューから操作します。 当初は run_menu.bat という名称で作成しましたが、既存の運用ファイル名に合わせてリネームしました。 bat内部でファイル名を参照している箇所はないため、リネームによる影響はありません。

番号処理内容
1EXAM CSV収集 → history自動更新
2NG CSV収集 → history自動更新
3OK CSV収集 → history自動更新
4全CSV収集(exam + ok + ng)→ history更新
4hhistory更新のみ(手動追加後などに使用)
5〜7各CSV → Excel書き込み
8全CSV → Excel書き込み(EXAM → OK → NG順)
9全収集 + history更新 + 全Excel書き込み(フルパイプライン)
0終了

8) の実行順序が重要な理由

EXAM → OK → NG の順に実行することで、STATUS優先度が正しく反映されます。 最後にNGを書き込むことで「EXAMとしてすでに記録されていてもNG判定で上書き」が確実に行われます。

bat起動時にメニュー画面下部に Config / Python / Script / Excel / Port の現在値が表示されます。 JSONの読み込みが正しくできているか起動直後に確認できるため、設定ミスの早期発見に役立ちます。

発生したエラーと解決策

エラー1:「Python not found」

bat起動直後に [ERROR] Python not callable: E:\temp\...\python\python.exe というエラーが発生しました。 原因は、python_dir(スクリプトの置き場)と python.exe の場所を混同していたことです。

当初の設計では python_dir + "\python.exe" というパスを組み立てていましたが、 実際のpythonはシステムのPATHに登録されており、スクリプトフォルダとは別の場所にありました。

解決策:python_exe を独立した設定項目に分離

stockphoto.jsonpython_exe という項目を追加し、 python_dir(スクリプト置き場)と完全に別管理にしました。 PATHが通っている場合は "python_exe": "python" と書くだけで動作します。

エラー2:「Failed to load settings from stockphoto.json」

batの起動時にJSONの読み込みに失敗するエラーです。 PowerShellでJSONを読み込む際、日本語のechoメッセージが文字コード(UTF-8 vs CP932)の混在を引き起こしていました。

解決策として、bat内のecho・メッセージを全て英語に統一しました。 また、PowerShellのfor /f 構文に usebackq-Encoding UTF8 オプションを追加し、 パスにスペースが含まれる場合も安定して動作するよう修正しました。

エラー3:「The syntax is incorrect」(run_collect_exam.bat が存在しない)

メニューの収集処理で call "%SCRIPT_DIR%run_collect_exam.bat" を呼び出すよう実装していましたが、 そのようなファイルは存在しないためエラーになりました。

既存の run_collect_exam_ok_ng.bat を確認すると、中間batを経由せずPythonスクリプトを直接呼び出す設計になっていました。 batメニューの収集処理をすべて "%PYTHON%" "%PY_DIR%\collect_exam.py" --debug-port %DEBUG_PORT% 形式に修正して解決しました。

エラー4:OKが1件も書き込まれない

8) の全書き込みを実行してもSTATUSのOK件数が0件のままという状況です。 調査したところ、OK CSVの file_number とEXAM CSVの file_id の一致件数は69件中8件のみで、 残り61件はEXAMとfile_idが一致しないためfilename解決に失敗していました。

原因を追うと、OKになった画像はAdobeのEXAMページから消えるため、 収集タイミングによってはEXAM CSVにそもそも存在しないことがわかりました。 8件が一致するのは、EXAMからOKになる過渡期のデータが偶然残っていた分です。

この問題は次記事で紹介するhistory設計により根本的に解決しています。

エラー5:collect_ng.py が起動しない(改行コードの問題)

batファイルをダブルクリックしても画面が一瞬出て閉じるだけで、何もメッセージが出ないという現象が起きました。 原因は、Linuxで生成したbatファイルの改行コードが LF(Unix形式) になっていたためです。 Windowsのバッチファイルは CRLF でなければ正しく解釈されません。

解決策として、ファイルをSublime TextやVS Codeで開いてCRLFに変換するか、 コマンドラインで sed -i 's/$/ /' ファイル名.bat を実行します。 以来、batファイルを生成・受け取った際は改行コードを必ず確認するようにしました。

エラー6:NGページで無限ループ(ページ遷移が「1→1」のまま)

collect_ng.py を実行すると、全タイルをスキップしたままページ遷移を繰り返す無限ループが発生しました。 コンソールを確認すると「ページ遷移 1 → 1」が永遠に繰り返されており、最終ページに到達できていない状態でした。

原因は2点ありました。1点目は go_to_next_page() 内で「次へ」クリック後にページ番号が実際に変わったかを確認せず True を返していたこと。2点目は internal_id がフォールバック値(p{page}_{i}形式)になっている場合、 2周目に同じIDが collected_ids に登録済みとして全タイルがスキップされてしまうことです。

解決策:ページ変化を確認してから Trueを返す

遷移後に get_current_page() を再取得し、前のページ番号と一致していれば False(最終ページ)として終了するよう修正しました。 また安全上限として while Truewhile page <= 500 に変更し、デバッグ用にページネーターの表示テキストもコンソール出力するようにしました。

エラー7:全タイルが同一ファイル名で収集される

ページ遷移の問題が解決した後も、収集結果のCSVを開くと 20260430 (116).jpg のような 同一ファイル名が100件並ぶという現象が起きました。

原因は wait_for_panel() の実装にありました。 この関数は「パネルに元のファイル名が含まれているか」だけを確認していたため、 次のタイルをクリックしても前のタイルのパネルが開いたままで条件を満たし、 古いパネルの内容を繰り返し読み続けていたのです。

解決策:パネルの切り替わりをIDで検出する

collect_ok.py(ポートフォリオ収集)ではこの問題がなく、クリック前のパネルIDを記録しておき 「前と異なるIDになるまで待つ」という方式を使っていました。 collect_exam.pycollect_ng.py も同じ wait_for_panel_change() 方式に統一することで解決しました。 パネルが一瞬閉じてから開くケースにも対応するため、「パネルが空になった後に再表示されたIDも新しいIDとして受け入れる」ロジックを追加しています。

エラー8:Chromeをバックグラウンドにするとタイムアウトが多発

Chromeウィンドウを前面に出していれば正常に収集できるのに、 別ウィンドウを操作してChromeを背面に回すと大量のタイムアウトが発生しました。 デバッグ出力には VISIBLE:serious young asian man ... と、 最初に開いたパネルの内容が延々と表示されており、パネルが切り替わっていないことが確認できました。

原因はSeleniumのクリック方式にありました。tile.click() はOSレベルのマウスイベントを送るため、 ウィンドウが背面にあるとクリックイベントがDOMに届かないのです。

解決策:JavaScriptクリックに統一

collect_ok.py では最初から driver.execute_script("arguments[0].click();", img_el) という JavaScriptクリック を使っており、バックグラウンドでも正常動作していました。 collect_exam.pycollect_ng.pytile.click() をすべてJSクリックに変更することで、 Chromeが背面にあっても安定して収集できるようになりました。

また、get_panel_file_id() がSeleniumの panel.text を使っていた部分も、 panel.is_displayed() で表示状態を確認してからテキストを取得する実装に変更しました。 非表示パネルのテキストが誤って読まれるケースを防ぐための対処です。