Python Selenium: 等待弹出窗口

huangapple go评论53阅读模式
英文:

python selenium: wait for popup window

问题

我遇到了使用Python Selenium等待弹出窗口的困难。如果我编写以下代码:

from selenium.webdriver.support import expected_conditions as ec
parent_driver = webdriver.Chrome()
parent_driver.get(url)
element = 'ignore this part of the code'
actions = ActionChains(parent_driver)
actions.move_to_element(element).click(element).perform()
##need code here to instruct selenium to wait
popup_driver = parent_driver.switch_to.active_element
##the following code doesn't solve the problem
WebDriverWait(popup_driver, 30).until(
            ec.presence_of_element_located((By.CLASS_NAME,'next_page'))
        )

这不起作用,因为代码尚未检测到弹出窗口,但我不能指示Selenium等待弹出窗口中的元素出现,而不切换到尚不存在的活动元素。弹出窗口中的元素都不会出现在父驱动程序中。我看到的用于检测弹出窗口的代码不起作用。所以我尝试了:

handles = parent_driver.window_handles
WebDriverWait.until(ec.new_window_is_opened(parent_driver.window_handles))

这不起作用,因为当弹出窗口出现时,window_handles的数量不会更改。

parent_driver.until(ec.visibility_of_element_located((arbitrary, "arbitrary")))

这不起作用,因为我在父驱动程序中看不到任何提示弹出窗口的存在。我正在处理的实际网站是Goodreads,弹出窗口出现是通过单击文本上的“x人投票”来触发的。

在我看来,弹出窗口的代码似乎不出现在父代码中。因此,我不能编写Selenium等待父代码中的某些更改,因为父代码永远不会更改。相反,我必须执行以下操作:

child_driver = driver.switch_to.active_element

但是,Selenium只会将活动驱动程序替换为子驱动程序,如果子驱动程序实际存在。更具体地说,假设在弹出窗口上存在一个在父窗口上不存在的元素,比如:

【1】:https://www.goodreads.com/list/show/1.Best_Books_Ever

英文:

I am having difficulty coding python selenium to wait for a popup window. If I write:

from selenium.webdriver.support import expected_conditions as ec
parent_driver = webdriver.Chrome()
parent_driver.get(url)
element = 'ignore this part of the code'
actions = ActionChains(parent_driver)
actions.move_to_element(element).click(element).perform()
##need code here to instruct selenium to wait
popup_driver = parent_driver.switch_to.active_element
##the following code doesn't solve the problem
WebDriverWait(popup_driver, 30).until(
            ec.presence_of_element_located((By.CLASS_NAME,'next_page'))
        )

This doesn't work because the code has not yet detected the popup window, but I cannot instruct selenium to wait for an element in the popup driver to appear without switching to the active element which does not exist yet. None of the elements in the popup_driver appear in the parent_driver. The code that I have seen for detecting popup windows does not work. So I have tried:

    handles = parent_driver.window_handles
    WebDriverWait.until(ec.new_window_is_opened(parent_driver.window_handles))

This does not work, because the number of window_handles does not change when the popup window appears.

    parent_driver.until(ec.visibility_of_element_located((arbitrary, "arbitrary")))

This does not work because I see nothing in the parent_driver that hints at the existence of a popup window. The actual website that I'm working on is goodreads

And the pop-up appears by pressing the text where it says 'x people voted'.

It seems to me that the code for the popup window does not appear in the parent code. So I cannot program selenium to wait until something changes in the parent code because the parent code will never change. Instead what I have to do is:

 child_driver = driver.switch_to.active_element

But selenium will only replace the active driver with the child driver if the child driver actually is present. More precisely, suppose there is an element that exists on the popup window that does not exist on the parent window, let's say it is

答案1

得分: 1

以下是您要翻译的内容:

The 'window' that opens when you click a ' people voted' is not an actual popup, it's just another element in the DOM. You can tell because you can't grab it and move it away from the page. It also doesn't have the chrome that a normal window would (like a close button, a title, etc.)

So, the following works just fine:

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# setting up the browser
s = Service(executable_path='bin/chromedriver.exe')
driver = webdriver.Chrome(service=s)
driver.get('https://www.goodreads.com/list/show/1.Best_Books_Ever')

# just grabbing the first one
result = driver.find_element(By.XPATH, "//*[contains(text(), 'people voted')]")
result.click()

# wait for the 'box' element to appear
wait = WebDriverWait(driver, 10)
element = wait until(EC.presence_of_element_located((By.ID, "box"))

# 'element' is what you want, but wait for it to complete loading, which is when this appears
wait.until(EC.presence_of_element_located((By.ID, "loadingPage"))

# now you can access its contents
print(element.text)

# close the browser, you're done
driver.close()

Having said that, these sites tend to not like you scraping them heavily, so either choose a focused approach, or don't be too surprised if your requests end up getting blocked. Regardless, using an API would be a better idea, if one is available.

The ID for the 'popup' you're waiting for just happens to be the non-descript 'box'. And just waiting for the box to load will get you an empty element if your code runs fast enough, so you'd want to wait for the 'loadingPage' element to have loaded as well, as it only loads after the interesting content has been added.

Note that I'm purposefully using double quotes around the argument passed to find_element and presence_of_element_located, since the values for that argument often contain ' themselves.

英文:

The 'window' that opens when you click a '<n> people voted' is not an actual popup, it's just another element in the DOM. You can tell because you can't grab it and move it away from the page. It also doesn't have the chrome that a normal window would (like a close button, a title, etc.)

So, the following works just fine:

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# setting up the browser
s = Service(executable_path='bin/chromedriver.exe')
driver = webdriver.Chrome(service=s)
driver.get('https://www.goodreads.com/list/show/1.Best_Books_Ever')

# just grabbing the first one
result = driver.find_element(By.XPATH, "//*[contains(text(), 'people voted')]")
result.click()

# wait for the 'box' element to appear
wait = WebDriverWait(driver, 10)
element = wait.until(EC.presence_of_element_located((By.ID, "box")))

# `element` is what you want, but wait for it to complete loading, which is when this appears
wait.until(EC.presence_of_element_located((By.ID, "loadingPage")))

# now you can access its contents
print(element.text)

# close the browser, you're done
driver.close()

Having said that, these sites tend to not like you scraping them heavily, so either choose a focused approach, or don't be too surprised if your requests end up getting blocked. Regardless, using an API would be a better idea, if one is available.

The ID for the 'popup' you're waiting for just happens to be the non-descript box. And just waiting for the box to load will get you an empty element if your code runs fast enough, so you'd want to wait for the loadingPage element to have loaded as well, as it only loads after the interesting content has been added.

Note that I'm purposefully using double quotes around the argument passed to find_element and presence_of_element_located, since the values for that argument often contain ' themselves.

huangapple
  • 本文由 发表于 2023年2月27日 08:39:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/75575936.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定