Python + Selenium + Chrome でファイル保存まわり


はじめに

Selenium (+ Chrome) でのファイル保存関係の方法をまとめます。

基本的操作: Python + Selenium で Chrome の自動操作を一通り

以下の説明の一部はChrome依存です(PDFのダウンロード、ヘッドレスモードでのダウンロードなど)。

注意事項

  • アクセス対象サイトの利用規約をよく読みます。
    • たとえばログインが絡むサイトなどは、機械的なダウンロードが禁止されていることもしばしばあります。(例:twitter)
    • 自分だけでなく、自分の所属するグループごと大きなペナルティを食らうこともあります。(例:電子ジャーナル)
  • 著作権をよく理解・考慮する必要があります。
  • サーバーの負荷もよく考えます。時間を十分空けながら処理をします。
    • 並列にダウンロードをするのは避けたほうがよいでしょう。
    • URLリストだけ取得しておき、あとで順にダウンロードしていくのもありでしょう。

現在ページのhtmlソースを取得

driver.page_source で現在のページのhtmlソースを取得できます。

html = driver.page_source
with open('hoge.html', 'w', encoding='utf-8') as f:
    f.write(html)

クリックでダウンロード

  • クリックイベントでダウンロードが始まる要素を見つけておいて .click()
  • <a href...> をたどるとダウンロードされるならば、.get_attribute("href") などで URL を取得してから driver.get(<URL>) も可

直接ダウンロード

画像などを直接ダウンロードするには、urllib.request.urlretrieve を使うことができます。

画像 (img) 要素が id="logo" を持つならば以下のようになります。

import urllib.request
# ... (省略) ...
url = driver.find_element_by_id("logo").get_attribute("src")
urllib.request.urlretrieve(url, 'logo.png')

PDFダウンロードとファイル保存先変更

PDFはデフォルトではChromeで表示されてしまうので、ファイルとしてダウンロードできるようにし、ついでに保存先のフォルダを明示的に指定します。

from selenium import webdriver
from pathlib import Path  # 絶対パスを簡単に取得できるように

dldir_name = 'download'  # 保存先フォルダ名
dldir_path = Path(dldir_name)
dldir_path.mkdir(exist_ok=True)  # 存在していてもOKとする(エラーで止めない)
download_dir = str(dldir_path.resolve())  # 絶対パス

options = webdriver.ChromeOptions()
options.add_experimental_option("prefs", {
    "download.default_directory": download_dir,
    "plugins.always_open_pdf_externally": True
})
# (1)
driver = webdriver.Chrome(options=options)
# (2)
driver.get("http://aaa.bbb.ccc/hoge.pdf")

注意事項にも書きましたが、機械的にダウンロードしてはいけない場合も多々あるので気を付けましょう。たとえば電子ジャーナルなどは絶対ダメですし、すぐに検出されて機関ごと利用停止になります。

ヘッドレスモードでもダウンロード

デフォルトだとヘッドレスモードではファイルダウンロードができないようです.

まず上記コードの (1) にオプションを追加してヘッドレスモードにします.

options.add_argument('--headless')

たしかにこれではダウンロードができません.
そこで、(2) の部分に以下のコードを入れてみます。

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

参考: https://qiita.com/zkangaroo/items/1c4d4c11b06e7823e7fe

これでヘッドレスモードでもファイルダウンロードが可能になります。
ただ、注意事項の通り、多くのファイルの並列ダウンロードは避けたほうがよいです。
したがって、処理速度を速めるという意味でヘッドレスにする必要性は少ないと思われます。