差分
このページの2つのバージョン間の差分を表示します。
両方とも前のリビジョン前のリビジョン次のリビジョン | 前のリビジョン | ||
selenium-webdriver [2023/09/07 21:09] – skk | selenium-webdriver [2025/02/22 16:07] (現在) – skk | ||
---|---|---|---|
行 1: | 行 1: | ||
- | = [[selenium-webdriver]] | + | = [[selenium-webdriver]] |
+ | ~~NOCACHE~~ | ||
---- | ---- | ||
行 23: | 行 25: | ||
</ | </ | ||
+ | * [2024-06-27] chrome 126 を headless で動かそうとしたが上手く動作せず.もしかしたら,下記 URL のように,FreeBSD だと上手く動かないのかもしれない.X forward/ | ||
+ | * https:// | ||
===== - ruby binding 環境での構築 | ===== - ruby binding 環境での構築 | ||
行 37: | 行 41: | ||
* 本ページと似たような説明文章(日本語): http:// | * 本ページと似たような説明文章(日本語): http:// | ||
- | ===== tips ===== | + | ===== - tips ===== |
- | ==== selenium (bot) 検知への対応について ==== | + | ==== - 画像保存の方法 ==== |
+ | |||
+ | [2025-01-13] | ||
+ | |||
+ | selenium を使って,Web 上の画像を保存する方法は,大きく分けて, | ||
+ | |||
+ | - screenshot をとる | ||
+ | - 名前をつけて保存 | ||
+ | - 画像の URL を取得し,request.get() する | ||
+ | |||
+ | の3つな気がする.1 番目は表示さえされてれば確実に画像が保存できるのだが,画像が縮小されていると画質が落ちてしまうし,取得した画像を jpeg や webp に変換していると結構な CPU リソースを食ってしまう. | ||
+ | |||
+ | 2 番目の名前をつけて保存は,もし画像の URL とスクレイピング先のホストが同じ場合,キャッシュから保存されるので,1度の URL アクセスで画像が保存できるのでもっとも効率的になるが,違う場合,クロスサイト対策(?)の関係で,もう一度 URL アクセスが発生してしまう. | ||
+ | |||
+ | そのため,2 番目と 3 番目はアクセスという面で考えると同じになってしまう. | ||
+ | |||
+ | 状況に応じて,適した方法を選ぶ必要がある. | ||
+ | |||
+ | ==== - 名前をつけて保存 ==== | ||
+ | |||
+ | [2025-01-13] | ||
+ | |||
+ | ブラウザ上の画像を右クリックし,名前をつけて保存,と押すと,保存ダイアログが出てきて,保存先を選び,画像を保存することになる. | ||
+ | この時出てくる保存ダイアログは,ブラウザの一部ではなく,OS(Windows)の管理下にあるので,selenium からコントロールすることができない. | ||
+ | よって,名前をつけて保存の処理を自動で行ないたい場合は,selenium とは別の枠組で考える必要がある. | ||
+ | |||
+ | FreeBSD/ | ||
+ | |||
+ | 僕の場合,ウィンドウマネージャを指定せずに,Xvfb に対して seleinum で操作している chromium を表示している状態である. | ||
+ | |||
+ | 次に,selenium において,次のように javascript を利用してブラウザ上での右クリックを行なわせる. | ||
+ | |||
+ | <code python> | ||
+ | driver.execute_script(f""" | ||
+ | const downloadImage = document.createElement(' | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | """ | ||
+ | </ | ||
+ | |||
+ | 実行すると,Xvfb 上では名前をつけて保存ダイアログにフォーカスがあたった状態で出てくる. | ||
+ | あとは,保存先ディレクトリを指定し,保存ボタンを押す.xdotool ならば, | ||
+ | |||
+ | <code bash> | ||
+ | % xdotool key Home | ||
+ | % xdotool type / | ||
+ | % xdotool key Return | ||
+ | </ | ||
+ | |||
+ | となる.もしコマンドライン上で実際に動かす場合は,DISPLAY 環境変数も指定しなければならない. | ||
+ | これらのコマンドを python 上でコマンド呼出せばよい.例えば,以下のような形. | ||
+ | |||
+ | <code python> | ||
+ | xdotool = [" | ||
+ | subprocess.run(xdotool) | ||
+ | </ | ||
+ | |||
+ | ==== - selenium (bot) 検知への対応について ==== | ||
特定のサイトでは,selenium でのアクセスを禁止している.UA などのアクセス情報から selenium で動作していることを検知している. | 特定のサイトでは,selenium でのアクセスを禁止している.UA などのアクセス情報から selenium で動作していることを検知している. | ||
- | === selenium detection の解説サイト === | + | === - selenium detection の解説サイト === |
- | * https:// | + | * https:// |
- | * https:// | + | * https:// |
+ | * [2025-02-22] https:// | ||
- | === undetected chromedriver [2023-09-07] === | + | === - undetected chromedriver [2023-09-07] === |
selenium であることの検知は,主に chromedriver (webdriver) と chrome の通信の中に痕跡が残り,アクセス時にその痕跡がサーバ側に通知されてしまうことで発生する模様. | selenium であることの検知は,主に chromedriver (webdriver) と chrome の通信の中に痕跡が残り,アクセス時にその痕跡がサーバ側に通知されてしまうことで発生する模様. | ||
行 51: | 行 115: | ||
undetected-chromedriver は内部的に,以下のような動作になっている. | undetected-chromedriver は内部的に,以下のような動作になっている. | ||
- | * chrome のバージョンが指定されてなかったら,chrome のバージョンを取得する | + | |
- | * そのバージョンと同じ chromedriver をダウンロードしてくる.Windows, | + | * そのバージョンと同じ chromedriver をダウンロードしてくる.Windows, |
- | * chromedriver そのものにパッチをあてる. | + | * chromedriver そのものにパッチをあてる. |
- | * python で webdriver.Chrome() として chromedriver-> | + | * python で webdriver.Chrome() として chromedriver-> |
- | === UA について === | + | FreeBSD で動作させる為には,[[https:// |
+ | |||
+ | === - seleniumbase [2025-02-22] === | ||
+ | undetected_chromedriver は,2025/ | ||
+ | |||
+ | ZenRow というクラウドサービスを使っても anti-bot の回避はできるようだが月額がまーまー高い.広告記事だと思うけど,この ZenRow の特集記事が良くできているので参考に読むと良い. | ||
+ | |||
+ | 今は,SeleniumBase というツールまたは,nodriver というツールが最近ではアクティブな模様.nodriver は undetected_chromedriver の作者が作っている後継だけど,selenium の書きにくいところと決別したいらしく,結構独自の書き方にしないといけなくて,既存のコードがある場合には導入しにくい.SeleniumBase は undetected_chromedriver を fork して独自進化させてるっぽいので,undetected_chromedriver からの乗り換えにはとても便利. | ||
+ | |||
+ | また,multiprocessing 環境への対応を頑張った形跡が見られるのも嬉しい.undetected_chromedriver は,複数のプロセスを動かそうとすると,Text Busy と言われることがちょいちょいあった.これは,ChromeDriver を利用するたびに chromedriver をダウンロードしてきてパッチを当ててたので,複数プロセスで動かそうとすると,時々競合のような状態になっていたと想像している. | ||
+ | SeleniumBase は,初回起動時に uc_driver という,パッチを当てまくった chromedriver を作成して,以降は必要がなければずっとそれを使い続けるので,複数のプロセスから ChromeDriver(=uc_driver) を利用しても問題が起きない. | ||
+ | |||
+ | さらに,undetected_chromedriver を FreeBSD で無理矢理動かしていた時は,zombie プロセスが大量に作成されてしまったので,定期的にプログラムを再起動してゾンビを殺していたが,終了処理などがきれいになっているのか,SeleniumBase だと zombie が発生しなかった. | ||
+ | |||
+ | ということで,今から利用する場合は,SeleniumBase の方が全然良い.(nodriver ももしかしたら良いのかもしれないけど,試してはいない) | ||
+ | |||
+ | === - UA について === | ||
* headless モードで動作させると,UA に headless であることが記載されてしまう. | * headless モードで動作させると,UA に headless であることが記載されてしまう. | ||
* 不都合が生じる場合は,chrome の起動オプションで UA の変更ができるので,headless ではない記載をすると良い.UA のリストはググルといっぱい出てくる. | * 不都合が生じる場合は,chrome の起動オプションで UA の変更ができるので,headless ではない記載をすると良い.UA のリストはググルといっぱい出てくる. | ||
行 63: | 行 143: | ||
- | ==== /tmp に作成される cache の場所を変更したい.[2022-08-17] [2014年頃] | + | ==== - /tmp に作成される cache の場所を変更したい.[2022-08-17] [2014年頃] |
- | === chrome 一般 [2022-08-17] === | + | === - chrome 一般 [2022-08-17] === |
* chrome が screenshot をとる際,デフォルトでは /tmp を利用する. | * chrome が screenshot をとる際,デフォルトでは /tmp を利用する. | ||
* 環境変数 TMPDIR を指定すれば screenshot の一時保存先の変更が可能. | * 環境変数 TMPDIR を指定すれば screenshot の一時保存先の変更が可能. | ||
行 75: | 行 155: | ||
* [2022-08-17] headless 環境では,--disable-gpu をつけることで,動作が安定した.もしかしたら,--no-sandbox,--disable-dev-shm-usage も効いているかもしれないが,詳細は実験していない. | * [2022-08-17] headless 環境では,--disable-gpu をつけることで,動作が安定した.もしかしたら,--no-sandbox,--disable-dev-shm-usage も効いているかもしれないが,詳細は実験していない. | ||
- | === ruby の場合 [2014 年頃] === | + | === - ruby の場合 [2014 年頃] === |
* webdriver が利用する cache が Dir.mktmpdir で作成されるため,/ | * webdriver が利用する cache が Dir.mktmpdir で作成されるため,/ | ||
* / | * / | ||
行 88: | 行 168: | ||
- | ====== freebsd における tips ====== | + | ====== |
- | ===== undetected-chromedriver の動作設定 [2023-09-07] ===== | + | ===== - SeleniumBase の動作設定 [2025-02-22] ===== |
+ | SeleniumBase もソースコードないでは Linux への分岐しか対応してない.ただ,undetected_chromedriver は Linux バイナリをダウンロードしてきていたので,Linux Emulation しなければならなかったが,SeleniumBase は chromedriver に対してなんらかの方法でパッチを当てているので,FreeBSD でインストールできる Chromium に附属している chromedriver をベースにして動作する.つまり,linux emulation しなくても大丈夫. | ||
+ | |||
+ | ==== - python ライブラリの準備 ==== | ||
+ | <code bash> | ||
+ | # pip install seleniumbase | ||
+ | </ | ||
+ | |||
+ | ==== - python ライブラリの FreeBSD 対応 ==== | ||
+ | / | ||
+ | |||
+ | < | ||
+ | __init__.py | ||
+ | __pycache__ | ||
+ | </ | ||
+ | |||
+ | patecher.py で以下. | ||
+ | |||
+ | <code python> | ||
+ | 15c16 | ||
+ | < IS_POSIX = sys.platform.startswith((" | ||
+ | --- | ||
+ | > IS_POSIX = sys.platform.startswith((" | ||
+ | 30c31 | ||
+ | < if sys_plat.endswith(" | ||
+ | --- | ||
+ | > if sys_plat.endswith(" | ||
+ | </ | ||
+ | |||
+ | / | ||
+ | |||
+ | <code python> | ||
+ | 47 def is_linux(): | ||
+ | 48 | ||
+ | </ | ||
+ | |||
+ | これで少なくとも,僕の環境では SeleniumBase が FreeBSD で動作している. | ||
+ | |||
+ | ===== - undetected-chromedriver の動作設定 [2023-09-07] ===== | ||
undetected-chromedriver がダウンロードできるバイナリは上述の通りで,FreeBSD で動作させる為には,以下のどちらかの対応かと考えた. | undetected-chromedriver がダウンロードできるバイナリは上述の通りで,FreeBSD で動作させる為には,以下のどちらかの対応かと考えた. | ||
行 97: | 行 215: | ||
[[https:// | [[https:// | ||
- | ==== linux emulation 設定 ==== | + | ==== - linux emulation 設定 ==== |
* [[https:// | * [[https:// | ||
- | ==== python ライブラリの準備 ==== | + | ==== - python ライブラリの準備 ==== |
- | < | + | < |
# pip install undetected-chromedriver | # pip install undetected-chromedriver | ||
</ | </ | ||
行 107: | 行 225: | ||
[2023-09-07] 時点での最新版は 3.5.3. | [2023-09-07] 時点での最新版は 3.5.3. | ||
- | ==== python ライブラリの FreeBSD 対応 ==== | + | ==== - python ライブラリの FreeBSD 対応 ==== |
(もっときれいなやりかたをした方が良いと思う) | (もっときれいなやりかたをした方が良いと思う) | ||
行 151: | 行 269: | ||
- | ==== headless への対応 ==== | + | ==== - headless への対応 ==== |
undetected_chromedriver の場合,headless での動作がうまくいかない気がする.調べ切れていないが,headless で動作させると,bot detection に引っかかる可能性が高くなるっぽい. | undetected_chromedriver の場合,headless での動作がうまくいかない気がする.調べ切れていないが,headless で動作させると,bot detection に引っかかる可能性が高くなるっぽい. | ||
安定動作の為には,Xvfb を利用して,Window を立ち上げてしまう方が無難. | 安定動作の為には,Xvfb を利用して,Window を立ち上げてしまう方が無難. | ||
- | ==== undetected_driver.Chrome() の使い方の注意 ==== | + | ==== - undetected_driver.Chrome() の使い方の注意 ==== |
スクリプトを書いている中で,エラーが頻発した際などへの対応として,Chrome の再起動を行なう場合がある. | スクリプトを書いている中で,エラーが頻発した際などへの対応として,Chrome の再起動を行なう場合がある. | ||
- | その時,Chrome に渡すオプションを扱う為の Opiotns() というクラスがあるが,これを再利用してはいけない模様.__init__.py の中に,以下のような記載があった. | + | その時,Chrome に渡すオプションを扱う為の Opiotns() というクラスがあるが,これを再利用してはいけない模様.%%__init__.py%% の中に,以下のような記載があった. |
<code python> | <code python> | ||
行 171: | 行 289: | ||
- | ===== firefox? chrome? [2022-08-17] ===== | + | ===== - firefox? chrome? [2022-08-17] ===== |
* 2022 年 8 月時点では、ports において Firefox 向けの webdriver の更新が止まっているので、動作しない。 | * 2022 年 8 月時点では、ports において Firefox 向けの webdriver の更新が止まっているので、動作しない。 | ||
* Chrome は、chromium のソースコード内に webdriver が存在しているので、バージョンミスマッチを気にせず利用可能. | * Chrome は、chromium のソースコード内に webdriver が存在しているので、バージョンミスマッチを気にせず利用可能. | ||
- | ===== firefox のバグ? | + | ===== - firefox のバグ? |
* 一定以上の高さ(20000pxとか)のあるページをキャプチャしようとすると,save_screenshot が JS 部分で落ちる. | * 一定以上の高さ(20000pxとか)のあるページをキャプチャしようとすると,save_screenshot が JS 部分で落ちる. | ||
* 実装的には,firefox の js エンジンで,ページを canvas に書き出し,PNG として保存している. | * 実装的には,firefox の js エンジンで,ページを canvas に書き出し,PNG として保存している. | ||
行 183: | 行 301: | ||
< | < | ||
window_height = @browser.driver.execute_script(" | window_height = @browser.driver.execute_script(" | ||
- | if (window_height < 15000) # within 15000px, capture whole page. otherwise, capture | + | if (window_height < 15000) # within 15000px, capture whole page. otherwise, capture |
- | </ | + | |
- | ly the displayed window | + | |
- | < | + | |
| | ||
else | else | ||
行 194: | 行 309: | ||
* [2022-08-17] 2022 年時点の chrome では,高さを 2 万 px などにしても問題はなかった.マシンは 2014 年時点と同じマシンなので,スペックの問題ではないと思われる. | * [2022-08-17] 2022 年時点の chrome では,高さを 2 万 px などにしても問題はなかった.マシンは 2014 年時点と同じマシンなので,スペックの問題ではないと思われる. | ||
+ | * [2023-09-07] window.scrollTo() などをうまく利用して,数万 px の高さの Window は作らない方が無難と思われる.どこにバグが潜んでいるか怪しい. | ||
- | ===== patch [2014年頃] ===== | + | ===== - patch [2014年頃] ===== |
* 起動のタイミングの関係で、ネットワークコネクションが立ち上がるまで sleep を入れる必要があるみたい。(かな?) | * 起動のタイミングの関係で、ネットワークコネクションが立ち上がるまで sleep を入れる必要があるみたい。(かな?) | ||
* https:// | * https:// | ||
+ | |||
+ | ---- | ||
+ | このページへのアクセス | ||
+ | 今日: {{counter|today}} / 昨日: {{counter|yesterday}} | ||
+ | 総計: {{counter|total}} | ||