Ahora que hemos cubierto algunos conceptos teóricos, creo que es el momento de pasar a la parte práctica. En esta sección, te mostraré cómo crear un scraper web con Selenium. Para este proyecto, asegúrate de que tu equipo tiene instalado Python y Chrome.
#1: Configurar el entorno
Como es habitual, en Python debemos encapsular todo dentro de un entorno virtual. Si no estás familiarizado con los entornos virtuales, lee esto primero. Ahora abramos una nueva ventana de terminal y:
- Crearemos una nueva carpeta
- Navegar hasta la carpeta
- Crearemos un nuevo entorno virtual
- Activar el entorno virtual
~ mkdir headless_scraper
~ cd headless_scraper
~ python3 -m venv env
~ source env/bin/activate
#2: Instalar las dependencias
Es bastante obvio que necesitamos Selenium y un controlador web para nuestro proyecto. Por suerte, podemos instalar ambos utilizando el gestor de paquetes de Python, `pip`. Dentro de la misma ventana de terminal, escribe el siguiente comando:
~ pip install selenium webdriver-manager
¡Ya está todo listo para el éxito! Podemos pasar a la programación propiamente dicha. Una breve advertencia: este artículo se centra en la interacción con un navegador sin interfaz gráfica. Una solución completa de web scraping requiere mucho más esfuerzo. Pero estoy seguro de que, si sigues nuestras entradas del blog, podrás hacerlo en muy poco tiempo.
#3: Abrir un navegador automatizado
Hasta ahora, tenemos el proyecto, pero no hay ningún archivo que podamos ejecutar. Creemos un nuevo archivo `.py` y abrámoslo en nuestro IDE:
~ touch headles_scraper.py
~ code .
Ahora deberías estar dentro de Visual Studio Code o de tu IDE. Puedes empezar importando los paquetes necesarios dentro de `handle_scraper.py`:
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
Este último es un paquete que te ayuda a gestionar fácilmente los controladores web para los diferentes navegadores compatibles con Selenium. Puedes leer más al respecto aquí. A continuación, queremos crear un nuevo navegador con Selenium y abrir un sitio web:
driver = webdriver.Chrome(ChromeDriverManager().install())
driver.get('https://webscrapingapi.com')
Ejecuta este archivo ahora y verás que funciona. Pero en lugar de utilizar un navegador sin interfaz gráfica de Python, se abre una ventana de Chrome con interfaz gráfica:
#4: Crear en modo sin interfaz gráfica
Nos hemos propuesto crear un rastreador web que consuma pocos recursos. Así que, idealmente, queremos abrir un navegador sin interfaz gráfica con Selenium. Afortunadamente, hay un método sencillo que podemos usar para cambiar Selenium de modo con interfaz gráfica a modo sin interfaz gráfica. Solo tenemos que utilizar las opciones del controlador web de Chrome. Así que importemos `Options` y añadamos dos líneas más de código:
...
from selenium.webdriver.chrome.options import Options
...
options = Options()
options.headless = True
driver = webdriver.Chrome(ChromeDriverManager().install(), options=options)
driver.get('https://webscrapingapi.com')
Ejecuta tu script de nuevo. Como puedes ver, esta vez no aparece ninguna ventana. Pero, ¿realmente está funcionando en segundo plano? Una forma rápida de visualizarlo y comprobarlo es hacer una captura de pantalla con Selenium. Solo tienes que añadir esta línea al final de tu script:
driver.get_screenshot_as_file('headless.png')
Si todo ha ido bien, deberías tener la misma imagen que yo:
#5: Añadir capacidades de scraping
¿Qué es un web scraper? Bueno, en esencia, un web scraper es un programa que llama a un punto final de un servidor y recopila datos de él. En el caso de los sitios web, estos datos suelen consistir en archivos HTML. Pero hoy en día algunos servidores también sirven objetos JSON. Así que quedémonos con este término: datos. Para la siguiente sección, fijemos unos objetivos más ambiciosos. ¡Usemos algo de programación orientada a objetos! Nuestros objetivos son:
- Crear una clase Scraper
- Añadir un método para extraer datos sin procesar
- Añadir un método para extraer datos de un único elemento
- Añadir un método para extraer datos de elementos de la misma clase
Así que tenemos tres métodos básicos que queremos crear. Sin embargo, con fines de aprendizaje, estos tres métodos nos abren el camino no solo al web scraping, sino también a la programación orientada a objetos (OOP) con Python. ¡Y creo que eso es genial! Ahora vamos a borrar todo lo que hemos programado y empezaremos desde cero:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.remote.webelement import WebElement
class Scraper:
def __init__(self, headless: bool = True) -> None:
self.headless = headless
pass
def setup_scraper(self) -> None:
self.options = Options()
self.options.headless = self.headless
self.driver = webdriver.Chrome(options=self.options)
def navigate(self, target) -> None:
self.driver.get(target) if target else print('[!] No target given. Please specify a URL.')
def extract_raw_data(self) -> str:
return self.driver.page_source
def extract_single_element(self, selector: str, selector_type: By = By.CSS_SELECTOR) -> WebElement:
return self.driver.find_element(selector_type, selector)
def extract_all_elements(self, selector: str, selector_type: By = By.CSS_SELECTOR) -> list[WebElement]:
return self.driver.find_elements(selector_type, selector)
He añadido anotaciones de tipo para facilitar la comprensión, más que para mejorar el rendimiento. De esta forma, puedes visualizar la aplicación desde una perspectiva de E/S. Ahora bien, los métodos se explican por sí mismos. No estamos realizando ningún tipo de acción sobre los datos, solo los estamos devolviendo. Si quieres, esto puede ser un punto de partida para crear un scraper complejo con un navegador sin interfaz gráfica de Python.
Hasta ahora, al ejecutar el archivo no pasa nada. Eso es porque solo hemos declarado nuestro Scraper y sus métodos. Ahora tenemos que usarlos. Así que añadamos los siguientes fragmentos de código:
# Initialize a new Scraper and navigate to a target
scraper = Scraper()
scraper.setup_scraper()
scraper.navigate('https://httpbin.org')
# Extract and print the entire HTML document
raw_data = scraper.extract_raw_data()
print(raw_data)
# Extract and print an element by its class name
single_element = scraper.extract_single_element('title', By.CLASS_NAME)
print(single_element.text)
# Extract and print all elements belonging to a tag type
all_elements = scraper.extract_all_elements('a', By.TAG_NAME)
print([el.get_attribute('href') for el in all_elements])
Y eso es todo. Si ejecutas tu script ahora, podrás ver que ocurre algo. De nuevo, esto es simplemente un prototipo diseñado para que puedas empezar. Si quieres aprender más sobre cómo se puede utilizar un navegador sin interfaz gráfica de Python en el scraping web, te reto a que:
De esta forma, podrás adquirir conocimientos y añadir un proyecto a tu portfolio.