Web Scraping en Python: Herramientas y Técnicas

En el desarrollo de web scraping con Python, se utilizan diversas bibliotecas para manejar solicitudes HTTP, analizar respuestas y extraer datos. La biblioteca urllib es fundamental para gestionar conexiones, soportando protocolos como HTTPS, que puede desencadenar mecanismos anti-scraping basados en encabezados User-Agent. Para solicitudes GET, métodos como quote convierten cadenas a codificación Unicode, mientras que urlencode extiende esta funcionalidad a múltiples parámetros. En solicitudes POST, los datos codificados requieren un paso adicional con encode. Las solicitudes AJAX, tanto GET como POST, se manejan de manera similar, permitiendo extraer datos de sitios web dinámicos.

Para ilustrar, consideremos un script que recupera datos de una API mediante una solicitud POST usando urllib. En lugar de un sitio específico, simulamos una consulta a un servicio de datos genérico, ajustando parámetros y encabezados para reflejar un escenario real.


import urllib.request
import urllib.parse

def build_request(page_num):
    endpoint = 'https://api.ejemplo.com/v1/recursos'
    params = {
        'ciudad': 'Madrid',
        'pagina': str(page_num),
        'elementos': '15'
    }
    encoded_params = urllib.parse.urlencode(params).encode('ascii')
    custom_headers = {
        'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0'
    }
    req = urllib.request.Request(url=endpoint, data=encoded_params, headers=custom_headers)
    return req

def fetch_response(req):
    with urllib.request.urlopen(req) as resp:
        return resp.read().decode('utf-8')

def save_data(index, raw_data):
    filename = f'resultados_{index}.json'
    with open(filename, 'w', encoding='utf-8') as file:
        file.write(raw_data)

if __name__ == '__main__':
    start = int(input("Introduce página inicial: "))
    end = int(input("Introduce página final: "))
    for i in range(start, end + 1):
        request_obj = build_request(i)
        response_data = fetch_response(request_obj)
        save_data(i, response_data)

urllib también ofrece manejo de excepciones mediante módulos como urllib.error, que incluye clases como HTTPError y URLError. Para tareas más complejas, se emplean handlers y proxies, permitiendo interceptar y modificar solicitudes. La analítica de contenido se facilita con bibliotecas como lxml para xpath, útil para extraer elementos de páginas HTML. Por ejemplo, un script puede descargar imágenes de un sitio web, adaptando la lógica de paginación y rutas de recursos.


import urllib.request
from lxml import etree

def construct_url(page_idx):
    if page_idx == 1:
        base = 'https://portalimagenes.com/galeria/paisajes.html'
    else:
        base = f'https://portalimagenes.com/galeria/paisajes_{page_idx}.html'
    return base

def retrieve_html(url):
    req = urllib.request.Request(url=url, headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'})
    with urllib.request.urlopen(req) as resp:
        return resp.read().decode('utf-8')

def extract_and_download(html_content):
    parsed = etree.HTML(html_content)
    names = parsed.xpath('//div[contains(@class,"gallery")]//img/@title')
    sources = parsed.xpath('//div[contains(@class,"gallery")]//img/@data-src')
    for name_val, src_val in zip(names, sources):
        full_url = f'https:{src_val}'
        urllib.request.urlretrieve(url=full_url, filename=f'./descargas/{name_val}.png')

if __name__ == '__main__':
    pages = range(1, 4)
    for pg in pages:
        link = construct_url(pg)
        html = retrieve_html(link)
        extract_and_download(html)

Para analizar datos JSON, jsonpath permite navegar estructuras complejas. Un ejemplo práctico podría involucrar el scraping de una API pública, donde se extraen campos específicos como nombres de regiones o listas de elementos, almacenando temporalmente los datos en archivos locales para su procesamiento.


import urllib.request
import json
import jsonpath

api_url = 'https://datos.ejemplo.com/api/ciudades?callback=jsonpCallback'
headers = {
    'Accept': 'application/json',
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)'
}
req = urllib.request.Request(url=api_url, headers=headers)
with urllib.request.urlopen(req) as resp:
    content = resp.read().decode('utf-8')
# Extraer contenido JSON de respuesta JSONP
json_str = content.split('(', 1)[1].rsplit(')', 1)[0]
with open('datos_temp.json', 'w', encoding='utf-8') as f:
    f.write(json_str)
with open('datos_temp.json', 'r', encoding='utf-8') as f:
    obj = json.load(f)
nombres_ciudades = jsonpath.jsonpath(obj, '$..nombre')
print(nombres_ciudades)

BeautifulSoup (bs4) simplifica el análisis de HTML y XML, ofreciendo métodos como get_text() para extraer texto de nodos, que es preferible a string cuando los elementos contienen etiquetas anidadas. Selenium se utiliza para sitios web con contenido dinámico cargado por JavaScript, simulando interacciones de usuario para acceder a datos completos. Requests proporciona una interfaz más sencilla para realizar solicitudes HTTP, soportando tanto GET como POST. Finalmente, Scrapy es un framwork robusto para proyectos de scraping a gran escala, con manejo integrado de solicitudes, extracción y pipelines de datos.

Etiquetas: urllib jsonpath lxml BeautifulSoup Selenium

Publicado el 6-2 18:12