Volver al blog

Raspado Web con Perl: Una Guía Paso a Paso para 2026

Emily Chen
Emily Chen

Advanced Data Extraction Specialist

31-Jul-2026

TL; DR:

  • Perl sigue siendo práctico para el web scraping cuando ya forma parte de una pila de datos u operaciones. Usa HTTP::Tiny para una solicitud pequeña, LWP::UserAgent para un control HTTP más completo, HTML::TreeBuilder para el análisis del DOM, y WWW::Mechanize para cookies, enlaces y formularios.
  • No analices HTML arbitrario con expresiones regulares. Analiza el documento en un árbol, selecciona elementos por atributos, valida campos requeridos, y escribe salida en UTF-8 con un verdadero codificador CSV o JSON.
  • Los clientes HTTP en Perl no ejecutan JavaScript. Confirma si los datos requeridos existen en la respuesta inicial antes de agregar un navegador o una capa de renderizado gestionada.
  • Los proxies resuelven requisitos de enrutamiento y ubicación; no reparan selectores ni renderizan una página. Para páginas públicas dinámicas o fuertemente protegidas, una API gestionada puede devolver HTML al mismo analizador de Perl.
  • El scraper principal de este tutorial fue probado con Perl 5.34.1, libwww-perl 6.83, HTML-Tree 5.07, Text-CSV 2.06, y WWW::Mechanize 2.22 contra el sitio de práctica segura Books to Scrape.

El web scraping con Perl es una elección sensata cuando una organización ya tiene scripts en Perl, despliegue de CPAN y experiencia en procesamiento de texto. Un programa corto en Perl puede obtener una página, recorrer HTML, validar registros y emitir CSV o JSON limpio sin introducir un nuevo runtime.

Los límites son igualmente importantes. Los clientes HTTP estáticos ven la respuesta del servidor, no un DOM renderizado por un navegador. Los sitios modernos pueden cargar datos después de que la página comienza, requerir una sesión o aplicar controles de tráfico. El diseño correcto mantiene el análisis en Perl mientras cambia la capa de adquisición solo cuando el objetivo lo requiere.

Esta guía construye ese diseño paso a paso.

¿Cuándo deberías usar Perl para el web scraping?

Usa Perl cuando:

  • Perl ya esté instalado y sea soportado en el entorno de producción;
  • la fuente devuelva HTML o JSON útiles sin la ejecución del navegador;
  • la tarea dependa de un procesamiento de texto maduro y transformación de archivos;
  • el scraper deba integrarse con un trabajo existente de ETL o informes en Perl;
  • el equipo valore un script pequeño y auditables sobre una pila de automatización de navegador.

Considera otro runtime o una API gestionada cuando la fuente dependa en gran medida de JavaScript del lado del cliente, estado interactivo del navegador, APIs multimedia o un marco con mejor soporte fuera de Perl. El punto no es hacer que Perl imite cada capacidad del navegador. Se trata de dejar que Perl maneje las partes que maneja bien: orquestación HTTP, análisis, validación y salida.

La documentación oficial de CPAN explica cómo Perl resuelve, construye, prueba e instala módulos. Fija versiones en un manifiesto de despliegue o imagen después de validarlas en tu entorno.

Elige el módulo de scraping de Perl correcto

Módulo Mejor uso JavaScript Soporte de sesión Fuente de instalación
HTTP::Tiny Cliente pequeño GET/POST con dependencias mínimas No Manual Núcleo de Perl en muchas instalaciones
LWP::UserAgent Encabezados, cookies, proxies, timeouts, redirecciones No Sí, con un frasco de cookies LWP::UserAgent
HTML::TreeBuilder Analiza HTML en un árbol transitable No No aplicable HTML::TreeBuilder
WWW::Mechanize Sigue enlaces, envía formularios, preserva cookies No WWW::Mechanize
Text::CSV Salida CSV consciente de estándares No aplicable No aplicable Text::CSV
JSON::PP Codifica o decodifica JSON sin una extensión compilada No aplicable No aplicable Incluido con Perl

La actual documentación de LWP::UserAgent cubre redirecciones, timeouts, cookies, autenticación y métodos de proxy. La documentación de WWW::Mechanize es explícita en que el módulo no ejecuta JavaScript.

Configura un proyecto de Perl reproducible

Requisitos previos:

  • Perl 5;
  • cpan o cpanm;
  • un directorio de proyecto escribible;
  • acceso saliente a HTTPS;
  • permiso para recopilar datos públicos del objetivo.

Crea un proyecto e instala los módulos exactos utilizados por el ejemplo completo:

bash Copy
mkdir perl-books-scraper
cd perl-books-scraper
cpanm LWP@6.83 HTML::Tree@5.07 Text::CSV@2.06 WWW::Mechanize@2.22
perl -MLWP -MHTML::TreeBuilder -MText::CSV -MWWW::Mechanize -e 'print "módulos listos\n"'

Estas versiones fueron verificadas contra sus registros de paquetes mientras se redactaba. Si un gestor de paquetes del sistema operativo proporciona módulos más antiguos, usa una biblioteca local del proyecto en lugar de reemplazar componentes del Perl del sistema.

Los archivos para este tutorial son:

Copy
perl-books-scraper/
├── scrape_books.pl
├── books.csv
└── books.json

Haz una pequeña solicitud con HTTP::Tiny

HTTP::Tiny es suficiente cuando la tarea es "enviar una solicitud e inspeccionar la respuesta". Devuelve un hash con status, reason, headers, y content.

perl Copy
use strict;
use warnings;
use HTTP::Tiny;

my $url = 'https://books.toscrape.com/';
```perl
mi $respuesta = HTTP::Tiny->new(
    agente  => 'PublicCatalogResearch/1.0',
    tiempo_de_espera => 20,
)->get($url);

muere "La solicitud falló: $respuesta->{estado} $respuesta->{razón}\n"
    a menos que $respuesta->{éxito};

imprimir "Recibido " . longitud($respuesta->{contenido}) . " bytes\n";

Esto es útil para verificaciones de punto final y fuentes JSON. Para cookies, credenciales de proxy, objetos de respuesta detallados o un manejo de redirección más rico, usa LWP::UserAgent.

Construir un raspador completo de LWP y HTML::TreeBuilder

El ejemplo ilustrativo recopila las tarjetas de producto visibles en la página de inicio de Books to Scrape, valida cada registro y escribe tanto en CSV como en JSON.

El bloque necesita acceso a la red a books.toscrape.com y los cuatro módulos instalados mencionados anteriormente. No necesita credenciales.

perl Copy
usar estricto;
usar advertencias;
usar utf8;

usar HTML::TreeBuilder;
usar JSON::PP qw(encode_json);
usar LWP::UserAgent;
usar Text::CSV;

binmode STDOUT, ':encoding(UTF-8)';
binmode STDERR, ':encoding(UTF-8)';

mi $url = $ENV{TARGET_URL} || 'https://books.toscrape.com/';
mi $ua = LWP::UserAgent->new(
    agente      => 'PublicCatalogResearch/1.0',
    tiempo_de_espera    => 20,
    tamaño_máximo   => 2_000_000,
);
$ua->protocols_allowed(['https']);

mi $respuesta = $ua->get($url);
muere "Fallo HTTP: " . $respuesta->status_line . "\n"
    a menos que $respuesta->is_success;

mi $contenido_tipo = $respuesta->header('Content-Type') || '';
muere "Esperado HTML, recibido $contenido_tipo\n"
    a menos que $contenido_tipo =~ m{text/html}i;

mi $árbol = HTML::TreeBuilder->new;
$árbol->ignore_unknown(0);
$árbol->parse_content($respuesta->decoded_content);

mi @registros;
para cada $tarjeta ($árbol->look_down(_tag => 'article', class => qr/\bproduct_pod\b/)) {
    mi $enlace = $tarjeta->look_down(_tag => 'h3')->look_down(_tag => 'a');
    mi $precio = $tarjeta->look_down(_tag => 'p', class => qr/\bprice_color\b/);
    mi $stock = $tarjeta->look_down(_tag => 'p', class => qr/\binstock\b/);

    siguiente a menos que $enlace && $precio && $stock;
    mi $título = $enlace->attr('title') || $enlace->as_trimmed_text;
    mi $href = $enlace->attr('href') || '';

    push @registros, {
        título => $título,
        precio => $precio->as_trimmed_text,
        stock => $stock->as_trimmed_text,
        url   => $href,
    };
}
$árbol->delete;

muere "Fallo en la verificación de aceptación: no hay registros de producto completos\n" a menos que @registros;

mi $csv = Text::CSV->new({ binary => 1, eol => "\n" })
    o muere "No se puede inicializar el codificador CSV\n";
abrir mi $csv_fh, '>:encoding(UTF-8)', 'books.csv'
    o muere "No se puede escribir books.csv: $!\n";
$csv->print($csv_fh, [qw(título precio stock url)]);
para cada $registro (@registros) {
    $csv->print($csv_fh, [@{$registro}{qw(título precio stock url)}]);
}
cerrar $csv_fh;

abrir mi $json_fh, '>:encoding(UTF-8)', 'books.json'
    o muere "No se puede escribir books.json: $!\n";
imprimir {$json_fh} JSON::PP->new->utf8(0)->canonical->pretty->encode(\@registros);
cerrar $json_fh;

imprimir "Aceptados " . scalar(@registros) . " registros de producto\n";

Ejecutarlo:

bash Copy
perl scrape_books.pl
cabeza -n 4 books.csv
perl -MJSON::PP -0777 -e 'decode_json(<STDIN>); imprimir "JSON válido\n"' < books.json

La verificación de aceptación es importante. Una página HTTP 200 aún puede ser una pantalla de inicio de sesión, página de desafío, mensaje de mantenimiento o plantilla cambiada. Un colector de producción debe validar los campos esperados y poner en cuarentena la salida inesperada en lugar de escribirla en el conjunto de datos principal.

¿Por qué no analizar HTML con expresiones regulares?

Perl tiene un excelente motor de expresiones regulares, pero HTML es un árbol con elementos anidados, atributos opcionales, entidades de caracteres, scripts, comentarios y marcado mal formado. Un patrón que funciona en una instantánea a menudo se rompe cuando cambia el espacio en blanco o el orden de los atributos.

Usa expresiones regulares para valores después de la selección—por ejemplo, para normalizar una cadena de precio. Usa un analizador HTML para localizar el elemento.

La referencia de HTML::TreeBuilder documenta look_down, atributos de elementos, extracción de texto y limpieza explícita del árbol. Llamar a $árbol->delete libera referencias circulares después del análisis.

La robustez del selector proviene de anclajes semánticos:

  • tipos de elementos estables y tokens de clase;
  • atributos data-* destinados al estado de la aplicación;
  • campos marcados por esquemas;
  • etiquetas cerca de valores;
  • verificaciones de aceptación para campos requeridos.

Evita suposiciones posicionales como "el tercer div contiene el precio."

Preservar sesiones y enviar formularios con WWW::Mechanize

WWW::Mechanize extiende LWP::UserAgent con enlaces, formularios, cookies y ayudantes de historial. Es útil para flujos de trabajo de formularios autorizados y pruebas de aplicaciones cuando el sitio devuelve HTML normal.

Este ejemplo usa una URL y nombres de campos de formulario como requisitos previos porque los formularios difieren según el sitio. Úsalo solo en una aplicación que poseas o que estés autorizado a probar.

perl Copy
usar estricto;
usar advertencias;
usar WWW::Mechanize;

mi $mech = WWW::Mechanize->new(
    agente      => 'AuthorizedFormTest/1.0',
    autocheck  => 1,
    tiempo_de_espera    => 20,
);
perl Copy
$mech->get($ENV{AUTHORIZED_FORM_URL});
$mech->submit_form(
    form_name => 'search',
    fields    => { query => 'documentación' },
);

print $mech->title . "\n";

No coloque nombres de usuario o contraseñas en un script publicado. Lea secretos de un entorno protegido o gerenciador de secretos, y mantenga los cuerpos de respuesta fuera de los registros cuando puedan contener datos de cuentas.

Configurar un proxy en LWP::UserAgent

Un proxy es apropiado cuando el requisito es una región seleccionada, una salida aprobada y estable, o separación entre trabajos de recopilación. No hace que un objetivo no autorizado sea aceptable.

El siguiente bloque es un ejemplo de configuración que requiere credenciales de proxy de propiedad del lector:

perl Copy
use strict;
use warnings;
use LWP::UserAgent;

for my $name (qw(PROXY_HOST PROXY_PORT PROXY_USER PROXY_PASSWORD)) {
    die "Establecer $name\n" unless defined $ENV{$name} && length $ENV{$name};
}

my $proxy = sprintf(
    '%s://%s:%s@%s:%s',
    'http',
    $ENV{PROXY_USER},
    $ENV{PROXY_PASSWORD},
    $ENV{PROXY_HOST},
    $ENV{PROXY_PORT},
);

my $ua = LWP::UserAgent->new(timeout => 20);
$ua->proxy([qw(http https)], $proxy);

my $response = $ua->get('https://example.com/');
die $response->status_line unless $response->is_success;
print $response->decoded_content;

Mantenga las credenciales del proxy en el entorno y oculte las de los informes de excepciones. La página de Scrapeless Proxy Solutions ayuda a mapear opciones residenciales, de centro de datos, ISP estático y IPv6 a requisitos de tráfico.

Manejar fallos sin corromper datos

La robustez comienza con resultados delimitados y explícitos:

  • rechazar códigos de estado HTTP no exitosos;
  • limitar el tamaño de respuesta y el tiempo de solicitud;
  • confirmar Content-Type;
  • validar la identidad de la página esperada;
  • requerir los campos que definen un registro completo;
  • escribir nueva salida a una ruta temporal y renombrarla solo después de la validación;
  • enviar páginas inesperadas a un directorio de cuarentena con metadatos seguros;
  • emitir registros estructurados sin credenciales ni cuerpos de respuesta.

Trate 403, 429, y HTML inesperado como señales para detenerse e investigar políticas, ritmo, cambios en el objetivo, o ajuste de adquisición. No cree un bucle de fallo ilimitado.

También respete el Protocolo de Exclusión de Robots, términos objetivo, leyes de privacidad y presupuestos de solicitudes específicos de la fuente. Para rastreos más grandes, almacene una URL canónica y un hash de contenido para que la misma página no se procese dos veces.

Sepa cuándo la página requiere JavaScript

Revise la respuesta en bruto antes de asumir que se requiere representación en el navegador:

  1. Abra las herramientas de desarrollador del navegador.
  2. Recargue la página e identifique la respuesta de la red que contiene los datos necesarios.
  3. Compare esa respuesta con la salida de LWP::UserAgent.
  4. Busque en el HTML un nombre de producto conocido o un identificador de registro.
  5. Si los datos provienen de un punto final JSON público, utilice ese punto final autorizado directamente.
  6. Si los datos solo existen después de la ejecución en el navegador, mueva la adquisición a una capa de representación.

WWW::Mechanize no es un motor de JavaScript. Existen módulos de Perl que controlan navegadores, pero agregan binarios de navegador, compatibilidad de controladores, aislamiento de procesos y mayores requisitos de recursos. Eso puede ser razonable para un pequeño sistema interno; rara vez es una mejora directa para un raspador estático.

Cuando las operaciones del navegador se conviertan en el proyecto principal, pruebe una URL representativa a través de la API de Raspado Universal y compare la salida aceptada, la latencia y el esfuerzo operativo.

Llamar a la API de Raspado Universal desde Perl

El camino gestionado mantiene el parser posterior en Perl. La API realiza la adquisición de la página y devuelve el resultado; Perl lo valida y transforma.

Este bloque de requisitos previos requiere SCRAPELESS_API_KEY y un TARGET_URL autorizado. Confirme los campos de solicitud actuales en el inicio rápido de la API de Raspado Universal antes de usar en producción.

perl Copy
use strict;
use warnings;
use HTTP::Tiny;
use JSON::PP qw(encode_json decode_json);

my $token = $ENV{SCRAPELESS_API_KEY} or die "Establecer SCRAPELESS_API_KEY\n";
my $target = $ENV{TARGET_URL} or die "Establecer TARGET_URL\n";

my $response = HTTP::Tiny->new(timeout => 60)->post(
    'https://api.scrapeless.com/api/v1/scraper/request',
    {
        headers => {
            'Content-Type' => 'application/json',
            'x-api-token'  => $token,
        },
        content => encode_json({
            actor => 'unlocker.webunlocker',
            input => { url => $target },
        }),
    },
);

die "Error de la API: $response->{status} $response->{reason}\n"

a menos que $response->{success};

mi $payload = decode_json($response->{content});
muere "La respuesta de la API no contenía datos\n" a menos que exista $payload->{data};
imprimir JSON::PP->new->canonical->pretty->encode($payload->{data});

Este límite es deliberadamente simple:

  • Scrapeless se encarga de la adquisición de páginas y operaciones de red;
  • Perl se encarga del ámbito objetivo, validación de respuestas, análisis y almacenamiento;
  • la organización se encarga de la autorización, retención y uso de datos.

Exportar CSV y JSON limpios

CSV y JSON sirven a diferentes sistemas de downstream.

Elige CSV cuando el resultado sea plano y vaya a Excel, a una importación de base de datos o a una herramienta de análisis. Usa Text::CSV; cita correctamente comas, saltos de línea y comillas.

Elige JSON cuando los registros contengan arreglos, objetos anidados o metadatos como URL de origen, hora de captura y estado de validación. JSON::PP es portátil y produce JSON compatible con los estándares.

Para un flujo de trabajo que entregue datos web a analistas, consulta raspado web en Excel con Power Query y APIs. Para opciones de salida de la API, lee la guía de formatos de respuesta de Scrapeless.

Cada registro debe llevar suficiente procedencia para auditar:

  • URL de origen;
  • hora de captura;
  • versión del parser o esquema;
  • localidad o región cuando sea relevante;
  • hash de contenido;
  • estado de aceptación.

Una lista de verificación de producción para raspadores de Perl

Antes de programar el script:

  • La fuente y los campos están autorizados.
  • Se revisaron las directivas de robots y términos del objetivo.
  • Las versiones de los módulos están fijadas y probadas.
  • Los secretos provienen de variables de entorno protegidas.
  • El parser utiliza selectores estructurales, no expresiones regulares HTML arbitrarias.
  • El tamaño de la respuesta, el tiempo, el tipo de contenido y los campos requeridos están limitados.
  • Las páginas inesperadas van a cuarentena.
  • Los registros excluyen credenciales y cuerpos sensibles.
  • La salida CSV y JSON es segura para la codificación.
  • Los requisitos de páginas dinámicas tienen una decisión de adquisición explícita.
  • Las métricas cuentan registros aceptados, no solo solicitudes.

Mantener a Perl enfocado en el contrato de datos

Perl es más fuerte cuando el raspador tiene un contrato claro: obtener una fuente autorizada, analizar estructuras conocidas, validar registros completos y escribir una salida determinista. Eso sigue siendo útil ya sea que el HTML provenga directamente de LWP::UserAgent, a través de un proxy, o de una API de renderizado gestionada.

Comienza con el método que funcione más pequeño. Si la página es dinámica o está fuertemente protegida, mantén el parser de Perl validado y reemplaza solo la adquisición. Compara las opciones de precios actuales de Scrapeless, luego crea una cuenta en Scrapeless y prueba una URL pública representativa antes de comprometerte a una migración más grande.

Preguntas frecuentes

¿Sigue siendo bueno Perl para el raspado web en 2026?

Sí, especialmente para equipos con un entorno Perl existente y objetivos que devuelven HTML o JSON útiles. Perl tiene módulos maduros para HTTP, análisis HTML, sesión, CSV y JSON. El trabajo que requiere navegadores puede ser más fácil a través de una capa de adquisición gestionada u otra pila de automatización soportada.

¿Qué módulo de Perl es el mejor para el raspado web?

Usa HTTP::Tiny para un cliente minimalista, LWP::UserAgent para un control de solicitud más rico, HTML::TreeBuilder para el análisis de HTML y WWW::Mechanize para enlaces, formularios, cookies e historial de sesiones. La mayoría de los proyectos reales combinan un cliente HTTP con un parser y un codificador de salida.

¿Puede LWP::UserAgent ejecutar JavaScript?

No. Recupera respuestas HTTP pero no ejecuta el JavaScript de la página. Si los datos necesarios están ausentes en la respuesta, utiliza un endpoint JSON autorizado, una herramienta de navegación o una API de renderizado gestionada.

¿Se deben usar expresiones regulares de Perl para analizar HTML?

No, no para la estructura del documento. Usa un parser HTML para localizar elementos, luego utiliza expresiones regulares para normalizar el texto seleccionado cuando sea necesario.

¿Cómo se usa un proxy con Perl?

Crea un LWP::UserAgent y llama a su método proxy para los protocolos requeridos. Lee el host del proxy, el puerto, el nombre de usuario y la contraseña de variables de entorno protegidas.

La legalidad depende de la jurisdicción, el método de acceso, los términos del objetivo, el tipo de datos y el uso previsto. Limita la recopilación a datos públicos autorizados, respeta las directivas de robots y los límites de origen, minimiza los datos personales y obtiene asesoría legal para programas de mayor riesgo.

En Scrapeless, solo accedemos a datos disponibles públicamente y cumplimos estrictamente con las leyes, regulaciones y políticas de privacidad del sitio web aplicables. El contenido de este blog es sólo para fines de demostración y no implica ninguna actividad ilegal o infractora. No ofrecemos garantías y renunciamos a toda responsabilidad por el uso de la información de este blog o enlaces de terceros. Antes de realizar cualquier actividad de scraping, consulte a su asesor legal y revise los términos de servicio del sitio web de destino u obtenga los permisos necesarios.

Artículos más populares

Catalogar