質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.92%

「Selenium × Firefox × Python」で、ActionChainsモジュールで2回以上同じアクションを行う方法について

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 290

M_T3

score 2

前提・実現したいこと

「Selenium × Firefox × Python」の環境でブラウザ操作の自動化を行っています。

ActionChainsモジュールを使用した操作について、
2回以上同じ操作を行う際のコードの書き方をご教示ください。

【自動化したい処理について】
マウスのホバーでメニューが表示されるドロップダウンリストについて、
「リストにホバー → 任意のメニューを選択 → 表示された画面を閉じる」
という一連の操作を、ActionChainsモジュールのmove_to_element()メソッドを
使用して実現しようとしています。

【発生している事象】
該当のコードの20行目「actions.move_to_element(target_list).perform()」で
リストへのホバーが実行されず処理が停止する。

【期待値】
リストへのホバーが実行され、2回目以降の処理も停止せず実行されること

【備考】
Chromeで同様のコードを実行した場合は、問題なく最後まで処理が実行されました。

ご回答をよろしくお願いいたします。

該当のソースコード

from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains

# ----------------------------------------------------------------------------------------------------
driver = webdriver.Firefox(executable_path = "ドライバーパス")

driver.maximize_window()
driver.get("サイトURL")


## ホバーでメニューが表示されるドロップダウンリスト操作
actions = ActionChains(driver)
target_list = driver.find_element_by_xpath('リストのxpath')

# 1回目
actions.move_to_element(target_list).perform()
driver.find_element_by_xpath("XXXX").click() # 任意のメニューを選択
driver.find_element_by_xpath("XXXX").click() # 表示された画面を閉じる

# 2回目
actions.move_to_element(target_list).perform()
driver.find_element_by_xpath("XXXX").click() # 任意のメニューを選択
driver.find_element_by_xpath("XXXX").click() # 表示された画面を閉じる

driver.quit()
# ----------------------------------------------------------------------------------------------------

補足情報(FW/ツールのバージョンなど)

OS:Windows10 1909
言語:Python 3.7.3
ブラウザ:Firefox 78.0.2(64bit)
WEBドライバー:geckodriver.exe 0.26.0(64bit)

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

check解決した方法

0

自己解決したので方法を記載しておきます。

結論から言うと、ActionChainsモジュールのインスタンスを生成後、
reset_actions()メソッドを呼び出し、保存されているアクションを逐一
解放してあげることで、同じ処理を複数回行うことができるようになりました。

■参考:非公式リファレンス「Selenium Python Bindings 2」
https://kurozumi.github.io/selenium-python/api.html#module-selenium.webdriver.common.action_chains

例として、質問文内の「該当のソースコード」の該当処理部分を
以下のように変更することで、コードの最後まで実行が可能となりました。

## ホバーでメニューが表示されるドロップダウンリスト操作
target_list = driver.find_element_by_xpath('リストのxpath')

# 1回目
actions = ActionChains(driver)
actions.move_to_element(target_list).perform()
driver.find_element_by_xpath("XXXX").click() # 任意のメニューを選択
driver.find_element_by_xpath("XXXX").click() # 表示された画面を閉じる

# 2回目
actions = ActionChains(driver)
actions.reset_actions() # キューに溜められたアクションを解放
actions.move_to_element(target_list).perform()
driver.find_element_by_xpath("XXXX").click() # 任意のメニューを選択
driver.find_element_by_xpath("XXXX").click() # 表示された画面を閉じる

※ 1回目の実行前のリセットは必要ありません。
※ 各実行ごとにインスタンスの生成(actions = ActionChains())を入れないとエラーとなります。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

1回目が終わった後にもう一度

actions = ActionChains(driver)
target_list = driver.find_element_by_xpath('リストのxpath')

を入れてみてください。

コメントを受けて追記

だったらこれ試してみてください。

マウスのホバーとその後のクリックの代わりにこれをやるイメージです。

driver.execute_script('''
function post(path, params, method='post') {
  const form = document.createElement('form');
  form.method = method;
  form.action = path;

  for (const key in params) {
    if (params.hasOwnProperty(key)) {
      const hiddenField = document.createElement('input');
      hiddenField.type = 'hidden';
      hiddenField.name = key;
      hiddenField.value = params[key];

      form.appendChild(hiddenField);
    }
  }

  document.body.appendChild(form);
  form.submit();
}
post('/contact/', {name: 'Johnny Bravo'});
''')

DOM上に無理やりこのJSを出現させて実行するイメージです。
実際のところはGETリクエストになると思います。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/08/12 11:08

    返信が遅くなり申し訳ありません。

    そうですね、sleep()などによるwaitでは解消されませんでした。
    また、内部の作り的にpyautoguiモジュールのキー操作で要素にフォーカスし、
    何らかのキー操作を行っても反応しなかったので、こちらについても対処は難しそうです。

    しかし、色々と調べていましたら自己解決できましたので、同事象で困っている他ユーザの
    ためにも別途記入しておきます。

    shiraiさんには何度もご回答いただき大変助かりました。ありがとうございました。
    また何かありましたらよろしくお願いいたします。

    キャンセル

  • 2020/08/12 12:59

    release() って 駄目でしょうか?

    キャンセル

  • 2020/08/12 14:47

    「reset_actions()の代わりにrelease()で実現できるか?」という意味であれば、
    私が試した限りではうまくいきませんでした。。
    (引数の指定の仕方が間違っているだけかもしれませんが...)

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.92%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • トップ
  • Pythonに関する質問
  • 「Selenium × Firefox × Python」で、ActionChainsモジュールで2回以上同じアクションを行う方法について