如何将Selenium浏览器置于前台?

23

如果浏览器窗口在后台,则此行不起作用。

from selenium import webdriver

from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
# available since 2.4.0
from selenium.webdriver.support.ui import WebDriverWait
# available since 2.26.0
from selenium.webdriver.support import expected_conditions as EC

browser = webdriver.Firefox()
browser.get(someWebPage)

element = WebDriverWait(browser, 10).until(
    EC.element_to_be_clickable((By.XPATH, '//button[contains(., "Watch")]')))

elements = browser.find_elements_by_xpath('//button[contains(., "Watch")]')
if elements:
    print 'find watch button',elements
    elements[0].click()

它出错了,显示为

  File "myScript.py", line 1469, in getSignedUrl
    EC.element_to_be_clickable((By.XPATH, '//button[contains(., "Watch")]')))
  File "C:\Python27\lib\site-packages\selenium\webdriver\support\wait.py", line 71, in until
    raise TimeoutException(message)
TimeoutException: Message: ''

如果我把浏览器窗口放在前面,就不会出现错误。这是因为我不应该使用 EC.element_to_be_clickable 吗?我试过忽略错误并继续点击我想要的按钮,但如果浏览器窗口在后台,它会说找不到按钮。所以我想我应该在代码执行到那行之前将浏览器窗口移到前台吗?

我看到有些人讨论 switchTo() 方法。但我的浏览器对象没有这个方法。我该怎么做才能独立于系统地将窗口置于前台?谢谢。

测试系统:

Python 2.7 Windows 7 x64

Python 2.6.6 CentOS 6.4

编辑:我试过了

browser.execute_script("window.focus();")

# commented out EC.element_to_be_clickable as suggested by alecxe
# element = WebDriverWait(browser, 20).until(
#     EC.element_to_be_clickable((By.XPATH, '//button[contains(., "Watch")]')))
print 'sleeping 5'
time.sleep(5)
elements = browser.find_elements_by_xpath('//button[contains(., "Watch")]')

print 'before clicking'

from selenium.webdriver.common.action_chains import ActionChains
hover = ActionChains(browser).move_to_element(elements[0])
hover.perform()

print elements
elements[0].click()

无法工作

编辑2:我查看了文档

class selenium.webdriver.support.expected_conditions.element_to_be_clickable(locator)[source]

    An Expectation for checking an element is visible and enabled such that you can click it.
似乎因为当窗口处于后台或最小化时,元素不可见,所以这个条件永远不会被满足? 不管怎样,我尝试了另一个条件
class selenium.webdriver.support.expected_conditions.presence_of_element_located(locator)[source]

    An expectation for checking that an element is present on the DOM of a page. This does not necessarily mean that the element is visible. locator - used to find the element returns the WebElement once it is located

看起来这个代码可以工作了。之前我尝试完全删除条件,但它并不能工作,可能只是因为我没有“等待”够久(睡眠5秒)。

编辑3:奇怪的是,在拥有selenium 2.39 python 2.6.6 firefox 28 centos 6.4的计算机上,相同的代码可以正常工作,即使浏览器窗口最小化。但是在另外两台机器上尝试同样的代码失败了,必须将浏览器窗口最大化并使按钮“可见”。 A. win7 x64 firefox 28 selenium 2.41 python2.7 B. Fedora 20 firefox 28 selenium 2.41 python2.7


你能否在点击之前尝试使用move_to_element()方法移动到该元素上? - alecxe
@alecxe 但是它在EC.element_to_be_clickable行出现错误(在我点击它之前),元素为None,我如何在没有引用的情况下移动到它?页面使用一些ajax调用,我必须等待按钮出现,但只要它在后台,无论我等多久,它都不会“出现”到webdriver中,实际上它出现在浏览器窗口中,我可以看到它。 - Shuman
移除 EC.element_to_be_clickable 检查,尝试使用 move_to_element() - alecxe
@alecxe,你的意思是这样吗?请看问题编辑。哦等等,如何访问这个 move_to_element() 方法呢?它不在浏览器对象中。 - Shuman
9个回答

14

2
对于Python3:driver.switch_to.window(driver.current_window_handle) - etayluz
2
@etayluz 谢谢您 - 我已经更新了答案以匹配。看起来旧的方法已被弃用。 - Taylor D. Edmiston

7
为了回答您最初的问题,您需要使用浏览器的最大化窗口方法来恢复焦点并置于前景。 在Python中应该是这样的:
browser.maximize_window()

我在Windows 7 x64上尝试了这个,Firefox窗口最大化在后台运行,但仍然出现了错误。 - Shuman
这非常奇怪。这将始终将其带到我的前台。我假设您在尝试我的建议时的代码看起来像这样? 尝试:browser.locateElement(x) except: browser.maximize_window() browser.locateElement(x) 此外,出于好奇,您还运行了什么其他程序,为什么不能仅给予浏览器100%的前台访问权限(例如通过提供专用虚拟机)? - HRVHackers
普通用户只有一个屏幕,他们需要一个正常的 Firefox 窗口进行其他工作。Selenium Firefox 不应该被使用。而且大多数用户都在 Windows 上,如何设置虚拟机?对于 browser.locateElement(x),我怎么才能先获取元素 x 的引用呢?通过使用 xpath 吗?(但这假设 x 已经存在,但它可能是由 Ajax 加载的,但我可以等待足够长的时间来显示它) - Shuman
我不明白你所说的用户只有一个屏幕是什么意思。你的公司应该为测试工作专门分配独立的机器,无论是物理机还是虚拟机(使用Virtualbox)。 - HRVHackers
2
我尝试使用Chrome驱动程序在macOS上通过Python使用Selenium,但它对窗口没有任何影响。 - Taylor D. Edmiston
显示剩余4条评论

4

在C#中,使用

Driver.SwitchTo().Window ( Driver.CurrentWindowHandle );

并没有将窗口置于最前,而是让它在其他窗口中保持焦点,并按照其Z序排序。

以下代码有效:

protected void BringWindowToFront()
{
    var window = Driver.Manage ().Window;
    var position = window.Position;
    window.Minimize();
    window.Position = position;
}

3

我现在不会用Python,但是我在Groovy中解决这个问题的方法如下:

browser.js."alert()"
webdriver.switchTo().alert().accept()

我调用了javascript的alert函数,它将窗口置于前台,然后我使用webdriver.switchTo().alert().accept()来关闭警告框。希望Python中也有类似的功能。
希望这能帮到你!

这对我有用,它帮助我从Zoom用户配置文件中获取了zoom host_key,感谢@joshua-king。 - DouadyRabbit

3

Python 3.9.8 和 Chrome 106:

def bring_to_front():
    position = driver.get_window_position()
    driver.minimize_window()
    driver.set_window_position(position['x'], position['y'])

这对我来说非常有效! - ejn
哎呀,在Java中就像这样:´Point position = driver.manage().window().getPosition(); ...´ - undefined

3

这是一个完全的hack,但我在Windows 7中使用IE和Selenium远程驱动程序时它起作用了。

driver.get("about:blank")  
driver.minimize_window()  
driver.maximize_window()  
driver.minimize_window()  
driver.maximize_window()  

我发送一个空白页面,再最小化和最大化两次。看起来新创建的 IE 窗口会获得前台焦点。

在C#中,我通过访问chromeDriver.Manage().Window并在其上调用Minimize()然后Maximize()来使其正常工作。 - user6285331
2
感觉有点破解的味道,但比其他方法都要好。 - user337598

3

在Python 36中测试并且工作正常。

driver1 = webdriver.Chrome()
driver1.get("http://www.python.org")
pyName = driver1.title
pyHandle = driver1.window_handles[0]
driver2 = webdriver.Chrome()
driver2.get("http://www.ruby-lang.org/en")
rubyName = driver2.title
rubyHandle = driver2.window_handles[0]
#driver 2 at this time will be in the foreground
driver1.switch_to.window(pyHandle)
driver1.switch_to_window(driver1.current_window_handle)

编辑:switch_to_window已被弃用,请使用switch_to.window


1
默认情况下,Selenium不公开驱动程序进程ID或浏览器hwnd,但这是可能的。 以下是获取hwnd的逻辑:
  • 初始化驱动程序时,获取hub的url并提取端口号
  • 从端口号中找到正在使用此端口进行侦听的进程ID,即驱动程序的PID
  • 导航后,从所有iexplore实例中查找父PID与驱动程序的PID匹配,即浏览器PID。
  • 获取浏览器PID的Hwnd 一旦找到浏览器hwnd,您可以使用win32 api将Selenium置于前台。
无法在此处发布完整的代码,将浏览器置于前台的完整工作解决方案(C#)在我的博客上。

http://www.pixytech.com/rajnish/2016/09/selenium-webdriver-get-browser-hwnd/


1
这对我也起作用(Python 3.8.0,chromedriver和Windows 10):
ws = driver.get_window_size()
driver.minimize_window()
driver.set_window_size(ws['width'], ws['height'])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接