提问人:Uri 提问时间:2/25/2015 最后编辑:Uri 更新时间:8/31/2023 访问量:148983
如何切换到 Selenium 中的活动选项卡?
How do I switch to the active tab in Selenium?
问:
我们开发了一个 Chrome 扩展程序,我想用 Selenium 测试我们的扩展程序。我创建了一个测试,但问题是我们的扩展在安装时会打开一个新选项卡,我想我从另一个选项卡中得到了异常。是否可以切换到我正在测试的活动选项卡?或者另一种选择是从禁用扩展程序开始,然后登录我们的网站,然后才启用扩展程序。可能吗?这是我的代码:
def login_to_webapp(self):
self.driver.get(url='http://example.com/logout')
self.driver.maximize_window()
self.assertEqual(first="Web Editor", second=self.driver.title)
action = webdriver.ActionChains(driver=self.driver)
action.move_to_element(to_element=self.driver.find_element_by_xpath(xpath="//div[@id='header_floater']/div[@class='header_menu']/button[@class='btn_header signature_menu'][text()='My signature']"))
action.perform()
self.driver.find_element_by_xpath(xpath="//ul[@id='signature_menu_downlist'][@class='menu_downlist']/li[text()='Log In']").click()
self.driver.find_element_by_xpath(xpath="//form[@id='atho-form']/div[@class='input']/input[@name='useremail']").send_keys("[email]")
self.driver.find_element_by_xpath(xpath="//form[@id='atho-form']/div[@class='input']/input[@name='password']").send_keys("[password]")
self.driver.find_element_by_xpath(xpath="//form[@id='atho-form']/button[@type='submit'][@class='atho-button signin_button'][text()='Sign in']").click()
测试失败,因为在新选项卡(由扩展程序打开)中,“登录”不可见(我认为新选项卡仅在命令之后打开)。ElementNotVisibleException: Message: element not visible
self.driver.get(url='http://example.com/logout')
更新:我发现异常与额外的选项卡无关,它来自我们的网站。但是根据@aberna的回答,我用这段代码关闭了额外的选项卡:
def close_last_tab(self):
if (len(self.driver.window_handles) == 2):
self.driver.switch_to.window(window_name=self.driver.window_handles[-1])
self.driver.close()
self.driver.switch_to.window(window_name=self.driver.window_handles[0])
关闭额外的选项卡后,我可以在视频中看到我的选项卡。
答:
一些可能的方法:
1 - 使用 send_keys (CONTROL + TAB) 在选项卡之间切换
self.driver.find_element_by_tag_name('body').send_keys(Keys.CONTROL + Keys.TAB)
2 - 使用 using ActionsChains (CONTROL+TAB) 在选项卡之间切换
actions = ActionChains(self.driver)
actions.key_down(Keys.CONTROL).key_down(Keys.TAB).key_up(Keys.TAB).key_up(Keys.CONTROL).perform()
3 - 另一种方法可以利用 Selenium 方法来检查当前窗口并移动到另一个窗口:
你可以使用
driver.window_handles
查找窗口句柄列表,然后尝试使用以下方法进行切换。
- driver.switch_to.active_element
- driver.switch_to.default_content
- driver.switch_to.window
例如,要切换到上次打开的选项卡,您可以执行以下操作:
driver.switch_to.window(driver.window_handles[-1])
评论
driver.switch_to_window(driver.window_handles[1])
next_tab = context.session.driver.window_handles[1] context.session.driver.switch_to.window(next_tab)
driver.window_handles[1]
driver.window_handles[0]
这实际上在 3.x 中对我有用:
driver.switch_to.window(driver.window_handles[1])
将附加窗口句柄,因此这将选择列表中的第二个选项卡
要继续使用第一个选项卡:
driver.switch_to.window(driver.window_handles[0])
评论
不幸的是,接受的答案对我不起作用。
要打开一个新选项卡并让 selenium 切换到它,我使用了:
driver.execute_script('''window.open("https://some.site/", "_blank");''')
sleep(1) # you can also try without it, just playing safe
driver.switch_to.window(driver.window_handles[-1]) # last opened tab handle
# driver.switch_to_window(driver.window_handles[-1]) # for older versions
如果需要切换回主选项卡,请使用:
driver.switch_to.window(driver.window_handles[0])
总结:
包含打开的列表,将其用作选项卡之间的参数。window_handles
handles
tabs
switch_to.window()
评论
switch_to_window()
switch_to.window()
import itertools, time; for tab in itertools.cycle(reversed(driver.window_handles)): driver.switch_to.window(tab); time.sleep(2)
switch_to.window()
按 + 或选择假定启动时只打开一个选项卡。ctrltwindow_handles[0]
如果您打开了多个选项卡,那么它可能会变得不可靠。
这是我所做的:
old_tabs=self.driver.window_handles
#Perform action that opens new window here
new_tabs=self.driver.window_handles
for tab in new_tabs:
if tab in old tabs:
pass
else:
new_tab=tab
driver.switch_to.window(new_tab)
这将在切换到新选项卡之前积极识别它,并将活动窗口设置为所需的新选项卡。
仅仅告诉浏览器发送 + 是行不通的,因为它不会告诉 Web 驱动程序实际切换到新选项卡。ctrltab
找到了一种使用 ahk 库的方法。对于我们这些需要解决这个问题的非程序员来说非常容易。使用的 Python 3.7.3
安装 ahk。pip 安装 ahk
import ahk
from ahk import AHK
import selenium
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
options = webdriver.ChromeOptions()
options.add_experimental_option("excludeSwitches", ['enable-automation']); #to disable infobar about chrome controlled by automation.
chrome_options.add_argument('--start-maximized')
chromeDriver = webdriver.Chrome('C:\\new_software\\chromedriver.exe', chrome_options = options) #specify your chromedriver location
chromeDriver.get('https://www.autohotkey.com/')#launch a tab
#launch some other random tabs for testing.
chromeDriver.execute_script("window.open('https://developers.google.com/edu/python/introduction', 'tab2');")
chromeDriver.execute_script("window.open('https://www.facebook.com/', 'tab3');")
chromeDriver.execute_script("window.open('https://developer.mozilla.org/en-US/docs/Web/API/Window/open', 'tab4');"`)
seleniumwindow = ahk.active_window #as soon as you open you Selenium session, get a handle of the window frame with AHK.
seleniumwindow.activate() #will activate whatever tab you have active in the Selenium browser as AHK is activating the window frame
#To activate specific tabs I would use chromeDriver.switchTo()
#chromeDriver.switch_to_window(chromeDriver.window_handles[-1]) This takes you to the last opened tab in Selenium and chromeDriver.switch_to_window(chromeDriver.window_handles[1])to the second tab, etc..
评论
这是完整的脚本。
注意:删除下面小 URL 的两行中的空格。Stack Overflow 不允许此处包含微小的链接。
import ahk
import win32clipboard
import traceback
import appJar
import requests
import sys
import urllib
import selenium
import getpass
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import socket
import time
import urllib.request
from ahk import AHK, Hotkey, ActionChain # You want to play with AHK.
from appJar import gui
try:
ahk = AHK(executable_path="C:\\Program Files\\AutoHotkey\\AutoHotkeyU64.exe")
except:
ahk = AHK(executable_path="C:\\Program Files\\AutoHotkey\\AutoHotkeyU32.exe")
finally:
pass
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--start-maximized')
chrome_options.add_experimental_option("excludeSwitches", ['enable-automation']);
chromeDriver = webdriver.Chrome('C:\\new_software\\chromedriver.exe', chrome_options = chrome_options)
def ahk_disabledevmodescript():
try:
ahk = AHK(executable_path="C:\\Program Files\\AutoHotkey\\AutoHotkeyU64.exe")
except:
ahk = AHK(executable_path="C:\\Program Files\\AutoHotkey\\AutoHotkeyU32.exe")
finally:
pass
ahk_disabledevmodescriptt= [
str('WinActivate,ahk_exe chrome.exe'),
str('Send {esc}'),
]
#Run-Script
for snipet in ahk_disabledevmodescriptt:
ahk.run_script(snipet, blocking=True )
return
def launchtabsagain():
chromeDriver.execute_script("window.open('https://developers.google.com/edu/python/introduction', 'tab2');")
chromeDriver.execute_script("window.open('https://www.facebook.com/', 'tab3');")
chromeDriver.execute_script("window.open('https://developer.mozilla.org/en-US/docs/Web/API/Window/open', 'tab4');")
chromeDriver.execute_script("window.open('https://www.easyespanol.org/', 'tab5');")
chromeDriver.execute_script("window.open('https://www.google.com/search?source=hp&ei=EPO2Xf3EMLPc9AO07b2gAw&q=programming+is+not+difficult&oq=programming+is+not+difficult&gs_l=psy-ab.3..0i22i30.3497.22282..22555...9.0..0.219.3981.21j16j1......0....1..gws-wiz.....6..0i362i308i154i357j0j0i131j0i10j33i22i29i30..10001%3A0%2C154.h1w5MmbFx7c&ved=0ahUKEwj9jIyzjb_lAhUzLn0KHbR2DzQQ4dUDCAg&uact=5', 'tab6');")
chromeDriver.execute_script("window.open('https://www.google.com/search?source=hp&ei=NvO2XdCrIMHg9APduYzQDA&q=dinner+recipes&oq=&gs_l=psy-ab.1.0.0i362i308i154i357l6.0.0..3736...0.0..0.179.179.0j1......0......gws-wiz.....6....10001%3A0%2C154.gsoCDxw8cyU', 'tab7');")
return
chromeDriver.get('https://ebc.cybersource.com/ebc2/')
compoanionWindow = ahk.active_window
launchtabs = launchtabsagain()
disabledevexetmessage = ahk_disabledevmodescript()
def copyUrl():
try:
ahk = AHK(executable_path="C:\\Program Files\\AutoHotkey\\AutoHotkeyU64.exe")
except:
ahk = AHK(executable_path="C:\\Program Files\\AutoHotkey\\AutoHotkeyU32.exe")
finally:
pass
snipet = str('WinActivate,ahk_exe chrome.exe')
ahk.run_script(snipet, blocking=True )
compoanionWindow.activate()
ahk_TinyChromeCopyURLScript=[
str('WinActivate,ahk_exe chrome.exe'),
str('send ^l'),
str('sleep 10'),
str('send ^c'),
str('BlockInput, MouseMoveoff'),
str('clipwait'),
]
#Run-AHK Script
if ahk:
for snipet in ahk_TinyChromeCopyURLScript:
ahk.run_script(snipet, blocking=True )
win32clipboard.OpenClipboard()
urlToShorten = win32clipboard.GetClipboardData()
win32clipboard.CloseClipboard()
return(urlToShorten)
def tiny_url(url):
try:
apiurl = "https: // tinyurl. com / api - create. php? url= " #remove spaces here
tinyp = requests.Session()
tinyp.proxies = {"https" : "https://USER:PASSWORD." + "@userproxy.visa.com:443", "http" : "http://USER:PASSWORD." + "@userproxy.visa.com:8080"}
tinyUrl = tinyp.get(apiurl+url).text
returnedresponse = tinyp.get(apiurl+url)
if returnedresponse.status_code == 200:
print('Success! response code =' + str(returnedresponse))
else:
print('Code returned = ' + str(returnedresponse))
print('From IP Address =' +IPadd)
except:
apiurl = "https: // tinyurl. com / api - create. php? url= " #remove spaces here
tinyp = requests.Session()
tinyUrl = tinyp.get(apiurl+url).text
returnedresponse = tinyp.get(apiurl+url)
if returnedresponse.status_code == 200:
print('Success! response code =' + str(returnedresponse))
print('From IP Address =' +IPadd)
else:
print('Code returned = ' + str(returnedresponse))
return tinyUrl
def tinyUrlButton():
longUrl = copyUrl()
try:
ahk = AHK(executable_path="C:\\Program Files\\AutoHotkey\\AutoHotkeyU64.exe")
except:
ahk = AHK(executable_path="C:\\Program Files\\AutoHotkey\\AutoHotkeyU32.exe")
finally:
pass
try:
shortUrl = tiny_url(longUrl)
win32clipboard.OpenClipboard()
win32clipboard.EmptyClipboard()
win32clipboard.SetClipboardText(shortUrl)
win32clipboard.CloseClipboard()
if ahk:
try:
if str(shortUrl) == 'Error':
ahk.run_script("Msgbox,262144 ,Done.,"+ shortUrl + "`rPlease make sure there is a link to copy and that the page is fully loaded., 5.5" )
else:
ahk.run_script("Msgbox,262144 ,Done.,"+ shortUrl + " is in your clipboard., 1.5" )
# ahk.run_script("WinActivate, tinyUrl" )
except:
traceback.print_exc()
print('error during ahk script')
pass
except:
print('Error getting tinyURl')
traceback.print_exc()
def closeChromeTabs():
try:
try:
ahk = AHK(executable_path="C:\\Program Files\\AutoHotkey\\AutoHotkeyU64.exe")
except:
ahk = AHK(executable_path="C:\\Program Files\\AutoHotkey\\AutoHotkeyU32.exe")
finally:
pass
compoanionWindow.activate()
ahk_CloseChromeOtherTabsScript = [
str('WinActivate,ahk_exe chrome.exe'),
str('Mouseclick, Right, 30, 25,,1'),
str('Send {UP 3} {enter}'),
str('BlockInput, MouseMoveOff'),
]
#Run-Script
if ahk:
for snipet in ahk_CloseChromeOtherTabsScript:
ahk.run_script(snipet, blocking=True )
return(True)
except:
traceback.print_exc()
print("Failed to run closeTabs function.")
ahk.run_script('Msgbox,262144,,Failed to run closeTabs function.,2')
return(False)
# create a GUI and testing this library.
window = gui("tinyUrl and close Tabs test ", "200x160")
window.setFont(9)
window.setBg("blue")
window.removeToolbar(hide=True)
window.addLabel("description", "Testing AHK Library.")
window.addLabel("title", "tinyURL")
window.setLabelBg("title", "blue")
window.setLabelFg("title", "white")
window.addButtons(["T"], tinyUrlButton)
window.addLabel("title1", "Close tabs")
window.setLabelBg("title1", "blue")
window.setLabelFg("title1", "white")
window.addButtons(["C"], closeChromeTabs)
window.addLabel("title2", "Launch tabs")
window.setLabelBg("title2", "blue")
window.setLabelFg("title2", "white")
window.addButtons(["L"], launchtabsagain)
window.go()
if window.exitFullscreen():
chromeDriver.quit()
def closeTabs():
try:
try:
ahk = AHK(executable_path="C:\\Program Files\\AutoHotkey\\AutoHotkeyU64.exe")
except:
ahk = AHK(executable_path="C:\\Program Files\\AutoHotkey\\AutoHotkeyU32.exe")
finally:
pass
compoanionWindow.activate()
ahk_CloseChromeOtherTabsScript = [
str('WinActivate,ahk_exe chrome.exe'),
str('Mouseclick, Right, 30, 25,,1'),
str('Send {UP 3} {enter}'),
str('BlockInput, MouseMoveOff'),
]
#Run-Script
if ahk:
for snipet in ahk_CloseChromeOtherTabsScript:
ahk.run_script(snipet, blocking=True )
return(True)
except:
traceback.print_exc()
print("Failed to run closeTabs function.")
ahk.run_script('Msgbox,262144,Failed,Failed to run closeTabs function.,2')
return(False)
评论
用户“aberna”的提示通过以下方式为我工作:
首先,我得到了一个选项卡列表:
tab_list = driver.window_handles
然后我选择选项卡:
driver.switch_to.window(test[1])
返回上一个选项卡:
driver.switch_to.window(test[0])
评论
test
如果您只想关闭活动选项卡并需要保持浏览器窗口打开,则可以使用 switch_to.Window 方法,该方法将输入参数为 Window handle-ID。以下示例演示如何实现此自动化:
from selenium import webdriver
import time
driver = webdriver.Firefox()
driver.get('https://www.google.com')
driver.execute_script("window.open('');")
time.sleep(5)
driver.switch_to.window(driver.window_handles[1])
driver.get("https://facebook.com")
time.sleep(5)
driver.close()
time.sleep(5)
driver.switch_to.window(driver.window_handles[0])
driver.get("https://www.yahoo.com")
time.sleep(5)
#driver.close()
TLDR:有一种变通解决方案,但有一些限制。
我正在使用已经打开的浏览器,如下所示。问题是每次我启动脚本时,selenium 都会在内部选择一个随机选项卡。官方文档说:
单击在新窗口中打开的链接将聚焦新窗口 或选项卡,但 WebDriver 不会知道哪个窗口 操作系统认为处于活动状态。
这对我来说听起来很奇怪。因为这不是 selenium 处理和自动化浏览器交互的第一个任务吗?更重要的是,切换到任何选项卡实际上将切换 gui 中的活动选项卡。似乎这是一个错误。在撰写本文时,python-selenium 版本为 4.1.0。driver.switch_to.window(...)
让我们看看我们可以使用哪些方法。
使用硒window_handles[0]方法
上面答案的方法并不可靠。它并不总是有效。例如,当您在不同的标签页之间切换时,chromium/vivaldi 可能会开始返回的不是当前标签页。
print("Current driver tab:", driver.title) # <- the random tab title
driver.switch_to.window(chromium_driver.window_handles[0])
print("Current driver tab:", driver.title) # <-- the currently opened tab title. But not always reliable.
所以跳过这个方法。
使用远程调试方法
与以前的方法相比,没有提供任何额外的 selenium 驱动程序。
通过远程调试协议获取选项卡列表,例如
r = requests.get("http://127.0.0.1:9222/json")
j = r.json()
found_tab = False
for el in j:
if el["type"] == "page": # Do this check, because if that is background-page, it represents one of installed extensions
found_tab = el
break
if not found_tab:
print("Could not find tab", file=sys.stderr)
real_opened_tab_handle = "CDwindow-" + found_tab["id"]
driver.switch_to(real_opened_tab_handle)
实际上返回的内容与 中的内容相同。所以也跳过这个方法。driver.window_handles
X11 的解决方法
from wmctrl import Window
all_x11_windows = Window.list()
chromium_windows = [ el for el in all_x11_windows if el.wm_class == 'chromium.Chromium' ]
if len(chromium_windows) != 1:
print("unexpected numbner of chromium windows")
exit(1)
real_active_tab_name = chromium_windows[0].wm_name.rstrip(" – Chromium")
chrome_options = Options()
chrome_options.add_experimental_option("debuggerAddress", "127.0.0.1:9222")
# https://stackoverflow.com/a/70088095/7869636 - Selenium connect to existing browser.
# Need to start chromium as: chromium --remote-debugging-port=9222
driver = webdriver.Chrome(service=Service(ChromeDriverManager(chrome_type=ChromeType.CHROMIUM).install()), options=chrome_options)
tabs = driver.window_handles
found_active_tab = False
for tab in tabs:
driver.switch_to.window(tab)
if driver.title != real_active_tab_name:
continue
else:
found_active_tab = True
break
if not found_active_tab:
print("Cannot switch to needed tab, something went wrong")
exit(1)
else:
print("Successfully switched to opened tab")
print("Working with tab called:", driver.title)
这个想法是从 wmctrl 获取窗口标题,这将让您知道活动的选项卡名称。
Wayland 的变通解决方案
以前的解决方案有一个限制,wmctrl 仅适用于 x11 窗口。
我目前发现了如何获取您单击的窗口的标题。
print("Please click on the browser window")
opened_tab = subprocess.run("qdbus org.kde.KWin /KWin queryWindowInfo | grep caption", shell=True, capture_output=True).stdout.decode("utf-8")
opened_tab_title = opened_tab.rstrip(" - Vivaldi\n").lstrip("caption: ")
然后,可以使用上一个解决方案中的脚本。
该解决方案可以在 wayland 上使用 kwin 窗口列表查询进行改进。如果有人帮助改善这一点,我会很高兴。不幸的是,我目前不知道如何获取 wayland 窗口列表。
如果您突然需要 Java 解决方案,您可以这样做:
driver.switchTo().window((String) driver.getWindowHandles().toArray()[index of tab]);
评论