SeleniumでChromeのダウンロードが進まないときの対処法【絶対パス】

こんにちは。

Selenium WebDriverのChromeでファイルをダウンロードする際、download.default_directoryというオプションでデフォルトのダウンロード先フォルダ(ディレクトリ)を設定することができます。今回この指定が絶対パスになっていないことでファイルのダウンロードが進まないという事象が起きたので、その紹介です。

Seleniumによるファイルの自動ダウンロード

Selenium WebDriverのChromeでファイルをダウンロードするリンクをクリックすると、標準のダウンロードフォルダにファイルがダウンロードされます。ただ、自動化の用途では環境がまちまちなことが多く、ファイルのダウンロード先は事前に明示的に指定しておきたいものです。

そのとき使うのが、download.default_directoryというオプションです。Pythonでの例になりますが、以下のように指定することができます。

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

# 各種オプションを設定(省略)
options = Options()
options.add_argument('--headless')

# デフォルトのダウンロード先ディレクトリを設定
options.add_experimental_option('prefs', {
    'download.default_directory': '/path/to/download/directory'
})

driver = webdriver.Chrome(options=options)

# ダウンロードリンクのクリック
download_link = driver.find_element_by_xpath('xpath/to/download/link')
download_link.click()

このような記述でファイルがダウンロードできます。非常に簡単で自動化万歳という感じなのですが、今回ダウンロードが進まないという事象に当たりました。

crdownloadファイルだけできる

Chromeがファイルをダウンロードするとき、ダウンロード中の一時ファイルとしてダウンロードするファイル名.crdownloadというファイルが生成されます。これはSelenium WebDriverのChromeでも同様で、まずcrdownloadファイルが作られ、その後ダウンロード完了時にそのファイルに置き換わるようになっています。

今回何度ダウンロードを試してもcrdownloadファイルのまま進まないという事象が発生しました。ダウンロードするファイルのサイズが大きく時間がかかっていて終わる前にプログラムが終了してしまっているのではないかと思い、time.sleep(20)のようにして少し待ってみるも結果は変わらず、ダウンロードリンククリック後に1秒ごとにcrdownloadファイルのファイルサイズを見てみると、ずっと0バイトのままという状態でした。

ちなみに環境によっては起きないなどあるかもしれないので一応書いておくと、Mac+Python+ローカル実行という環境です。

ダウンロード先は絶対パスで指定する

ググっても情報が出てこず正直途方に暮れていたのですが、結論、原因はダウンロード先のディレクトリを指定するdownload.default_directoryオプションに相対パスを指定していたことでした。プロジェクトのディレクトリ内にファイルをダウンロードしたかったので相対パスで指定していたのですが、/ 始まりの絶対パスで指定したところ、すんなりダウンロードが完了しました。

想定通りのディレクトリにcrdownloadファイルが生成されるということは、相対パス自体は認識されているということになります。そのうえでなぜファイルのダウンロード自体は進むことがないのか、SeleniumのせいなのかChromeのせいなのか分かりません。相対パスを指定したらcrdownloadファイルの生成すらされないとかならもう少し早く気づけたかもしれません。

とはいえ相対パスで指定したい

とはいえ、先ほど書いた「プロジェクトのディレクトリ内にファイルをダウンロードしたい」という用途からすると、ダウンロード先は相対パスで指定したいところです。どこでそのプロジェクトを実行するか分からないですからね。というわけで実行時に相対パスを絶対パスに変換することにしました。

pathlibで絶対パスに変換

Python 3.4以降に標準で含まれているライブラリ「pathlib」を使えば、簡単に相対パスを絶対パスに変換することができます。以下のように使います。

path = pathlib.Path('./output/')
print(path.resolve())
# /プロジェクトまでの絶対パス/output/ が出力される

pathlibはPathオブジェクトをベースに様々な操作をすることができ、絶対パスでの取得はresolveメソッドを使います。他にも、絶対パスを相対パスに変換できるrelative_toメソッドや、絶対パスかどうかを判定するis_absoluteメソッドなどがあります。

今回はresolveメソッドで変換した結果をWebDriverのオプションに渡すことで、問題なくダウンロードができるようになりました。


というわけで今回は、Selenium WebDriverを使った自動化プログラムで遭遇した謎の事象への対処法でした。中途半端にファイルだけ作られてしまうと原因に気づくのに時間がかかって厄介ですね。調べてもあまり出てこない情報だったのでどなたかの役に立てれば幸いです。

それではまた。

関連記事