差分

このページの2つのバージョン間の差分を表示します。

この比較画面へのリンク

両方とも前のリビジョン前のリビジョン
次のリビジョン
前のリビジョン
selenium-webdriver [2023/09/07 22:47] skkselenium-webdriver [2025/02/22 16:07] (現在) skk
行 1: 行 1:
-= [[selenium-webdriver]]+= [[selenium-webdriver]] LM: [2025-02-22 16:05:39] 
 +~~NOCACHE~~ 
 ---- ----
  
行 23: 行 25:
 </code> </code>
  
 +  * [2024-06-27] chrome 126 を headless で動かそうとしたが上手く動作せず.もしかしたら,下記 URL のように,FreeBSD だと上手く動かないのかもしれない.X forward/デスクトップ環境以外で,headless のように動かしたいならば,Xvfb の方が安定すると思われる.
 +      * https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=278413
  
 ===== - ruby binding 環境での構築  [2014年頃] ===== ===== - ruby binding 環境での構築  [2014年頃] =====
行 38: 行 42:
  
 ===== - tips  ===== ===== - tips  =====
 +==== - 画像保存の方法 ====
 +
 +[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/Linux などの XWindow な環境の場合,xdotool を利用すると,簡単に XWindow 上での操作が行なえるので,selenium と組み合わせると便利かもしれない.他にも pyautogui などがあるようだが,僕の FreeBSD 環境では上手く動かせなかった.[[http://takeno.iee.niit.ac.jp/~shige/FreeBSD/fbsd-omemo.html#o-20220127|参考1]][[https://stackoverflow.com/questions/58432057/how-do-i-click-enter-when-a-save-as-window-is-open-with-selenium|参考2]]
 +
 +僕の場合,ウィンドウマネージャを指定せずに,Xvfb に対して seleinum で操作している chromium を表示している状態である.
 +
 +次に,selenium において,次のように javascript を利用してブラウザ上での右クリックを行なわせる.
 +
 +<code python>
 +driver.execute_script(f"""
 +   const downloadImage = document.createElement('a');
 +   document.body.appendChild(downloadImage);
 +   downloadImage.setAttribute('download', 'image');
 +   downloadImage.href = '{img_src}';
 +   downloadImage.click();
 +""")
 +</code>
 +
 +実行すると,Xvfb 上では名前をつけて保存ダイアログにフォーカスがあたった状態で出てくる.
 +あとは,保存先ディレクトリを指定し,保存ボタンを押す.xdotool ならば,
 +
 +<code bash>
 +% xdotool key Home
 +% xdotool type /home/skk/Downloads/
 +% xdotool key Return 
 +</code>
 +
 +となる.もしコマンドライン上で実際に動かす場合は,DISPLAY 環境変数も指定しなければならない.
 +これらのコマンドを python 上でコマンド呼出せばよい.例えば,以下のような形.
 +
 +<code python>
 +xdotool = ["xdotool", "key", "Home"]
 +subprocess.run(xdotool)
 +</code>
 +
 ==== - selenium (bot) 検知への対応について ====  ==== - selenium (bot) 検知への対応について ==== 
 特定のサイトでは,selenium でのアクセスを禁止している.UA などのアクセス情報から selenium で動作していることを検知している. 特定のサイトでは,selenium でのアクセスを禁止している.UA などのアクセス情報から selenium で動作していることを検知している.
行 44: 行 107:
   * https://stackoverflow.com/questions/67551031/how-to-pass-desired-capabilities-to-undetected-chromedriver-with-selenium-python   * https://stackoverflow.com/questions/67551031/how-to-pass-desired-capabilities-to-undetected-chromedriver-with-selenium-python
   * https://stackoverflow.com/questions/72406597/how-to-avoid-bot-detection-on-websites-using-selenium-python   * https://stackoverflow.com/questions/72406597/how-to-avoid-bot-detection-on-websites-using-selenium-python
 +  * [2025-02-22] https://www.zenrows.com/blog/selenium-cloudflare-bypass
  
 === - undetected chromedriver [2023-09-07] === === - undetected chromedriver [2023-09-07] ===
行 57: 行 121:
  
 FreeBSD で動作させる為には,[[https://www.sakaki.works/doku/doku.php?id=selenium-webdriver#undetected-chromedriver_%E3%81%AE%E5%8B%95%E4%BD%9C%E8%A8%AD%E5%AE%9A_2023-09-07|下記]]参照. FreeBSD で動作させる為には,[[https://www.sakaki.works/doku/doku.php?id=selenium-webdriver#undetected-chromedriver_%E3%81%AE%E5%8B%95%E4%BD%9C%E8%A8%AD%E5%AE%9A_2023-09-07|下記]]参照.
 +
 +=== - seleniumbase [2025-02-22] ===
 +undetected_chromedriver は,2025/02 現在,あまりメンテされておらず,Cloudflare などの anti-bot システムで検知されがちなツールになってきている模様.
 +
 +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 について === === - UA について ===
行 91: 行 169:
  
 ====== - freebsd における tips  ====== ====== - freebsd における tips  ======
 +===== - SeleniumBase の動作設定 [2025-02-22] =====
 +SeleniumBase もソースコードないでは Linux への分岐しか対応してない.ただ,undetected_chromedriver は Linux バイナリをダウンロードしてきていたので,Linux Emulation しなければならなかったが,SeleniumBase は chromedriver に対してなんらかの方法でパッチを当てているので,FreeBSD でインストールできる Chromium に附属している chromedriver をベースにして動作する.つまり,linux emulation しなくても大丈夫.
 +
 +==== - python ライブラリの準備 ====
 +<code bash>
 +# pip install seleniumbase 
 +</code>
 +
 +==== - python ライブラリの FreeBSD 対応 ====
 +/usr/local/lib/python3.11/site-packages/seleniumbase/undetected  以下に,下記のファイルが存在している.
 +
 +<code>
 +__init__.py     cdp_driver      dprocess.py     patcher.py      webelement.py
 +__pycache__     cdp.py          options.py      reactor.py
 +</code>
 +
 +patecher.py で以下.
 +
 +<code python>
 +15c16
 +< IS_POSIX = sys.platform.startswith(("darwin", "cygwin", "linux"))
 +---
 +> IS_POSIX = sys.platform.startswith(("darwin", "cygwin", "linux", "freebsd"))
 +30c31
 +<     if sys_plat.endswith("linux"):
 +---
 +>     if sys_plat.endswith("linux") or sys_plat.endswith("freebsd"):
 +</code>
 +
 +/usr/local/lib/python3.11/site-packages/seleniumbase/fixtures/shared_utils.py というファイルでも OS 分岐を行なっていたので,ここでも Linux と同じ動作にしてしまう.
 +
 +<code python>
 +47 def is_linux():
 +48     return "linux" in sys.platform or "freebsd" in sys.platform
 +</code> 
 +
 +これで少なくとも,僕の環境では SeleniumBase が FreeBSD で動作している.
 +
 ===== - undetected-chromedriver の動作設定 [2023-09-07] ===== ===== - undetected-chromedriver の動作設定 [2023-09-07] =====
 undetected-chromedriver がダウンロードできるバイナリは上述の通りで,FreeBSD で動作させる為には,以下のどちらかの対応かと考えた. undetected-chromedriver がダウンロードできるバイナリは上述の通りで,FreeBSD で動作させる為には,以下のどちらかの対応かと考えた.
行 103: 行 219:
  
 ==== - python ライブラリの準備 ====  ==== - python ライブラリの準備 ==== 
-<code>+<code bash>
 # pip install undetected-chromedriver  # pip install undetected-chromedriver 
 </code> </code>
行 161: 行 277:
 スクリプトを書いている中で,エラーが頻発した際などへの対応として,Chrome の再起動を行なう場合がある. スクリプトを書いている中で,エラーが頻発した際などへの対応として,Chrome の再起動を行なう場合がある.
  
-その時,Chrome に渡すオプションを扱う為の Opiotns() というクラスがあるが,これを再利用してはいけない模様.__init__.py の中に,以下のような記載があった.+その時,Chrome に渡すオプションを扱う為の Opiotns() というクラスがあるが,これを再利用してはいけない模様.%%__init__.py%% の中に,以下のような記載があった.
  
 <code python> <code python>
行 185: 行 301:
 <code> <code>
 window_height = @browser.driver.execute_script("return document.body.clientHeight;") window_height = @browser.driver.execute_script("return document.body.clientHeight;")
-if (window_height < 15000) # within 15000px, capture whole page. otherwise, capture on\ +if (window_height < 15000) # within 15000px, capture whole page. otherwise, capture only the displayed window
-</code> +
-ly the displayed window +
-<code>+
  @browser.screenshot.save("file.png")  @browser.screenshot.save("file.png")
 else  else 
行 196: 行 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://github.com/rdeguzman/selenium-webdriver/blob/master/lib/selenium/webdriver/common/socket_poller.rb   * https://github.com/rdeguzman/selenium-webdriver/blob/master/lib/selenium/webdriver/common/socket_poller.rb
 +
 +----
 +このページへのアクセス
 +今日: {{counter|today}} / 昨日: {{counter|yesterday}}
 +総計: {{counter|total}}
  
selenium-webdriver.1694094424.txt.gz · 最終更新: 2023/09/07 22:47 by skk
文書の先頭へ
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0