如何切换到 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
,因为在新标签页中(由扩展打开)"Log In"是不可见的(我认为只有在命令[=13=之后才打开新标签页) ]).
更新:我发现异常与额外选项卡无关,它来自我们的网站。但是根据@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 - 使用 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 方法来检查当前 window 并移动到另一个:
您可以使用
driver.window_handles
查找 window 句柄列表,然后尝试使用以下方法进行切换。
- driver.switch_to.active_element
- driver.switch_to.default_content
- driver.switch_to.window
例如,要切换到上次打开的标签页,您可以这样做:
driver.switch_to.window(driver.window_handles[-1])
这实际上对我有用 3.x:
driver.switch_to.window(driver.window_handles[1])
window 句柄已附加,因此这将选择列表中的第二个选项卡
继续第一个选项卡:
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
包含已打开 tabs
的 handles
列表,将其用作 switch_to.window()
中的参数以在选项卡之间切换。
按下 ctrl+t 或选择 window_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)
这会在切换到新标签之前明确识别新标签并将活动 window 设置为所需的新标签。
只是告诉浏览器发送 ctrl+tab 是行不通的,因为它没有告诉 webdriver 实际切换到新标签页。
找到了使用 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..
这是完整的脚本。
注:去掉下面tinyURL两行的空格。 Stack Overflow 不允许在此处使用微小的 link。
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])
如果您只想关闭活动选项卡并需要保持浏览器 window 打开,您可以使用 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:有一个变通解决方案,但有一些限制。
我正在使用已经打开的浏览器,如图所示here. The problem is that every time I launch the script, selenium internally selects a random tab. The official documentation 说:
Clicking a link which opens in a new window will focus the new window
or tab on screen, but WebDriver will not know which window the
Operating System considers active.
我听起来很奇怪。因为这不是 selenium 处理和自动化浏览器交互的首要任务吗?更重要的是,切换到 driver.switch_to.window(...)
的任何选项卡实际上 将 切换 gui 中的活动选项卡。似乎这是一个错误。在撰写本文时,python-selenium 版本为 4.1.0.
让我们看看我们可以使用哪些方法。
使用硒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 driver 中的内容之外,没有提供任何额外内容。
通过类似
的远程调试协议获取选项卡列表
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)
实际上 returns 与 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://whosebug.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 获取 window 标题,这将让您知道活动标签名称。
Wayland 的解决方案
之前的解决方案有一个限制,wmctrl 仅适用于 x11 windows。
我目前找到了如何获取您单击的 window 的标题。
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 window 列表查询来改进解决方案。 如果有人帮助改进这个,我会很高兴。不幸的是,我目前不知道如何获取 wayland 列表 windows。
我们开发了一个 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
,因为在新标签页中(由扩展打开)"Log In"是不可见的(我认为只有在命令[=13=之后才打开新标签页) ]).
更新:我发现异常与额外选项卡无关,它来自我们的网站。但是根据@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 - 使用 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 方法来检查当前 window 并移动到另一个:
您可以使用
driver.window_handles
查找 window 句柄列表,然后尝试使用以下方法进行切换。
- driver.switch_to.active_element
- driver.switch_to.default_content
- driver.switch_to.window
例如,要切换到上次打开的标签页,您可以这样做:
driver.switch_to.window(driver.window_handles[-1])
这实际上对我有用 3.x:
driver.switch_to.window(driver.window_handles[1])
window 句柄已附加,因此这将选择列表中的第二个选项卡
继续第一个选项卡:
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
包含已打开 tabs
的 handles
列表,将其用作 switch_to.window()
中的参数以在选项卡之间切换。
按下 ctrl+t 或选择 window_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)
这会在切换到新标签之前明确识别新标签并将活动 window 设置为所需的新标签。
只是告诉浏览器发送 ctrl+tab 是行不通的,因为它没有告诉 webdriver 实际切换到新标签页。
找到了使用 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..
这是完整的脚本。
注:去掉下面tinyURL两行的空格。 Stack Overflow 不允许在此处使用微小的 link。
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])
如果您只想关闭活动选项卡并需要保持浏览器 window 打开,您可以使用 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:有一个变通解决方案,但有一些限制。
我正在使用已经打开的浏览器,如图所示here. The problem is that every time I launch the script, selenium internally selects a random tab. The official documentation 说:
Clicking a link which opens in a new window will focus the new window or tab on screen, but WebDriver will not know which window the Operating System considers active.
我听起来很奇怪。因为这不是 selenium 处理和自动化浏览器交互的首要任务吗?更重要的是,切换到 driver.switch_to.window(...)
的任何选项卡实际上 将 切换 gui 中的活动选项卡。似乎这是一个错误。在撰写本文时,python-selenium 版本为 4.1.0.
让我们看看我们可以使用哪些方法。
使用硒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 driver 中的内容之外,没有提供任何额外内容。
通过类似
的远程调试协议获取选项卡列表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)
实际上 returns 与 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://whosebug.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 获取 window 标题,这将让您知道活动标签名称。
Wayland 的解决方案
之前的解决方案有一个限制,wmctrl 仅适用于 x11 windows。
我目前找到了如何获取您单击的 window 的标题。
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 window 列表查询来改进解决方案。 如果有人帮助改进这个,我会很高兴。不幸的是,我目前不知道如何获取 wayland 列表 windows。