Chrome+Seleniumでファイルをダウンロードできない【解決済】

これは、Selenium + Python で Chrome を自動操作してファイルをダウンロードしようと思ったときの話です。

テストでは上手くいくのに本番環境にいくとダウンロードされない。エラーも発生しない。ぜんぜん分からず調べること数時間…。

結局原因はheadlessモードでした。本番時にのみheadlessにしていたことが仇になりました。Chrome の初期設定では(セキュリティのためか)headlessモードではファイルをダウンロードできないようです。それならそれでエラーで落としてほしいものです。

Webにあった情報を参考にプログラムを修正したら解決。無事にダウンロードができました。

Chrome + Selenium でのファイルのダウンロード for ヘッドレスモード

まずは必要なパッケージのインポートします。

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

次にオプションの生成。
パス関係はそれぞれの環境に応じて適宜変更してください。

opt = Options()
exec_path = '/usr/bin/chromedriver'
opt.binary_location = '/usr/bin/google-chrome'
## Windows の場合
#exec_path = 'C:\\bin\\chromedriver_win32\\chromedriver.exe'
#opt.binary_location = 'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe'
opt.add_argument('--headless')

次にダウンロードに関する詳細設定を生成します。download.default_directoryという保存先を指定する項目もありますが、これは後から別の方法で指定するので、ここでは不要です。

prefs = {}
prefs['download.prompt_for_download'] = False
prefs['download.directory_upgrade'] = True
opt.add_experimental_option('prefs', prefs)

ここまでやってとりあえずChromeを起動します。

driver = webdriver.Chrome(chrome_options=opt, executable_path=exec_path)

そして本題のダウンロードの有効化です。ここではchromedriverに直接コマンドを投げます。download_pathはダウンロードファイルの保存先ディレクトリーの絶対パスです。Seleniumでダウンロードする場合は都度保存パスを指定することはできませんので、こうしてデフォルトのパスを指定します。

driver.command_executor._commands["send_command"] = (
    'POST', 
    '/session/$sessionId/chromium/send_command'
)
driver.execute("send_command", params={
    'cmd': 'Page.setDownloadBehavior',
    'params': {
        'behavior': 'allow',
        'downloadPath': download_path
        }
    })

これでヘッドレスモードでもファイルのダウンロードができるようになりました。