<jupyter_start><jupyter_text>Capítulo 5 - Uso de Selenium para automatizar acciones en el navegador___ Ejemplo práctico___ importamos librerías clave:<jupyter_code>! pip install selenium
from selenium import webdriver  # hay que haber ejecutado `pip install selenium` para que funcione la importación<jupyter_output><empty_output><jupyter_text>Para levantar el explorador deberá estar presente en la misma carpeta que este documento el driver (descomprimido como .exe) de la versión del navegador que queramos automatizar. Se puede bajar de aquí: https://sites.google.com/chromium.org/driver/<jupyter_code>driver = webdriver.Chrome()
driver.get("http://www.python.org")<jupyter_output><empty_output><jupyter_text>comprobación de texto en el título:<jupyter_code>print(driver.title)
assert "Python" in driver.title<jupyter_output><empty_output><jupyter_text>referenciar un elemento de la web:orden de rapidez: 1.- id | 2.- name | 3.- css selector | 4.- xpath<jupyter_code>from selenium.webdriver.common.by import By

# id
tbx__search = driver.find_element(By.ID, "id-search-field") 

# name
tbx__search = driver.find_element(By.NAME, "q") 

# css selector
tbx__search = driver.find_element(By.CSS_SELECTOR, "input#id-search-field")                                     # id
tbx__search = driver.find_element(By.CSS_SELECTOR, "input.search-field")                                        # class
tbx__search = driver.find_element(By.CSS_SELECTOR, "input[placeholder='Search']")                               # otro atributo
tbx__search = driver.find_element(By.CSS_SELECTOR, "input#id-search-field.search-field[placeholder='Search']")  # más de un atributo a la vez

tbx__search = driver.find_element(By.CSS_SELECTOR, "input[placeholder^='Sea']")   # empieza con
tbx__search = driver.find_element(By.CSS_SELECTOR, "input[placeholder$='arch']")  # termina con
tbx__search = driver.find_element(By.CSS_SELECTOR, "input[placeholder*='ear']")   # contiene

# xpath
tbx__search = driver.find_element(By.XPATH, "//input[@placeholder='Search']")<jupyter_output><empty_output><jupyter_text>Cundo el identificador no es único se puede coger una lista de elementos con el siguiente método:<jupyter_code>lista_de_elementos = driver.find_elements(By.CSS_SELECTOR, "input#id-search-field")  # devuelve un lista

tbx__search = lista_de_elementos[0]  # en este caso es 0 porque queremos el primero, pondríamos 1 si fuera el segundo, etc.<jupyter_output><empty_output><jupyter_text>escribir en el buscador y pulsar Enter:<jupyter_code>from selenium.webdriver.common.by import By

tbx__search = driver.find_element(By.ID, "id-search-field") 
tbx__search.clear()
tbx__search.send_keys("no va a haber resultados para esta frase")

from selenium.webdriver.common.keys import Keys  # con esta línea importamos la clase Keys de selenium, que nos hará fata a continuación

tbx__search.send_keys(Keys.RETURN)  # pulsar Enter<jupyter_output><empty_output><jupyter_text>escribir en el buscador y clicar en 'go':<jupyter_code>tbx__search = driver.find_element(By.ID, "id-search-field") 
tbx__search.clear()
tbx__search.send_keys("tampoco va a haber resultados para esta frase")

btn__go = driver.find_element(By.ID, "submit") 
btn__go.click()<jupyter_output><empty_output><jupyter_text>más comprobaciones:<jupyter_code>print("···")
print( driver.page_source[21500:21800] )
print("···")

assert "No results found." in driver.page_source
txt__results = driver.find_element(By.CSS_SELECTOR, "#content > div > section > form > ul > p")
print(txt__results.text)

assert "No results found." in txt__results.text<jupyter_output><empty_output><jupyter_text>cerrar el navegador:<jupyter_code>driver.quit()<jupyter_output><empty_output><jupyter_text>Page objects___vamos a transformar el portal http://www.python.org en un pageobject<jupyter_code>class PortalPage(object):
    
    # constructor
    def __init__(self, driver):
        self.driver = driver
        
        # elementos
        self.tbx__search = lambda: self.driver.find_element(By.ID, "id-search-field")
        self.btn__go = lambda: self.driver.find_element(By.ID, "submit")
    
    # métodos    
    def get(self):
        driver.get("http://www.python.org")
        return self
    
    def search(self, text):
        self.tbx__search().clear()
        self.tbx__search().send_keys(text)
        self.btn__go().click()
        
    
class ResultsPage(object):
    
    def __init__(self, driver):
        self.driver = driver
        self.txt__results = lambda: self.driver.find_element(By.CSS_SELECTOR, "#content > div > section > form > ul > p")
    
    def assert_no_results_visible(self):
        assert self.txt__results().is_displayed()
        assert "No results found." in self.txt__results().text
import time

driver = webdriver.Chrome()

try:
    page__portal = PortalPage(driver).get()
    page__portal.search("algo que no existe")

    page__results = ResultsPage(driver)
    page__results.assert_no_results_visible()
    
finally:
    time.sleep(3)
    driver.close()<jupyter_output><empty_output><jupyter_text>el flujo utilizando solo los atributos sería así:<jupyter_code>import time

driver = webdriver.Chrome()

try:
    driver.get("http://www.python.org")
    
    # Portal
    page__portal = PortalPage(driver)
    page__portal.tbx__search().clear()
    page__portal.tbx__search().send_keys("<PASSWORD> no existe")
    page__portal.btn__go().click()
    
    # Results
    assert "No results found." in ResultsPage(driver).txt__results().text
    print("No results found.")
    
finally:
    time.sleep(3)
    driver.close()<jupyter_output><empty_output><jupyter_text>otro ejemplo de uso:dada esta web (http://the-internet.herokuapp.com/login), crear debajo un script que habrá la página se loguee y luego desloguee (incluyendo asserciones)<jupyter_code>from selenium import webdriver

driver = webdriver.Chrome()

try:
    driver.get("http://the-internet.herokuapp.com/login")
    tbx__search = driver.find_element(By.NAME, "username")
    tbx__search.send_keys("tomsmith")
    tbx__search = driver.find_element(By.NAME, "password")
    tbx__search.send_keys("<PASSWORD>!")
    btn__login = driver.find_element(By.CSS_SELECTOR, "#login > button > i")
    btn__login.click()
    btn__logout = driver.find_element(By.CSS_SELECTOR, "#content > div > a > i")
    btn__logout.click()
finally:
    driver.quit()<jupyter_output><empty_output><jupyter_text>usando pageobjects quedaría así:<jupyter_code>from selenium import webdriver
from selenium.webdriver.common.keys import Keys

class Portal(object):
    
    def __init__(self, driver):
        self.driver = driver
        self.tbx__username = lambda: self.driver.find_element(By.NAME, "username")
        self.tbx__password = lambda: self.driver.find_element(By.NAME, "password")
        self.btn__login = lambda: self.driver.find_element(By.CSS_SELECTOR, "#login > button > i")
        
    def get(self):
        self.driver.get("https://the-internet.herokuapp.com/login")
        return self
    
    def login(self, username, password):
        self.tbx__username().clear()
        self.tbx__username().send_keys(username)
        self.tbx__password().clear()
        self.tbx__password().send_keys(password)
        self.btn__login().click()
        
        
class SecureArea(object):
    
    def __init__(self, driver):
        self.driver = driver
        self.btn__logout = lambda: self.driver.find_element(By.XPATH, "//*[@id='content']/div/a")
    
    def assert_page_loaded(self):
        assert self.btn__logout().is_displayed()


driver = webdriver.Chrome()

try:
    page__portal = Portal(driver).get()
    page__portal.login("tomsmith", "<PASSWORD>!")
    page__secure_area = SecureArea(driver)
    page__secure_area.assert_page_loaded()
    page__secure_area.btn__logout().click()
finally:
    driver.quit()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11669636039704759, 'fraction_numerical': 0.0025451768897938407, 'mean_word_length': 4.249832999331997, 'pattern_counts': {'":': 0, '<': 56, '<?xml version=': 0, '>': 73, 'https://': 2, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '13', 'dir': 'jupyter-structured-clean-dedup', 'id': '62237', 'license': 'MIT', 'n_tokens_mistral': 2673, 'n_tokens_neox': 2633, 'n_words': 516, 'path': 'test-lab/05 - selenium.ipynb', 'repo_name': 'manzanero/curso-python-auto', 'size': '7874'}