Django Girls and Boys 備忘録

Python、Selenium、Django、java、iPhoneアプリ、Excelマクロなどで気付いたこと、覚えておきたいことなどを載せていきます。

【Python Selenium】新規ウインドウ(新規タブ)追加時のウインドウ切替方法(追加ハンドルをハンドル差異比較にて取得)(SeleniumVer4.6以降)

Seleniumを使用してスクレイピングしている場合の話ですが、ウェブドライバーから見て新規ウインドウが追加になった時に、新しいウインドウハンドルは必ずしもブラウザのドライバのハンドル(window_handles)の末尾に追加されるわけではないようです。

 

実際に自分でウインドウ追加などをやりながらwindow_handlesを見ていたところでは、ハンドル数が1から2に増える場合には末尾に追加がほとんどだったのですが、ハンドルの数が増えてくると末尾でないところに追加される場合が多くなるような感じでした。

 

そのような場合に、新規ウインドウへの切替を行うには、新規ウインドウ追加前と追加後でwindow_handlesを比較して、追加後に追加されたハンドルを探し出してそのハンドルへの切替をする必要が出てきます。

 

そういう必要性があった時に、実際にハンドルの比較、抜き出しを行いましたので、備忘録もかねて書き残しておきます。

 

 

 

目次

 

プログラム自体はあまりいい書き方でないところもあるかと思います。

そこはご容赦ください。

 

実際に記載したプログラムの抜粋は以下のようになります。

 

尚、Seleniumのバージョンアップでウェブドライバーの設定方法が変わったこともあり、以下の例はSelenium Ver.4.6以降の場合の例として記載しています。

 

 Ver.4.6以前の場合については以下の過去記事などで載せています。

違いはドライバーの設定方法だけですが。

 

kuku81kuku81.hatenablog.com

 

 

ハンドルを比較し地道にがんばった方法

selenium ver.4.6以降の場合)

from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait

######################################################################
driver = webdriver.Chrome()  ###################################################################### before_handles = driver.window_handles before_len = len(driver.window_handles) # 新しいタブを作成する(switch_to.new_window("tab")で新タブ追加) # 新しいタブを作成し、フォーカスする driver.switch_to.new_window("tab") WebDriverWait(driver, 10).until(lambda d: len(d.window_handles) > before_len) # 新しいタブに切り替える(before_handlesとafter_handlesを比較、追加されたhandleにswiitch_to.windowで切り替える) newhandle = driver.window_handles[-1] after_handles = driver.window_handles for ahandle in after_handles: flg = 0 for bhandle in before_handles: if ahandle == bhandle: flg = 1 break if flg == 0: newhandle = ahandle break driver.switch_to.window(newhandle) driver.get('https://www.google.com/')

 

はじめの2行は必要なライブラリのインポート文です。

 

次の行でChrome用ですが、ドライバーの設定をしています。

 

次からが今回の内容ですが、

before_handles = driver.window_handles

before_len = len(driver.window_handles)

で、新規ウインドウ追加前のハンドルとその数を取得しています。

 

続いて、

driver.switch_to.new_window("tab")

で、新規ウインドウ(この例ではタブが追加)が追加されます。

 

次の、

WebDriverWait(driver, 10).until(lambda d: len(d.window_handles) > before_len)

で、追加前のハンドル数(before_len)と追加後のハンドル数(lambda d: len(d.window_handles))を比較しています。

追加後のハンドル数が追加前のハンドル数より多くなるまで最大10秒間待機します。

 

newhandle = driver.window_handles[-1]

は、初期値として末尾のハンドルを入れているだけです。

 

after_handles = driver.window_handles

にて、新規ウインドウ追加後のハンドルを取得しています。

 

それに続く、

for ahandle in after_handles:

 flg = 0

 for bhandle in before_handles:

  if ahandle == bhandle:

   flg = 1

   break

 if flg == 0:

  newhandle = ahandle break

 

で、追加前ハンドル(before_handles)と追加後ハンドル(after_handles)を比較して、追加後ハンドルの中で、追加前ハンドルにないものがあれば、それを新しいハンドル(newhandle)に入れています。

 

driver.switch_to.window(newhandle)

で、その新しいハンドルに移動しています。

 

その後、

driver.get('https://www.google.com/')

とすることで、新規タブにGoogle検索ウインドウが表示されると思います。

 

 

ここまで、やってきていろいろと調べているうちに同内容を簡単に実施できそうな方法をみつけましたので追加で記載しておきます。

 

簡潔コードによる方法

(selenium ver.4.6以降の場合)

from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
######################################################################
driver = webdriver.Chrome()  ######################################################################

before_handles = driver.window_handles before_len = len(driver.window_handles) # 新しいタブを作成する(switch_to.new_window("tab")で新タブ追加) # 新しいタブを作成し、フォーカスする driver.switch_to.new_window("tab") WebDriverWait(driver, 10).until(lambda d: len(d.window_handles) > before_len) # 新しいタブに切り替える(before_handlesとafter_handlesを比較、追加されたhandleにswiitch_to.windowで切り替える) after_handles = driver.window_handles # ウインドウハンドルの比較を行い、新規で開いたウインドウのハンドルを取得
newhandle = set(after_handles).difference(set(before_handles)).pop() driver.switch_to.window(newhandle) driver.get('https://www.google.com/')

 

最初のコードとの差異は、after_handles 取得後のfor文で地道にハンドルの差異を見つけていることが、

newhandle = set(after_handles).difference(set(before_handles)).pop()

の1行でできるということです。

 

実際に実行してみると、1つ目のプログラムと同様に2つ目の新規タブにGoogle検索ウインドウが表示されました。

 

 

以上が、ハンドル差異比較をすることで追加ハンドルを取得しながら新規ウインドウ(新規タブ)追加時のウインドウの切替をする方法になります。

 

 

 

また、PythonにてSeleniumを活用してスクレイピング、RPA化などを行っていく場合に必要となりそうな内容の記事を一覧として以下にまとめましたのでご参照ください。

 

 

kuku81kuku81.hatenablog.com

 

 

 

 

関連記事:

【PythonからWeb操作】seleniumのインストール手順 - Django Girls and Boys 備忘録

 

【PythonによるExcelファイルの読み書き】PythonのダウンロードからExcelファイルの読み書きまでの一通りすべての方法 - Django Girls and Boys 備忘録

 

【Python Selenium】Webサイトのスクレイピングなどで必要なフレーム間移動方法 - Django Girls and Boys 備忘録

 

【Python Selenium】ブラウザ用ドライバーのダウンロードとインストール - Django Girls and Boys 備忘録