Selenium chromedriverに問題があり、原因を特定できません。数週間前、すべてが正常に機能していましたが、突然このエラーが表示され始めました。問題は次の関数にあります。
_ def login_(browser):
try:
browser.get("some_url")
# user credentials
user = browser.find_element_by_xpath('//*[@id="username"]')
user.send_keys(config('user'))
password = browser.find_element_by_xpath('//*[@id="password"]')
password.send_keys(config('pass'))
login = browser.find_element_by_xpath('/html/body/div[1]/div/button')
login.send_keys("\n")
time.sleep(1)
sidebar = browser.find_element_by_xpath('//*[@id="sidebar"]/ul/li[1]/a')
sidebar.send_keys("\n")
app_submit = browser.find_element_by_xpath('//*[@id="sidebar"]/ul/li[1]/ul/li[1]/a')
app_submit.send_keys("\n")
except TimeoutException or NoSuchElementException:
raise LoginException
_
この関数は開発環境(macOS 10.11)では問題なく機能しますが、本番環境では次のエラーをスローします。
_Message: no such element: Unable to locate element: {"method":"xpath","selector":"//*[@id="sidebar"]/ul/li[1]/a"}
(Session info: headless chrome=67.0.3396.79)
(Driver info: chromedriver=2.40.565383 (76257d1ab79276b2d53ee97XXX),platform=Linux 4.4.0-116-generic x86_64)
_
各環境でChromeとchromedriver(それぞれv67と2.40))を更新しました。さらにtime.sleep(15)
も追加しました。しかし問題は解決しません。私の最新の推測はおそらく、Webドライバーの初期化が正しく機能していません。
_def initiate_webdriver():
option = webdriver.ChromeOptions()
option.binary_location = config('GOOGLE_CHROME_BIN')
option.add_argument('--disable-gpu')
option.add_argument('window-size=1600,900')
option.add_argument('--no-sandbox')
if not config('DEBUG', cast=bool):
display = Display(visible=0, size=(1600, 900))
display.start()
option.add_argument("--headless")
else:
option.add_argument("--incognito")
return webdriver.Chrome(executable_path=config('CHROMEDRIVER_PATH'), chrome_options=option)
_
Display
が機能していない場合は、言及されたsidebar
がなく、他のボタンがある可能性があるためです。
だから私の質問は:誰かが同様の問題を抱えていませんか?ドライバーがそのような要素を探しているときにページが何を表示しているかを知る方法はありますか?
login_(browser)
メソッドによるいくつかのこと:
Loginボタンを特定すると、次のようになります。
_login = browser.find_element_by_xpath('/html/body/div[1]/div/button')
_
私はむしろsend_keys("\n")
を呼び出すことをお勧めします onclick()login.click()
を介したイベントの助けを借りますログインボタンのクリックを次のように模擬します。
_login = browser.find_element_by_xpath('/html/body/div[1]/div/button')
login.click()
_
次に、次のようにsidebarを特定すると、WebDriverWaitがelementをクリックできるようになります:
_WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, '//*[@id="sidebar"]/ul/li[1]/a'))).click()
_
あなたのコードコードブロックはmacOS 10.11環境で完璧に動作しますが、本番環境(Linux)で次のエラーをスローします異なるブラウザが HTML DOM を異なるOSアーキテクチャで異なるようにレンダリングする可能性が高いです。したがって、absolute xpathの代わりに、次のようにrelative xpathを使用する必要があります。
_WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//a[@attribute='value']"))).click()
_
initiate_webdriver()
メソッドによるいくつかのこと:
ヘッドレスChromeの使用開始 引数_--disable-gpu
_はWindowsにのみ適用されますLinux OSの有効な構成ではありません。だから削除する必要があります:
_option.add_argument('--disable-gpu')
_
注:次のインポートを追加する必要があります:
_from Selenium.webdriver.support.ui import WebDriverWait
from Selenium.webdriver.common.by import By
from Selenium.webdriver.support import expected_conditions as EC
_
ログインを提供した後、要素が見つからないというエラーが報告されたため、ログインが失敗し、ページがどこかにリダイレクトされたと思います。スクリーンショットオプションを使用して、ページのスクリーンショットを撮り、ドライバーがロードするページを確認できます。
driver.save_screenshot("path to save screen.jpeg")
また、未加工のhtmlコードを保存して、同じページを検査することもできます。
このようにSeleniumで奇妙な問題に遭遇したときはいつでも、断続的なトラブルを引き起こしている特定の要素を見つけるために再試行することを好みます。 1つの方法は、それをtry-exceptブロックにラップすることです。
try:
sidebar = browser.find_element_by_xpath('//*[@id="sidebar"]/ul/li[1]/a')
except NoSuchElementException:
time.sleep(10)
print("Unable to find element in first time, trying it again")
sidebar = browser.find_element_by_xpath('//*[@id="sidebar"]/ul/li[1]/a')
自動化コードを機能させるために、適切なカウント変数を使用してtry
コードをループに入れることもできます。 (チェック this )。私のJavaの経験では、このアイデアは複数の問題を解決しました。
要素が表示されるまで待つ必要があります。そうしないと、このエラーが発生します。このようなものを試してください:
from Selenium.webdriver.support.wait import WebDriverWait
from Selenium.webdriver.support.expected_conditions import visibility_of_element_located
from Selenium.webdriver.common.by import By
TIMEOUT = 5
...
xpath = '//*[@id="sidebar"]/ul/li[1]/a'
WebDriverWait(self.Selenium, TIMEOUT).until(visibility_of_element_located((By.XPATH, xpath)))
browser.find_element_by_xpath(xpath)
...