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

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

ただいまの
回答率

88.91%

Python + Selenium サブミットによる認証後のJavaScript認証でエラーになります。

解決済

回答 1

投稿 編集

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

gkan

score 3

前提・実現したいこと

Python+Seleniumを活用して社内システムの操作自動化を検討しています。
その中で、WEBページ(社外パッケージ品)内にユーザーID、パスワード用のテキストボックスがあるページはsubmitによる認証、
その認証が通った後のページがBasic認証(もしくはjavascriptを使ったパスワード入力)でパスワードを要求してくるため、
Seleniumでの操作でパスワードを入力するよう言われ、エラーになります。

同じような事例があるか調べましたが、見つかりませんでした。
解決策などありましたら、ご教授いただければ幸いです。

発生している問題・エラーメッセージ

例外が発生しました: UnexpectedAlertPresentException
Alert Text: パスワードをいれてください!
Message: unexpected alert open: {Alert text : パスワードをいれてください!}
  (Session info: chrome=84.0.4147.89)
  File "C:\***\test.py", line 43, in <module>
    driver.get('https://***/menu.php3?type=xxxxxx&pass=&ip_addr= ')

該当のソースコード

import os
os.system('cls')
os.chdir('\\\\xxxxxx')

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.alert import Alert

driver = webdriver.Chrome()
driver.get('http://xxxx/login.php3')

# ID, PW
login_id = 'xxxxxx'
login_pw = 'xxxxxx'

button_login = driver.find_element_by_xpath("//input[@type='submit']") #Chromeの場合のみ確認画面があるので必要
button_login.click() #Chromeの場合のみ確認画面があるので必要

input_id = driver.find_element_by_name('id')
input_password = driver.find_element_by_name('pass')

input_id.send_keys(login_id)
input_password.send_keys(login_pw)

button_login = driver.find_element_by_xpath("//input[@type='submit']")
button_login.click()
driver.get('https://パスワードをここに入れる@xxxx/menu.php3?type=xxxxxx&pass=&ip_addr= ')

試したこと

・表記したソースはChromeDriverですが、IEDriverでも試しましたが同じ結果です。
・Basic認証画面はID入力欄がないので、ソース上はhttps://パスワード@xxxx/x.php3となっていますが、
submit認証画面(1画面目)で入力するIDを埋め込んで、https://ID:パスワード@xxxx/x.php3としてもダメです。

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

Google Chrome バージョン: 84.0.4147.89(64bit)
Internet Explorer11 バージョン:11.959.18362.0
Python バージョン:3.7.4
ChromeDriver バージョン:84.0.4147.30 
IEDriver バージョン:3.150.1.0

1画面目のログイン画面
1画面目のログイン画面

ここでログインボタンを押した後、下記のパスワード要求画面に遷移します。

2画面目のパスワード要求
パスワード要求

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

質問への追記・修正、ベストアンサー選択の依頼

  • shirai

    2020/07/23 00:11

    javascriptを使ったパスワード入力とはどのような画面ですか?Basic認証を通す代わりに無理やりJSをぶっこむやり方があるのではないかと考えています。

    キャンセル

  • gkan

    2020/07/23 13:38

    ご意見、ありがとうございます。
    補足に画面イメージを追加しました。
    Basic認証ではなく、javascriptな気がします・・・。
    2画面目でパスワードを入れて表示したフレーム分割ページでソース表示しても、参考となりそうなスクリプトが見当たりませんでした。
    1画面目でサブミット後に何かあると思うのですが。

    キャンセル

  • shirai

    2020/07/23 15:25

    この2画面目が表示された直後のDOMにはこの画面の構成要素と思われるDOMは存在しますか?
    例えば開発者ツールに「パスワードをいれてください!」という文字列はありますか?

    キャンセル

  • gkan

    2020/07/23 16:02

    フレーム分けされたページの片側に、下記javascriptによる記述を発見しました。Basic認証ではなかったですね・・・。
    ※知識不足で、フレーム分けされページのソースを見る方法を間違えておりました。申し訳ありません。

    if (pass.value=="") {
    var strAns; //入力された文字列
    strAns = prompt("パスワードをいれてください!","");
    document.Main.pass.value=strAns;
    submit();
    }

    1画面目(login.php)のサブミット認証が通れば、たとえばindex.phpというページに遷移してそこからa.htm、b.htmが表示されており、a.htmの方に上記のスクリプトがあるようなイメージです。

    キャンセル

回答 1

checkベストアンサー

+1

ではindex.phpに遷移したのち、
frameをa.htmに移して、
そこでそのJSを実行してやるといいのではないでしょうか。

# driver.find_element_by_hogehoge('fugafuga') でa.htmのframeタグを指定する
driver.switch_to.frame(driver.find_element_by_hogehoge('fugafuga'))

driver.execute_script('document.Main.pass.value="パスワード";submit();')

コメントを受けて追記

かなり難易度が高そうですね。。。

思いつくことは後2つあります。

1つ目は
1画面目を開いた後、従業員コード等を入力する前に、
JSで無理やりリクエストを投げる方法です。
詳しく紐解いて行かないと分からないですがおそらくpostリクエストだと思います。
画像を見る限りvueやangulerは使ってなさそうなシステムなので、
生JSでおそらくぶっこめると思います。

driver.execute_script('''
function send_post_request() {
  const form = document.createElement('form');
  form.method = 'post';
  form.action = 'パスワードをここに入れる@xxxx/menu.php3?';

  const id_Field = document.createElement('input');
  id_Field.type = 'hidden';
  id_Field.name = 'id';
  id_Field.value = 'hogehoge';
  form.appendChild(id_Field);

  const pass_Field = document.createElement('input');
  pass_Field.type = 'hidden';
  pass_Field.name = 'pass';
  pass_Field.value = 'fugafuga';
  form.appendChild(pass_Field);

  document.body.appendChild(form);
  form.submit();
}
send_post_request();
''')

おおよそこんなイメージでしょうか。 cf


2つ目は
pyautoguiという別のモジュールと組み合わせることです。
こちらは別途調べていただければと思いますが、
1つ目よりはシンプルだと思います。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2020/07/27 14:45

    返信が遅くなり申し訳ございません。
    login画面でサブミットされた後に呼び出された画面の初期表示でJavascriptが前に出てしまうため、
    driver.switch_to.frame(driver.find_element_by_xpath('//frame[@src="a.php3"]'))

    driver.execute_script('document.Main.pass.value="' + 'パスワード' + '";submit();')
    も実行しようとすると、パスワードを入力してください、とエラーになっていまいます。
    ※JavaScriptパスワード入力よりも優先させることができません。try exceptで、パスワード入力エラーの後にexcept側でjavascriptを実行した場合は、「Message: Error from JavaScript: 未定義または NULL 参照のプロパティ 'pass' は取得できません」
    と別のエラーになってしまいます。

    キャンセル

  • 2020/07/27 21:28

    追記しました

    キャンセル

  • 2020/07/28 15:26

    回答、ありがとうございます。
    教えていただいた方法を組み合わせながら色々と確認していった結果、以下の方法でクリアできました。

    try:
    ※ここはエラーを起こすため、なんでもOK。
    webdriver.ActionChains(driver).send_keys(Keys.ESCAPE).perform()
    except:
    driver.switch_to.frame(driver.find_element_by_xpath('//frame[1]'))
    driver.execute_script('document.Main.pass.value="パスワードを入れる";')
    driver.execute_script('document.Main.submit();')

    最初のjavascript認証はブラウザに対してのキー操作よりも優先されてしまうので、メッセージをキャンセルすることも出来ず、一度エラーを発生させなければいけないという所は気になりますが、これで問題なく後続の操作が出来るようになりました。

    様々な方法をご提示いただき、誠にありがとうございました。

    キャンセル

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

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

関連した質問

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