在新标签页中打开网页 Selenium + Python
Posted
技术标签:
【中文标题】在新标签页中打开网页 Selenium + Python【英文标题】:Open web in new tab Selenium + Python 【发布时间】:2015-04-10 11:46:49 【问题描述】:所以我正在尝试在我的 WebDriver 内的新选项卡上打开网站。我想这样做,因为使用 PhantomJS 为每个网站打开一个新的 WebDriver 大约需要 3.5 秒,我想要更快的速度...
我使用的是多进程python脚本,我想从每个页面中获取一些元素,所以工作流程是这样的:
Open Browser
Loop throught my array
For element in array -> Open website in new tab -> do my business -> close it
但我找不到任何方法来实现这一点。
这是我正在使用的代码。网站之间需要很长时间,我需要它快速......允许使用其他工具,但我不知道有太多工具用于废弃使用 javascript 加载的网站内容(在加载时触发某些事件时创建的 div 等)为什么我需要 Selenium... BeautifulSoup 不能用于我的某些页面。
#!/usr/bin/env python
import multiprocessing, time, pika, json, traceback, logging, sys, os, itertools, urllib, urllib2, cStringIO, mysql.connector, shutil, hashlib, socket, urllib2, re
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from PIL import Image
from os import listdir
from os.path import isfile, join
from bs4 import BeautifulSoup
from pprint import pprint
def getPhantomData(parameters):
try:
# We create WebDriver
browser = webdriver.Firefox()
# Navigate to URL
browser.get(parameters['target_url'])
# Find all links by Selector
links = browser.find_elements_by_css_selector(parameters['selector'])
result = []
for link in links:
# Extract link attribute and append to our list
result.append(link.get_attribute(parameters['attribute']))
browser.close()
browser.quit()
return json.dumps('data': result)
except Exception, err:
browser.close()
browser.quit()
print err
def callback(ch, method, properties, body):
parameters = json.loads(body)
message = getPhantomData(parameters)
if message['data']:
ch.basic_ack(delivery_tag=method.delivery_tag)
else:
ch.basic_reject(delivery_tag=method.delivery_tag, requeue=True)
def consume():
credentials = pika.PlainCredentials('invitado', 'invitado')
rabbit = pika.ConnectionParameters('localhost',5672,'/',credentials)
connection = pika.BlockingConnection(rabbit)
channel = connection.channel()
# Conectamos al canal
channel.queue_declare(queue='com.stuff.images', durable=True)
channel.basic_consume(callback,queue='com.stuff.images')
print ' [*] Waiting for messages. To exit press CTRL^C'
try:
channel.start_consuming()
except KeyboardInterrupt:
pass
workers = 5
pool = multiprocessing.Pool(processes=workers)
for i in xrange(0, workers):
pool.apply_async(consume)
try:
while True:
continue
except KeyboardInterrupt:
print ' [*] Exiting...'
pool.terminate()
pool.join()
【问题讨论】:
【参考方案1】:只是为了以后参考,简单的方法可以这样做:
driver.switch_to.new_window()
t=driver.window_handles[-1]# Get the handle of new tab
driver.switch_to.window(t)
driver.get(target_url) # Now the target url is opened in new tab
【讨论】:
【参考方案2】:你可以用它来打开一个新标签
driver.execute_script("window.open('http://google.com', 'new_window')")
【讨论】:
【参考方案3】:在一次讨论中,Simon 明确提到:
虽然用于存储句柄列表的数据类型可以按插入排序,但 WebDriver 实现迭代窗口句柄以插入它们的顺序不需要稳定。顺序是任意的。
使用Selenium v3.x 现在通过Python 在新标签 中打开网站要容易得多。我们必须为number_of_windows_to_be(2)
引入一个WebDriverWait,然后在每次打开新选项卡/窗口时收集窗口句柄,最后根据需要遍历窗口句柄和switchTo().window(newly_opened)
。这是一个解决方案,您可以在初始TAB中打开http://www.google.co.in
,在相邻TAB中打开https://www.yahoo.com
:
代码块:
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
options = webdriver.ChromeOptions()
options.add_argument("start-maximized")
options.add_argument('disable-infobars')
driver = webdriver.Chrome(chrome_options=options, executable_path=r'C:\Utility\BrowserDrivers\chromedriver.exe')
driver.get("http://www.google.co.in")
print("Initial Page Title is : %s" %driver.title)
windows_before = driver.current_window_handle
print("First Window Handle is : %s" %windows_before)
driver.execute_script("window.open('https://www.yahoo.com')")
WebDriverWait(driver, 10).until(EC.number_of_windows_to_be(2))
windows_after = driver.window_handles
new_window = [x for x in windows_after if x != windows_before][0]
driver.switch_to.window(new_window)
print("Page Title after Tab Switching is : %s" %driver.title)
print("Second Window Handle is : %s" %new_window)
控制台输出:
Initial Page Title is : Google
First Window Handle is : CDwindow-B2B3DE3A222B3DA5237840FA574AF780
Page Title after Tab Switching is : Yahoo
Second Window Handle is : CDwindow-D7DA7666A0008ED91991C623105A2EC4
浏览器快照:
结尾
您可以在Best way to keep track and iterate through tabs and windows using WindowHandles using Selenium 中找到基于java 的讨论
【讨论】:
【参考方案4】:编者注:此答案不再适用于新的 Selenium 版本。参考this comment。
您可以通过组合键COMMAND + T或COMMAND + W (OSX)。在其他操作系统上,您可以使用 CONTROL + T / CONTROL + W。
在 selenium 中,您可以模拟这种行为。 您将需要创建一个 Web 驱动程序和您需要的测试尽可能多的选项卡。
这是代码。
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
driver = webdriver.Firefox()
driver.get("http://www.google.com/")
#open tab
driver.find_element_by_tag_name('body').send_keys(Keys.COMMAND + 't')
# You can use (Keys.CONTROL + 't') on other OSs
# Load a page
driver.get('http://***.com/')
# Make the tests...
# close the tab
# (Keys.CONTROL + 'w') on other OSs.
driver.find_element_by_tag_name('body').send_keys(Keys.COMMAND + 'w')
driver.close()
【讨论】:
但是我有多进程,所以,我有 10 个并发作业,想要访问每个页面中的数据,这样做(我尝试过)以打开大量选项卡但只有一个查找元素结束和做生意 对不起,我没有得到你的陈述。您的问题是“对于数组中的元素-> 在新选项卡中打开网站-> 做我的事-> 关闭它”。因此,提议的解决方案试图回答它。你能澄清一下你在找什么吗?您确定 webdriver 是适合您的工具吗?刮痧呢? 我并没有从driver.find_element_by_tag_name('body').send_keys(Keys.COMMAND + 't')
得到预期的行为。这给了我预期的行为,如下所述:http://selenium-python.readthedocs.org/en/latest/api.html#module-selenium.webdriver.common.action_chains:ActionChains(driver).key_down(Keys.COMMAND).send_keys("t").key_up(Keys.COMMAND).perform()
它在我最近的测试中不起作用(OSX 10.10.5,selenium 2.47.1 python,Ghrome 驱动程序 2.25),在这个 post 中得到了工作方式,代码:driver.execute_script("window.open('');")
坏消息:看起来 Control-t 不再有效...... cf。 driver.find_element_by_tag_name('body').send_keys(Keys.COMMAND + 't')
...^T 已被禁用为“超出规格”参见。 github.com/mozilla/geckodriver/issues/786 还有python-forum.io/Thread-Need-Help-Opening-A-New-Tab-in-Selenium【参考方案5】:
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()
https://www.edureka.co/community/52772/close-active-current-without-closing-browser-selenium-python
【讨论】:
driver.execute_script('window.open()')
看起来更简单。【参考方案6】:
试试这个,它会起作用的:
# Open a new Tab
driver.execute_script("window.open('');")
# Switch to the new window and open URL B
driver.switch_to.window(driver.window_handles[1])
driver.get(tab_url)
【讨论】:
【参考方案7】:#Change the method of finding the element if needed
self.find_element_by_xpath(element).send_keys(Keys.CONTROL + Keys.ENTER)
这将找到元素并在新选项卡中打开它。 self 只是用于 webdriver 对象的名称。
【讨论】:
您好...检查//观看...您的答案没有详细说明。插入带有代码和参考的有效响应很有用。得出一个切实有效的解决方案。这个平台不仅仅是任何论坛。我们是世界上其他程序员和开发人员最大的帮助和支持中心。查看社区条款并了解如何发帖;【参考方案8】:正如已经多次提到的,以下方法不再有效:
driver.find_element_by_tag_name('body').send_keys(Keys.CONTROL + 't')
ActionChains(driver).key_down(Keys.CONTROL).send_keys('t').key_up(Keys.CONTROL).perform()
此外,driver.execute_script("window.open('');")
正在工作,但受到弹出窗口阻止程序的限制。我并行处理数百个标签(使用scrapy 进行网络抓取)。然而,弹出窗口拦截器在使用 JavaScript 的 window.open('')
打开 20 个新标签后激活,因此破坏了我的爬虫。
作为解决方法,我将一个标签声明为“master”,它打开了以下helper.html
:
<!DOCTYPE html>
<html><body>
<a id="open_new_window" href="about:blank" target="_blank">open a new window</a>
</body></html>
现在,我的(简化的)爬虫可以通过故意点击弹出式博客根本不考虑的链接来打开尽可能多的标签:
# master
master_handle = driver.current_window_handle
helper = os.path.join(os.path.dirname(os.path.abspath(__file__)), "helper.html")
driver.get(helper)
# open new tabs
for _ in range(100):
window_handle = driver.window_handles # current state
driver.switch_to_window(master_handle)
driver.find_element_by_id("open_new_window").click()
window_handle = set(driver.window_handles).difference(window_handle).pop()
print("new window handle:", window_handle)
通过 JavaScript 的 window.close()
关闭这些窗口没有问题。
【讨论】:
【参考方案9】:为此,我会坚持使用ActionChains。
这是一个打开新标签并切换到该标签的函数:
import time
from selenium.webdriver.common.action_chains import ActionChains
def open_in_new_tab(driver, element, switch_to_new_tab=True):
base_handle = driver.current_window_handle
# Do some actions
ActionChains(driver) \
.move_to_element(element) \
.key_down(Keys.COMMAND) \
.click() \
.key_up(Keys.COMMAND) \
.perform()
# Should you switch to the new tab?
if switch_to_new_tab:
new_handle = [x for x in driver.window_handles if x!=base_handle]
assert len new_handle == 1 # assume you are only opening one tab at a time
# Switch to the new window
driver.switch_to.window(new_handle[0])
# I like to wait after switching to a new tab for the content to load
# Do that either with time.sleep() or with WebDriverWait until a basic
# element of the page appears (such as "body") -- reference for this is
# provided below
time.sleep(0.5)
# NOTE: if you choose to switch to the window/tab, be sure to close
# the newly opened window/tab after using it and that you switch back
# to the original "base_handle" --> otherwise, you'll experience many
# errors and a painful debugging experience...
以下是应用该函数的方法:
# Remember your starting handle
base_handle = driver.current_window_handle
# Say we have a list of elements and each is a link:
links = driver.find_elements_by_css_selector('a[href]')
# Loop through the links and open each one in a new tab
for link in links:
open_in_new_tab(driver, link, True)
# Do something on this new page
print(driver.current_url)
# Once you're finished, close this tab and switch back to the original one
driver.close()
driver.switch_to.window(base_handle)
# You're ready to continue to the next item in your loop
你可以这样做wait until the page is loaded。
【讨论】:
【参考方案10】:其他解决方案不适用于 chrome driver v83。
相反,它的工作原理如下,假设只有 1 个打开标签:
driver.execute_script("window.open('');")
driver.switch_to.window(driver.window_handles[1])
driver.get("https://www.example.com")
如果已经有超过1个打开的标签,你应该先获取最后一个新创建的标签的索引,并在调用url之前切换到标签(感谢tylerl):
driver.execute_script("window.open('');")
driver.switch_to.window(len(driver.window_handles)-1)
driver.get("https://www.example.com")
【讨论】:
window_handles
只是一个列表,因此您的代码仅适用于 2 个选项卡。此外,您可能不知道您有多少个标签,因为即使 -1 索引也无济于事
我的代码只是展示如何切换标签的示例。一旦你理解了它的逻辑,你将能够切换多个选项卡。不知道 -1 索引是什么意思。
干得好兄弟,这段代码非常适用于 chrome webdriver 85 和 selenium。坚持下去
如果您想始终获取最新的标签,请使用 driver.switch_to.window(driver.window_handles[len(driver.window_handles)-1])
而不是 driver.switch_to.window(driver.window_handles[1])
。【参考方案11】:
tabs =
def new_tab():
global browser
hpos = browser.window_handles.index(browser.current_window_handle)
browser.execute_script("window.open('');")
browser.switch_to.window(browser.window_handles[hpos + 1])
return(browser.current_window_handle)
def switch_tab(name):
global tabs
global browser
if not name in tabs.keys():
tabs[name] = 'window_handle': new_tab(), 'url': url+name
browser.get(tabs[name]['url'])
else:
browser.switch_to.window(tabs[name]['window_handle'])
【讨论】:
【参考方案12】:据我所知,在 Chrome 浏览器的同一窗口中打开新的空白标签是不可能,但您可以使用网络链接打开新标签。
到目前为止,我上网并获得了关于这个问题的很好的工作内容。 请尽量按照步骤操作,不要遗漏。
import selenium.webdriver as webdriver
from selenium.webdriver.common.keys import Keys
driver = webdriver.Chrome()
driver.get('https://www.google.com?q=python#q=python')
first_link = driver.find_element_by_class_name('l')
# Use: Keys.CONTROL + Keys.SHIFT + Keys.RETURN to open tab on top of the stack
first_link.send_keys(Keys.CONTROL + Keys.RETURN)
# Switch tab to the new tab, which we will assume is the next one on the right
driver.find_element_by_tag_name('body').send_keys(Keys.CONTROL + Keys.TAB)
driver.quit()
我认为这是迄今为止更好的解决方案。
致谢:https://gist.github.com/lrhache/7686903
【讨论】:
【参考方案13】: 操作系统:Win 10, Python 3.8.1 硒==3.141.0from selenium import webdriver
import time
driver = webdriver.Firefox(executable_path=r'TO\Your\Path\geckodriver.exe')
driver.get('https://www.google.com/')
# Open a new window
driver.execute_script("window.open('');")
# Switch to the new window
driver.switch_to.window(driver.window_handles[1])
driver.get("http://***.com")
time.sleep(3)
# Open a new window
driver.execute_script("window.open('');")
# Switch to the new window
driver.switch_to.window(driver.window_handles[2])
driver.get("https://www.reddit.com/")
time.sleep(3)
# close the active tab
driver.close()
time.sleep(3)
# Switch back to the first tab
driver.switch_to.window(driver.window_handles[0])
driver.get("https://bing.com")
time.sleep(3)
# Close the only tab, will also close the browser.
driver.close()
参考:Need Help Opening A New Tab in Selenium
【讨论】:
【参考方案14】:奇怪的是,有这么多答案,而且都使用 JS 和键盘快捷键之类的代理项,而不仅仅是使用 selenium 功能:
def newTab(driver, url="about:blank"):
wnd = driver.execute(selenium.webdriver.common.action_chains.Command.NEW_WINDOW)
handle = wnd["value"]["handle"]
driver.switch_to.window(handle)
driver.get(url) # changes the handle
return driver.current_window_handle
【讨论】:
AttributeError: type object 'Command' has no attribute 'NEW_WINDOW'
看起来这仅在 selenium 预发布版本 4.0.0 中可用。在 selenium==4.0.0b2.post1 版本中,driver.execute(selenium.webdriver.remote.command.Command.NEW_WINDOW, "type": "tab")
有效。【参考方案15】:
我尝试了很长时间在 Chrome 中使用 action_keys 和 send_keys 复制标签页。唯一对我有用的是答案here。这就是我的重复标签 def 最终的样子,可能不是最好的,但对我来说效果很好。
def duplicate_tabs(number, chromewebdriver):
#Once on the page we want to open a bunch of tabs
url = chromewebdriver.current_url
for i in range(number):
print('opened tab: '+str(i))
chromewebdriver.execute_script("window.open('"+url+"', 'new_window"+str(i)+"')")
它基本上从 python 内部运行一些 java,它非常有用。希望这对某人有所帮助。
注意:我使用的是 Ubuntu,它不应该有所作为,但如果它不适合你,这可能是原因。
【讨论】:
【参考方案16】:这是改编自另一个例子的通用代码:
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
driver = webdriver.Firefox()
driver.get("http://www.google.com/")
#open tab
# ... take the code from the options below
# Load a page
driver.get('http://bings.com')
# Make the tests...
# close the tab
driver.quit()
可能的方法是:
向一个元素发送<CTRL> + <T>
#open tab
driver.find_element_by_tag_name('body').send_keys(Keys.CONTROL + 't')
通过动作链发送<CTRL> + <T>
ActionChains(driver).key_down(Keys.CONTROL).send_keys('t').key_up(Keys.CONTROL).perform()
执行一个javascript sn-p
driver.execute_script('''window.open("http://bings.com","_blank");''')
为了实现这一点,您需要确保正确设置首选项browser.link.open_newwindow 和browser.link.open_newwindow.restriction。上个版本的默认值是可以的,否则你应该需要:
fp = webdriver.FirefoxProfile()
fp.set_preference("browser.link.open_newwindow", 3)
fp.set_preference("browser.link.open_newwindow.restriction", 2)
driver = webdriver.Firefox(browser_profile=fp)
问题在于这些首选项预设为 other values 并且至少在 selenium 3.4.0 中冻结。当您使用配置文件通过 java 绑定设置它们时,会出现 exception 并且使用 python 绑定会忽略新值。
在 Java 中,有一种方法可以在与 geckodriver 对话时设置这些首选项,而无需指定配置文件对象,但它似乎尚未在 python 绑定中实现:
FirefoxOptions options = new FirefoxOptions().setProfile(fp);
options.addPreference("browser.link.open_newwindow", 3);
options.addPreference("browser.link.open_newwindow.restriction", 2);
FirefoxDriver driver = new FirefoxDriver(options);
第三个选项在 selenium 3.4.0 中为 python 做了stop working。
前两个选项在 selenium 3.4.0 中似乎也确实是 stop working。它们确实依赖于向元素发送 CTRL 键事件。乍一看似乎是 CTRL 键的问题,但由于新的multiprocess feature of Firefox 而失败。可能是这种新架构强加了这样做的新方法,或者可能是一个临时的实施问题。无论如何,我们可以通过以下方式禁用它:
fp = webdriver.FirefoxProfile()
fp.set_preference("browser.tabs.remote.autostart", False)
fp.set_preference("browser.tabs.remote.autostart.1", False)
fp.set_preference("browser.tabs.remote.autostart.2", False)
driver = webdriver.Firefox(browser_profile=fp)
...然后你就可以成功使用第一种方式了。
【讨论】:
名称“ActionChains”未定义 对于 Firefox,也可以试试这个:driver.execute_script('''window.open("about:blank");''')
@pyd from selenium.webdriver.common.action_chains import ActionChains
@ScylddeFraud 这是唯一对我有用的方法。好郁闷【参考方案17】:
经过这么长时间的努力,下面的方法对我有用:
driver.find_element_by_tag_name('body').send_keys(Keys.CONTROL + 't')
driver.find_element_by_tag_name('body').send_keys(Keys.CONTROL + Keys.TAB)
windows = driver.window_handles
time.sleep(3)
driver.switch_to.window(windows[1])
【讨论】:
你用最新版本测试过这个吗?它对我不起作用。我认为在您的情况下,您出于某种原因失去了焦点。【参考方案18】:browser.execute_script('''window.open("http://bings.com","_blank");''')
browser 是 webDriver
【讨论】:
可以和本地html文件一起使用吗? @abhi1610 是的,没关系。指示浏览器在此处打开一个新选项卡 不要忘记标签之间的切换。例如self.selenium.switch_to.window(window_name=window_name)
@Александр 您如何找到窗口名称?即使浏览器专注于第二个选项卡,我也遇到了驱动程序控制第一个选项卡的问题。
@F.M 只需使用window_name = self.selenium.window_handles[-1]
获取最后一个选项卡名称或其他可用索引的名称。以上是关于在新标签页中打开网页 Selenium + Python的主要内容,如果未能解决你的问题,请参考以下文章