web-dev-qa-db-fra.com

Ouvrir le web dans un nouvel onglet Selenium + Python

J'essaie donc d'ouvrir des sites Web sur de nouveaux onglets dans mon WebDriver. Je veux le faire, car l'ouverture d'un nouveau WebDriver pour chaque site Web prend environ 3,5 secondes à l'aide de PhantomJS, je veux plus de vitesse ...

J'utilise un multiprocessus python, et je veux obtenir des éléments de chaque page, donc le flux de travail est comme ceci:

Open Browser

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

Mais je ne trouve aucun moyen d'y parvenir.

Voici le code que j'utilise. Cela prend une éternité entre les sites Web, j'en ai besoin pour être rapide ... D'autres outils sont autorisés, mais je ne connais pas trop d'outils pour supprimer le contenu du site Web qui se charge avec JavaScript (divs créées lorsqu'un événement est déclenché au chargement, etc.) pourquoi j'ai besoin de sélénium ... BeautifulSoup ne peut pas être utilisé pour certaines de mes pages.

#!/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()
18
Robert W. Hunter

Vous pouvez réaliser l'ouverture/fermeture d'un onglet par la combinaison de touches COMMAND + T ou COMMAND + W (OSX). Sur d'autres OS, vous pouvez utiliser CONTROL + T / CONTROL + W.

Dans Selenium, vous pouvez émuler un tel comportement. Vous devrez créer un pilote Web et autant d'onglets que les tests dont vous avez besoin.

Ici, c'est le code.

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

Il s'agit d'un code commun adapté d'autres exemples:

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

les moyens possibles étaient:

  1. Envoi <CTRL> + <T> à un élément

    #open tab
    driver.find_element_by_tag_name('body').send_keys(Keys.CONTROL + 't')
    
  2. Envoi <CTRL> + <T> via des chaînes d'action

    ActionChains(driver).key_down(Keys.CONTROL).send_keys('t').key_up(Keys.CONTROL).perform()
    
  3. Exécutez un extrait javascript

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

    Pour ce faire, vous devez vous assurer que les préférences browser.link.open_newwindow et browser.link.open_newwindow.restriction sont correctement définies. Les valeurs par défaut dans les dernières versions sont correctes, sinon vous avez supposément besoin de:

    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)
    

    le problème est que ces préférences sont prédéfinies à autres valeurs et sont figées au moins Selenium 3.4.0. Lorsque vous utilisez le profil pour les définir avec la liaison Java, il y a une exception et avec la liaison python), les nouvelles valeurs sont ignoré.

    Dans Java il y a un moyen de définir ces préférences sans spécifier d'objet de profil lors de la conversation avec geckodriver , mais il semble pas encore implémenté dans la liaison 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 troisième option a arrêter de fonctionner pour python dans Selenium 3.4.0.

Les deux premières options semblaient également cesser de fonctionner dans Selenium 3.4.0. Ils dépendent de l'envoi d'un événement de touche CTRL à un élément. À première vue, il semble que ce soit un problème de la clé CTRL, mais il échoue à cause de la nouvelle fonctionnalité multiprocessus de Firefox . Il se peut que cette nouvelle architecture impose de nouvelles façons de le faire, ou est peut-être un problème de mise en œuvre temporaire. Quoi qu'il en soit, nous pouvons le désactiver via:

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)

... et ensuite vous pouvez utiliser avec succès la première façon.

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

navigateur est le webDriver

13
Supratik Majumdar

Au cours d'une discussion, Simon a clairement mentionné que:

Bien que le type de données utilisé pour stocker la liste des descripteurs puisse être ordonné par insertion, l'ordre dans lequel l'implémentation WebDriver parcourt les descripteurs de fenêtre pour les insérer n'a pas besoin d'être stable. La commande est arbitraire.


Utilisation de Selenium v3.x ouverture d'un site Web dans un nouvel onglet à Python est beaucoup plus facile maintenant. Nous devons induire un WebDriverWait pour number_of_windows_to_be(2) puis collecter les poignées de fenêtre chaque fois que nous ouvrons un nouvel onglet/fenêtre et enfin itérons à travers les poignées de fenêtre et switchTo().window(newly_opened) comme requis. Voici une solution où vous pouvez ouvrir http://www.google.co.in dans le TAB initial et https://www.yahoo.com dans le TAB adjacent :

  • Bloc de code:

    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)
    
  • Sortie console:

    Initial Page Title is : Google
    First Window Handle is : CDwindow-B2B3DE3A222B3DA5237840FA574AF780
    Page Title after Tab Switching is : Yahoo
    Second Window Handle is : CDwindow-D7DA7666A0008ED91991C623105A2EC4
    
  • Instantané du navigateur:

multiple__tabs


Outro

Vous pouvez trouver la discussion basée sur Java dans Meilleur moyen de suivre et d'itérer à travers les onglets et les fenêtres en utilisant WindowHandles en utilisant Selenium

5
DebanjanB

Après avoir lutté pendant si longtemps, la méthode ci-dessous a fonctionné pour moi:

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])
3
Ziad abbas

J'ai essayé pendant très longtemps de dupliquer des onglets dans Chrome fonctionnant en utilisant action_keys et send_keys sur le corps. La seule chose qui a fonctionné pour moi était une réponse ici . Ceci est à quoi ressemblaient mes onglets en double, probablement pas le meilleur, mais cela fonctionne bien pour moi.

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)+"')")

Il exécute essentiellement quelques Java de l'intérieur de python, c'est incroyablement utile. J'espère que cela aide quelqu'un.

Remarque: j'utilise Ubuntu, cela ne devrait pas faire de différence, mais si cela ne fonctionne pas pour vous, cela pourrait être la raison.

0
astroben