Abrir web en nueva pestaña Selenium + Python

11 minutos de lectura

[*]
robert w cazador

Así que estoy tratando de abrir sitios web en nuevas pestañas dentro de mi WebDriver. Quiero hacer esto, porque abrir un nuevo WebDriver para cada sitio web toma alrededor de 3.5 segundos usando PhantomJS, quiero más velocidad…

Estoy usando una secuencia de comandos de Python multiproceso y quiero obtener algunos elementos de cada página, por lo que el flujo de trabajo es así:

Open Browser

Loop throught my array
For element in array -> Open website in new tab -> do my business -> close it

Pero no puedo encontrar ninguna manera de lograr esto.

Aquí está el código que estoy usando. Se tarda una eternidad entre sitios web, necesito que sea rápido… Se permiten otras herramientas, pero no conozco demasiadas herramientas para desechar el contenido del sitio web que se carga con JavaScript (divs creados cuando se activa algún evento al cargar, etc.) Eso es por qué necesito Selenium… BeautifulSoup no se puede usar para algunas de mis páginas.

#!/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,"https://stackoverflow.com/",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()

1646957710 273 Abrir web en nueva pestana Selenium Python
aberna

Nota del editor: Esta respuesta ya no funciona para las nuevas versiones de Selenium. Consulte este comentario.


Puede lograr la apertura/cierre de una pestaña mediante la combinación de teclas MANDO + T o MANDO + W (OSX). En otros sistemas operativos puede usar CONTROL + T / CONTROL + W.

En selenium puedes emular tal comportamiento. Deberá crear un controlador web y tantas pestañas como las pruebas que necesite.

Aquí está el código.

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://stackoverflow.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()

  • Pero tengo multiproceso, entonces, tengo 10 trabajos simultáneos, que quieren acceder a los datos en cada página, haciendo eso (lo he intentado) termina con toneladas de pestañas abiertas pero solo una encuentra elementos y hace negocios.

    – Robert W. Hunter

    10 de febrero de 2015 a las 14:44

  • Lo siento, no recibo tu declaración. Su pregunta fue “Para el elemento en la matriz -> Abrir sitio web en una nueva pestaña -> hacer mi negocio -> cerrarlo”. Así que la solución propuesta trató de responder a ella. ¿Puedes aclarar exactamente lo que estás buscando? ¿Estás seguro de que webdriver es la herramienta adecuada para ti? ¿Qué hay de raspado?

    – aberna

    10/02/2015 a las 14:50

  • No estaba obteniendo el comportamiento esperado de driver.find_element_by_tag_name('body').send_keys(Keys.COMMAND + 't') . Esto me dio el comportamiento esperado como se documenta aquí: 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()

    – dmmfll

    27 de julio de 2015 a las 11:17


  • no funciona en mi prueba reciente (OSX 10.10.5, selenium 2.47.1 python, controlador Ghrome 2.25), funcionó en esta publicación, código: driver.execute_script("window.open('');")

    –Jerry Zhang

    11 de noviembre de 2016 a las 2:34

  • Malas noticias: Parece que Control-t ya no funciona… cf. driver.find_element_by_tag_name('body').send_keys(Keys.COMMAND + 't') …^T ha sido deshabilitado como “fuera de especificación” cf. github.com/mozilla/geckodriver/issues/786 además python-forum.io/Thread-Need-Help-Opening-A-New-Tab-in-Selenium

    – NevilleDNZ

    29 de agosto de 2018 a las 14:38


browser.execute_script('''window.open("http://bings.com","_blank");''')

Donde navegador es el controlador web

  • ¿Se puede usar con archivos html locales?

    – abhi1610

    25 de mayo de 2018 a las 6:44

  • @ abhi1610 sí, eso no importa. Se le indica al navegador que abra una nueva pestaña aquí

    – Supratik Majumdar

    20 de septiembre de 2018 a las 9:04

  • No te olvides de cambiar entre pestañas. Por ejemplo self.selenium.switch_to.window(window_name=window_name)

    – Александр

    19 de noviembre de 2019 a las 21:39

  • @Александр ¿Cómo encontraría el nombre de la ventana? Tengo el problema de que el controlador controla la primera pestaña a pesar de que el navegador está enfocado en la segunda pestaña.

    – FM

    12 de agosto de 2020 a las 17:18

  • @FM solo usa window_name = self.selenium.window_handles[-1] para obtener el nombre de la última pestaña u otro índice disponible.

    – Александр

    13 de agosto de 2020 a las 7:59

Este es un código común adaptado de otros ejemplos:

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()

las formas posibles eran:

  1. Enviando <CTRL> + <T> a un elemento

    #open tab
    driver.find_element_by_tag_name('body').send_keys(Keys.CONTROL + 't')
    
  2. Enviando <CTRL> + <T> a través de cadenas de acción

    ActionChains(driver).key_down(Keys.CONTROL).send_keys('t').key_up(Keys.CONTROL).perform()
    
  3. Ejecutar un fragmento de javascript

    driver.execute_script('''window.open("http://bings.com","_blank");''')
    

    Para lograr esto, debe asegurarse de que las preferencias browser.link.open_newwindow y browser.link.open_newwindow.restricción están correctamente configurados. Los valores predeterminados en las últimas versiones están bien, de lo contrario, supuestamente necesita:

    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)
    

    el problema es que esas preferencias preestablecidas para otros valores y son congelado al menos selenio 3.4.0. Cuando usa el perfil para configurarlos con el enlace Java, aparece un excepción y con el enlace de python, los nuevos valores se ignoran.

    En Java hay una forma de establecer esas preferencias sin especificar un objeto de perfil al hablar con conductor de geckopero parece que aún no está implementado en el enlace de 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);
    

La tercera opción hizo para de trabajar para python en selenio 3.4.0.

Las dos primeras opciones también parecían para de trabajar en selenio 3.4.0. Dependen de enviar un evento de tecla CTRL a un elemento. A primera vista parece que es un problema de la tecla CTRL, pero está fallando debido a la nueva función multiproceso de Firefox. Puede ser que esta nueva arquitectura imponga nuevas formas de hacerlo, o tal vez sea un problema de implementación temporal. De todos modos podemos desactivarlo a través de:

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)

… y luego puede usar con éxito la primera forma.

  • el nombre ‘ActionChains’ no está definido

    – pyd

    12 de noviembre de 2018 a las 4:15

  • Para Firefox, prueba también esto: driver.execute_script('''window.open("about:blank");''')

    – Scyld de fraude

    25 de noviembre de 2018 a las 17:52


  • @pyd from selenium.webdriver.common.action_chains import ActionChains

    – Reedinador

    17 de junio de 2019 a las 18:59

  • @ScylddeFraud ese fue el único método que funcionó para mí. Muy frustrante

    – palabras para el sabio

    13 de enero de 2021 a las 23:49

  • Sistema operativo: ganar 10,
  • Pitón 3.8.1
    • selenio==3.141.0
from 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://stackoverflow.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()

Referencia: Necesito ayuda para abrir una nueva pestaña en Selenium

Abrir web en nueva pestana Selenium Python
selenio no detectado

En una discusión, Simon mencionó claramente que:

Si bien el tipo de datos utilizado para almacenar la lista de identificadores puede ordenarse por inserción, el orden en el que la implementación de WebDriver itera sobre los identificadores de ventana para insertarlos no tiene ningún requisito para ser estable. El orden es arbitrario.


Utilizando Selenio v3.x abrir un sitio web en un Nueva pestaña a través de Pitón es mucho más fácil ahora. Tenemos que inducir un WebDriverWait por number_of_windows_to_be(2) y luego recopilar los identificadores de ventana cada vez que abrimos una nueva pestaña/ventana y finalmente iterar a través de los identificadores de ventana y switchTo().window(newly_opened) según sea necesario. Aquí hay una solución donde puede abrir http://www.google.co.in en el PESTAÑA inicial y https://www.yahoo.com en el TAB adyacente:

  • Bloque de código:

      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)
    
  • Salida de la consola:

      Initial Page Title is : Google
      First Window Handle is : CDwindow-B2B3DE3A222B3DA5237840FA574AF780
      Page Title after Tab Switching is : Yahoo
      Second Window Handle is : CDwindow-D7DA7666A0008ED91991C623105A2EC4
    
  • Instantánea del navegador:

múltiples_pestañas


final

Puede encontrar la discusión basada en Java en La mejor manera de realizar un seguimiento e iterar a través de pestañas y ventanas usando WindowHandles usando Selenium

Las otras soluciones no funcionan para controlador de cromo v83.

En cambio, funciona de la siguiente manera, supongamos que solo hay 1 pestaña de apertura:

driver.execute_script("window.open('');")
driver.switch_to.window(driver.window_handles[1])
driver.get("https://www.example.com")

Si ya hay más de 1 pestaña abierta, primero debe obtener el índice de la última pestaña recién creada y cambiar a la pestaña antes de llamar a la url (crédito a tylerl):

driver.execute_script("window.open('');")
driver.switch_to.window(len(driver.window_handles)-1)
driver.get("https://www.example.com")

1646957712 259 Abrir web en nueva pestana Selenium Python
Keiwan

Después de luchar durante tanto tiempo, el siguiente método funcionó para mí:

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])

  • ¿Has probado esto con versiones recientes? no funciona para mi Creo que en tu caso perdiste el foco por alguna razón.

    – yucer

    4 de agosto de 2017 a las 8:56

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad