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

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

テストでは上手くいくのに本番環境にいくとダウンロードされない。エラーも発生しない。
テストは Windows で本番は Ubuntu だったので環境の違いかと思っていろいろ調べたのですが、分からず…。結局原因は 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
        }
    })

これでヘッドレスモードでもファイルのダウンロードが可能になります。