Construyendo Tu Primera App de Web Scraping
Descarga de páginas web y análisis de HTML con requests y BeautifulSoup
Internet y la World Wide Web (WWW) son probablemente la fuente de información más prominente en la actualidad. La mayor parte de esa información se puede recuperar mediante HTTP. Python incluye un cliente HTTP en su biblioteca estándar, pero el módulo requests hace que obtener páginas web sea extremadamente sencillo.
En esta primera parte cubrimos las dos recetas fundamentales: descargar páginas web con el módulo requests y analizar el HTML resultante con Beautiful Soup para extraer datos estructurados.
- Descargar páginas web
- Analizar HTML
- Rastrear la web (crawling)
- Suscribirse a feeds RSS
- Acceder a APIs web
- Interactuar con formularios
- Selenium para interacción avanzada
- Páginas protegidas por contraseña
- Acelerar el web scraping
Descargar Páginas Web
La capacidad básica para descargar una página web consiste en hacer una solicitud HTTP GET a una URL. Esta es la operación fundamental de cualquier navegador web. La operación tiene tres componentes bien diferenciados:
Usar el protocolo HTTP, que determina cómo se estructura la solicitud.
Usar el método GET, que es el método HTTP más común para recuperar recursos.
Una URL completa que describe la dirección de la página, incluyendo el servidor (ej: mypage.com) y la ruta (ej: /page).
La solicitud es enrutada al servidor por internet. La respuesta contendrá un código de estado (típicamente 200 si todo fue bien) y un cuerpo con el resultado, normalmente texto HTML.
Preparación
Instala el módulo requests:
$ echo "requests==2.23.0" >> requirements.txt $ source .venv/bin/activate (.venv) $ pip install -r requirements.txt
Cómo hacerlo
# Paso 1: Importar el módulo import requests # Paso 2: Realizar la solicitud GET url = 'http://www.columbia.edu/~fdc/sample.html' response = requests.get(url) # Paso 3: Verificar el código de estado print(response.status_code) # 200 # Paso 4: Ver el contenido HTML print(response.text) # HTML completo de la página # Paso 5: Inspeccionar las cabeceras print(response.request.headers) print(response.headers)
{'User-Agent': 'python-requests/2.22.0', 'Accept-Encoding': 'gzip, deflate', ...}
{'Date': 'Fri, 24 Jan 2020 19:04:12 GMT', 'Server': 'Apache', 'Content-Type': 'text/html', ...}
Cómo funciona
El funcionamiento de requests es muy simple: se realiza la solicitud usando el método GET sobre la URL. Esto devuelve un objeto de resultado con dos elementos principales: status_code y el cuerpo del contenido como texto.
# Inspeccionar la solicitud completa response.request # <PreparedRequest [GET]> response.request.url # 'http://www.columbia.edu/~fdc/sample.html'
Códigos de estado HTTP
Todos los códigos están documentados en httpstatuses.com y en el enum http.HTTPStatus.
| Rango | Categoría | Ejemplo |
|---|---|---|
| 1XX | Informacional | Detalles del protocolo |
| 2XX | Éxito | 200 OK |
| 3XX | Redirección | URL movida permanentemente |
| 4XX | Error del cliente | 404 Not Found, 403 Forbidden |
| 5XX | Error del servidor | Server no disponible |
HTTPS (HTTP seguro). Es igual que HTTP pero garantiza que el contenido de la solicitud y la respuesta sean privados. requests lo maneja de forma transparente.
Analizar HTML
Descargar texto sin formato es un buen punto de partida, pero el lenguaje principal de la web es HTML. HTML es un lenguaje estructurado y jerárquico que define distintas partes de un documento. La capacidad de analizar texto en un documento estructurado nos permite extraer información automáticamente de cualquier página web.
Preparación
Usaremos el módulo Beautiful Soup para analizar HTML. Añade el paquete beautifulsoup4 a tu entorno:
$ echo "beautifulsoup4==4.8.2" >> requirements.txt $ pip install -r requirements.txt
Cómo hacerlo
import requests from bs4 import BeautifulSoup # Paso 1: Descargar la página URL = 'http://www.columbia.edu/~fdc/sample.html' response = requests.get(URL) # Paso 2: Analizar (parsear) el HTML descargado page = BeautifulSoup(response.text, 'html.parser') # Paso 3: Obtener el título de la página print(page.title) # <title>Sample Web Page</title> print(page.title.string) # 'Sample Web Page' # Paso 4: Encontrar todas las secciones h3 print(page.find_all('h3')) # Paso 5: Extraer el texto de una sección específica link_section = page.find('h3', attrs={'id': 'chars'}) section = [] for element in link_section.next_elements: if element.name == 'h3': break section.append(element.string or '') result = ''.join(section) print(result)
'Sample Web Page'
[<h3><a name="contents">CONTENTS</a></h3>, <h3>1. Creating a Web Page...</h3>, ...]
'3. Special Characters\n\nHTML special "character entities"...'
Cómo funciona
BeautifulSoup nos permite buscar elementos HTML de dos formas principales:
Devuelve la primera ocurrencia del elemento buscado.
Devuelve una lista con todos los elementos coincidentes.
Usar expresiones regulares en búsquedas
Las expresiones regulares pueden usarse como entrada en .find() y .find_all():
import re # Buscar etiquetas h2 y h3 simultáneamente page.find_all(re.compile('^h(2|3)')) # [<h2>Sample Web Page</h2>, <h3 id="contents">CONTENTS</h3>, ...] # Buscar por clase CSS page.find_all('div', class_='mi-clase')
html.parser es el predeterminado, pero para páginas grandes puede ser lento. Alternativas más potentes: lxml (mucho más rápido) y html5lib (se comporta como un navegador real). Son módulos externos que deben añadirse a requirements.txt.
<div>, otras usan texto sin formato, otras anidan elementos de formas no estándar. Se requiere algo de experimentación para cada sitio. ¡No tengas miedo de probar!
Resumen // Parte 1
01 // requests.get()
Realiza solicitudes HTTP GET y devuelve un objeto con status_code y text.
02 // Códigos de estado
2XX = éxito, 4XX = error del cliente (404 = no encontrado), 5XX = error del servidor.
03 // BeautifulSoup
Convierte HTML en texto plano a un árbol de objetos Python navegable y consultable.
04 // find / find_all
Métodos para buscar elementos HTML por etiqueta, atributo, clase CSS o expresión regular.