Tabla de Contenidos
Python: Web Scraping
import webbrowser # Abre el navegador en cierta página: webbrowser.open("https://example.org")
En el web scraping, normalmente se siguen unos pasos:
- Definir la URL de base
- Hacer petición a esa URL
- Obtener respuesta HTML
- Extraer datos del HTML
- Volver al paso 2 con nuevas URLs.
XPath
Lenguaje para el procesado de documentos XML.
Buscar en cualquier parte del documento:
//
Para buscar cualquier etiqueta h1:
//h1
Después de definir el step, añadimos un predicado al step para afinar más la búsqueda:
//h1[@class="title"]
Con la expresión anterior estaríamos buscando etiquetas h1 por el atributo class con el valor title.
Podemos usar operadores lógicos para añadir expresiones:
//h1[@class="title" or @class="subtitle"]
Una vez encontremos un elemento de partida, podemos hacer búsquedas dentro de él añadiéndolo a la expresión:
//div[@class="container container-uno"]//li
En los predicados podemos indicar la posición de los elementos que queremos buscar:
//div[@class="container container-uno"]//li[1]
Solo nos quedaríamos con el primer li
Si solo nos queremos quedar con el texto que contiene cierto elemento:
//h1[contains(text(), "This is")]/text()
Si solo queremos obtener el valor de un atributo:
//h1[contains(text(), "This is")]/@class
En los navegadores Google Chrome y Mozilla Firefox se pueden probar expresiones XPath desde la consola de las herramientas de desarrolladores introduciendo las expresiones en $x(): $x("//h2[1]")
Funciones
positioncontainsstarts-withnottext
//div[@class="container container-uno"]//li[starts-with(@id, "elem")]
Obtiene todos los li cuyo atributo id comience por elem.
Si queremos buscar por un texto:
//h1[contains(text(), "Hola, mundo")]
Nos buscará todos los elementos h1 que contengan el texto Hola, mundo.
Descargar ficheros
El módulo no viene incluido por defecto en la instalación de Python así que hay que instalarlo con pip: pip install requests
import requests # Con la petición vamos a personalizar la cabecera HTTP para # que el servidor "crea" que estamos utilizando un navegador web headers = { "user-agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36" } url = "https://example.org/page" res = requests.get(url, headers=headers) # 'res' es el objeto con la respuesta # Resultado de la petición res.status_code # Resultado # 200 -> Si ha ido bien # El contenido de la descarga está en: res.text
Procesar HTML
Tenemos dos posibilidades interesantes con los siguientes módulos de Python:
Hay una tercera posibilidad que es Scrapy, que es ya todo un framework para navegar por páginas, extraer información y moverse por las diferentes páginas de un mismo sitio.
La ventaja de Beautiful Soup frente a lxml es poder movernos por elementos sin conocer su id o clase, solo con tener un punto de partida. Ejemplos de esto es el método find_next_sibling()
Es necesario instalar BeautifulSoup: pip install beautifulsoup4
import bs4 import requests # es el módulo que hará la descarga # Para las webs que no permiten scraping, le hacemos creer que # nos estamos conectando con un navegador headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36'} res = requests.get("https://www.amazon.es/dp/B07DLRWFF8/", headers = headers) # Nos aseguramos de que no ha habido errores al descargar la web anterior res.raise_for_status() soup = bs4.BeautifulSoup(res.text, "html.parser") # Se crea un objeto 'BeautifulSoup' donde se podrán hacer búsquedas # utilizando selectores CSS, por ejemplo: elementos = soup.select('<ruta CSS al elemento que interesa>') # Eliminamos el HTML quedándonos solo con el texto: elementos[0].text # Quitamos también saltos de línea y espacios: elementos[0].text.strip()
Interacción automática con webs
Usar el navegador sin intervención del usuario, de forma automática.
Es necesario instalar Selenium: pip install selenium
from selenium import webdriver # Para lanzar el Firefox browser = webdriver.Firefox() # Para abrir una web en esa instancia de Firefox browser.get("http://example.org")
Si queremos simular un click en cierto elemento:
# Buscamos el elemento mediante selector CSS: elem = browser.find_element_by_css_selector('<selector CSS al elemento>') elem.click()
Si sabemos que hay más de un elemento con el mismo selector CSS, el método cambia:
# Buscamos los elementos mediante selector CSS: elem = browser.find_elements_by_css_selector('<selector CSS a los elementos>')
| Método | Objeto / lista devuelto |
|---|---|
browser.find_element_by_class_name(name) | Elementos que tengan la clase name |
browser.find_elements_by_class_name(name) | Elementos que tengan la clase name |
browser.find_element_by_css_selector(selector) | Elemento que tengan el selector CSS |
browser.find_elements_by_css_selector(selector) | Elementos que tengan el selector CSS |
browser.find_element_by_id(id) | Elemento con el id igual a id |
browser.find_elements_by_id(id) | Elementos con el id igual a id |
browser.find_element_by_link_text(texto) | Enlace con el texto texto |
browser.find_elements_by_link_text(texto) | Enlaces con el texto texto |
browser.find_element_by_partial_link_text(texto) | Enlaces que contengan el texto texto |
browser.find_elements_by_partial_link_text(texto) | Enlaces que contengan el texto texto |
browser.find_element_by_name(name) | Elemento con un atributo name |
browser.find_elements_by_name(name) | Elementos con un atributo name |
browser.find_element_by_tag_name(name) | Elemento con la etiqueta name |
browser.find_elements_by_tag_name(name) | Elementos con la etiqueta name |
Enviar texto
Por ejemplo para formularios:
# Buscamos el elemento elem = browser.find_element_by_css_selector('ruta CSS al elemento') elem.send_keys('texto') # Enviamos el formulario elem.submit()
Navegación
browser.back(): página anteriorbrowser.forward(): página siguientebrowser.refresh(): actualizar páginabrowser.quit(): cerrar el navegador
Scraping
Al seleccionar un elemento, podemos acceder al texto con el atributo text:
elem = browser.find_element_by_css_selector('<selector CSS al elemento>') elem.text
Si quisiésemos todo el código HTML de la página:
elem = find_element_by_css_selector('html')
