Selenium使用中にファイルのダウンロード処理が動かない場合に行った事(VB.Net)


VB.NetでSeleniumを使用中にファイルをダウンロードする処理を入れていたのですが、その部分の処理が正常に動かない状態になってしまったのでその時の対応内容を纏めておきます。

状況

まずはその部分の処理について。

今回VB.Netでダウンロードを行うにあたり使用した処理は、WebClientクラスを使用した以下の様なものです。

動かなくなった箇所は「wc.DownloadFile(url, path)」で、具体的なエラーの内容は接続タイムアウトです。

※上のコードとは微妙に異なりますが、内容は同じ

もちろんですが指定しているURLと保存先のパスに誤りは無い事は確認済みです。

また「リモート サーバに接続できません」とは出ていますが、通信回線自体に問題はありません。該当のドメインサイトにもアクセス出来ていますし、ブラウザ上では対象のファイル(今回は画像)も問題無く表示できています。

ちなみにこのエラー・・・
特定のタイミングで呼び出すと発生する様で、再現確率は100%でした。


スポンサーリンク

エラーが発生するタイミングを検証

Seleniumでブラウザ操作中に呼び出したダウンロード処理が動かなくなったという事で、どの部分に問題があるのかを切り分ける為、以下の①~④のタイミングでそれぞれダウンロード処理を呼び出してみました。

※ここで呼び出している「fileDownload」は、冒頭で記述したものを使用しています。

①、②はChromeDriverのインスタンス化前後。

③はブラウザ立ち上げ後。

④は立ち上げたブラウザを終了後、リソースを解放して更に5秒待機した後。

という条件でそれぞれ実行してみた所、

①、②は共に成功し、ファイルがダウンロードできていた事を確認。

③、④は何度試してもタイムアウトとなりました。

③の時点ではChromeが起動している事が原因なのかと思いましたが、④でもエラーのままという事で余計謎が深まってしまいました。

ただし、一度処理を停止させた後、最初から起動してみると①、②の処理で正常にダウンロードする事ができます。

ブラウザを起動した時点で何らかの要素が占有されてしまい、ブラウザを閉じてもそれが解放されないまま残ってしまい、それとWebClientの処理が何か競合してしまっている・・・という事なのかな?


スポンサーリンク

対策を考えてみる

「SeleniumからChromeブラウザを起動した」という事がタイムアウトエラーのきっかけになっている事は何となく分かりましたが、ブラウザを閉じてリソース解放してもダメ・・・となると、お手上げです。そこまで追えない。

という訳で

エラーを解消する」という対策では無く、

別の形で動く様にする」という方針に切り替えて幾つか方法を考えてみました。

WebRequest、WebResponseクラスを使ってみる

「System.Net.WebClient」と同様に、WebRequest、WebResponseを使用した以下の処理でもファイルをダウンロードする事が可能です。

参考サイト:WebRequest、WebResponseクラスを使ってファイルをダウンロードし保存する(dobon.net 様)

https://dobon.net/vb/dotnet/internet/webrequestsavefile.html

試してみた結果は・・・・

やっぱりダメでした。

webres.GetResponseStream()

の部分で同じく処理が停止してしまい、そのままタイムアウトとなりました。

JavaScriptでローカルにファイルをダウンロードする

chromeDriverクラスにあるExecuteScriptでJavaScriptを実行できるので、これを使ってファイルをダウンロードする事ができないかと思い調べてみましたが・・・出てくるのはhtmlを修正してダウンロードリンクを生成する処理ばかり。

違うそうじゃない。

ただ調べているとこんな感じの書き込みが。

「それ(ローカルへの直接保存)ができてしまったらサイト開くだけでウイルス仕込み放題になってしまう。」

「セキュリティ的に無理」

うーん確かに。

まぁでも出来る事は出来るみたいな内容も見つけました。

ただし保存先やファイル名を自由に設定できない様で、それでは意味が無いので断念。(ダウンロード後にファイルの場所を動かしたり改名する事もできますが、手間が掛かり過ぎるので×)

ダウンロード機能だけを別出しする

引数でURLと保存先のパスを渡して実行すると、色々やってファイルをダウンロードしてくれるスクリプト(VBSとか)を用意する方法です。

途中まで作業を進めた段階で、ふと

「できれば本体のファイルのみで処理を完結させたい・・・」

と思い中断。

という訳で最後まで試してはいませんが、本体とは独立した処理で動作するはずなのでこれはこれで成功したんじゃないかと思う。

URLDownloadToFileを使用する

「そういえば・・・VBAでファイルダウンロードしてた時はまた別の処理を使ってたな・・・」

と、唐突に思い出したのでこちらも実践。

VBAではdllをインポートして使う「URLDownloadToFile」というメソッドでファイルを保存していたので、駄目元で試してみる事に。

今回はChromeブラウザの立ち上げ前後にダウンロード処理を挟んでテストしてみます。

こちらを実行してみた所、

Chromeブラウザ起動前後のどちらの処理においても、問題無くファイルをダウンロードする事が出来ました!

・・・ただし、本来ダウンロード成功時は戻り値として「0」が返ってくるはずなのになぜか数値が返って来ているのが謎。何かがエラーになっているのだとは思いますが、その割にはファイルは正常に保存できている・・・

まぁ対象のファイルがしっかり保存出来ているのでこの際戻り値は無視しても良いとは思うんですが、何か引っかかるなぁ。

結論

URLDownloadToFile」なら動く。という結果が出ました。

同じ現象で悩んでいる方がいれば、こういった解決策もあるという事で紹介しておきます。

というかこんな現象があるならどこかで話題に挙がっててもおかしくないはずなんだけど・・・やっぱり環境的な問題という事か・・・。

もしくは本当にSeleniumとWebClientクラスが相性的に悪いとかそういう話になるのかな。

気が向いたら調べてみる事にします。


スポンサーリンク