MAGAZINE
ルーターマガジン
Ruby × Seleniumでファイルをダウンロード
こんにちは、アルバイトのarakiです.
最近は感染症の流行で外に出る機会も減りました.人の少ない時間帯に散歩などしたいものですが、季節柄、暑さが厳しいかと思えば雨が強かったりでおっくうになってしまうものです.それでも、室内が湿気ないように外の空気を取り入れるくらいはしたいですね.
そういうわけで、今回はRubyとSeleniumを使ってWebサイトにあるファイルを"取り入れる"、つまりダウンロードする方法についてご紹介します.
通常の場合
先にソースコードを貼ります.
require 'selenium-webdriver'
download_path = File.absolute_path('./dl_files') # 現在位置にあるdl_filesディレクトリへのパス.
# windows用
driver_path = '/mnt/c/Users/driver/chromedriver.exe'
if File.exist?(driver_path)
Selenium::WebDriver::Chrome::Service.driver_path = driver_path
download_path = download_path.gsub(%r{/mnt/c}, 'C:').gsub(%r{/}, "\\")
end
download_pref = {
'prompt_for_download'=> false,
'default_directory'=> download_path,
'directory_upgrade'=> true
}
options = Selenium::WebDriver::Chrome::Options.new
options.add_preference(:download, download_pref)
client = Selenium::WebDriver::Remote::Http::Default.new
driver = Selenium::WebDriver.for :chrome, http_client: client, options: options
driver.manage.timeouts.implicit_wait = 10
# seleniumの設定ここまで
sleep 1
driver.navigate.to 'https://chromedriver.storage.googleapis.com/index.html?path=84.0.4147.30/'
# テキストが'chromedriver_win32.zip'となっているa要素.
download_link = driver.find_elements(:css, 'a').find { |a| a.text.include? 'chromedriver_win32.zip' }
download_link.click
sleep 3
driver.quit
これは、seleniumでChromeDriverのダウンロードページへ行き、zipファイルをダウンロードするプログラムです.
最初のdownload_path
にはダウンロード先に指定したいディレクトリのパスを書きます.
また、#WSL用 とされている箇所では、指定されたパスにファイルがあればWSLで実行しているとみなしてWSL用の処理をしています.
ここでは、Selenium::WebDriver::Chrome::Service.driver_path = driver_path
によって指定したパス上のChromeDriverを使い、
download_path = download_path.gsub(%r{/mnt/c}, 'C:').gsub(%r{/}, "\\")
によってパスをWindows向けのものにします.
例えば、/mnt/c/Users/dev/dl_files
をC:\Users\dev\dl_files
にします.
このコードを書くことによって、MacユーザーもWSLユーザーも同じプログラムを実行できます.私は社内で少数派のWSLユーザーなので、この書き方を見つけたときはとても便利だと感じました.
以下、Seleniumの各種設定をした後に、ダウンロードページへでのダウンロード処理を行っています.なお、download_pref
のところでハッシュロケットを使っているのが奇妙に見えるかもしれませんが、どうやらキーをStringにしないとうまくいかないようです(注1).
Seleniumでは、実際のページでダウンロードリンクを踏めばダウンロードできるのと同様に、リンクの要素をクリックすることでダウンロードができます.
ここで、ダウンロードしてすぐquitしないように気を付けましょう.ダウンロードする前にChromeを閉じてしまうと、ダウンロードができません.
サンプルでは3秒スリープを挟んでいますが、実際に使うときはディレクトリにファイルが落ちたことを確認してからquitする、のような処理を挟むと確実にダウンロードできるかもしれません.
ヘッドレスの場合
やはり先にソースコードを貼ります.
require 'selenium-webdriver'
download_path = File.absolute_path('./dl_files') # 現在位置にあるdl_filesディレクトリへのパス.
# WSL用
driver_path = '/mnt/c/Users/driver/chromedriver.exe'
if File.exist?(driver_path)
Selenium::WebDriver::Chrome::Service.driver_path = driver_path
download_path = download_path.gsub(%r{/mnt/c}, 'C:').gsub(%r{/}, "\\")
end
options = Selenium::WebDriver::Chrome::Options.new
options.add_argument('--headless')
options.add_argument('--no-sandbox')
options.add_argument('--disable-popup-blocking')
options.add_argument('--disable-gpu')
caps = Selenium::WebDriver::Remote::Capabilities.chrome(
'chromeOptions' => { w3c: false }
)
client = Selenium::WebDriver::Remote::Http::Default.new
driver = Selenium::WebDriver.for :chrome, desired_capabilities: caps, http_client: client, options: options
driver.manage.timeouts.implicit_wait = 10
bridge = driver.send(:bridge)
path = "/session/#{bridge.session_id}/chromium/send_command"
command_hash = {
cmd: 'Page.setDownloadBehavior',
params: {
behavior: 'allow',
downloadPath: download_path
}
}
bridge.http.call(:post, path, command_hash)
# seleniumの設定ここまで
sleep 1
driver.navigate.to 'https://chromedriver.storage.googleapis.com/index.html?path=84.0.4147.30/'
# テキストが'chromedriver_win32.zip'となっているa要素.
download_link = driver.find_elements(:css, 'a').find { |a| a.text.include? 'chromedriver_win32.zip' }
download_link.click
sleep 3 # ダウンロードの待機
driver.quit
処理内容は通常の場合と同じです.ただし、ヘッドレスのseleniumでは設定の仕方が通常のものとは少し異なります(注2).
おわりに
以上になります.今年は体を動かす機会が減ってしまった方も多いかと思われます.プログラミングをしているのも良いですが、たまには椅子から立ち上がって体を動かしたほうが良いかもしれませんね.それでは.
脚注
(注1): Chrome download prefs stopped working when passed as symbols; directory_upgrade option
CONTACT
お問い合わせ・ご依頼はこちらから