Volver al blog
Guías
Sorin-Gabriel Marica14 de enero de 202314 min de lectura

Extracción de datos web con PHP: la guía definitiva sobre la extracción de datos web

Extracción de datos web con PHP: la guía definitiva sobre la extracción de datos web

Qué es el web scraping

La ingente cantidad de datos que hay en Internet se encuentra lamentablemente dispersa en miles de millones de sitios web. Por ello, los desarrolladores necesitan una forma de recopilarlos y procesarlos para ofrecer a los usuarios productos nuevos e innovadores. Sin embargo, la recopilación manual de información no es, en absoluto, una buena idea, ya que el volumen suele ser demasiado grande y los datos cambian continuamente.

La solución consiste en extraerla automáticamente. En pocas palabras, eso es lo que hace el web scraping.

Por qué deberías extraer datos

Cuanta más información se recopila, más ideas, oportunidades y ventajas surgen. Una vez procesada, puede resultar de un valor incalculable tanto para ti como para tus clientes. A continuación te mostramos algunas formas en las que se puede utilizar el web scraping:

  • Herramientas de comparación de precios: recopilación de datos de múltiples sitios web para obtener una visión general de los precios de un tipo de producto.
  • Estudio de mercado: averiguar quiénes son tus principales competidores y qué están haciendo.
  • Aprendizaje automático: recopilación de conjuntos de datos de entrenamiento y de prueba para un modelo de aprendizaje automático.
  • Cualquier idea que requiera el acceso a una cantidad considerable de datos.

Por ejemplo, un posible caso de uso sería crear una aplicación nutricional que permita a los usuarios añadir sus comidas. Lo ideal sería que los usuarios simplemente abrieran la aplicación, buscaran los productos que han consumido, los añadieran a la herramienta y pudieran saber cuántas calorías más pueden consumir después.

Sin embargo, la herramienta debe ofrecer una lista exhaustiva de todos los productos posibles y sus valores nutricionales. Esta lista se puede crear y actualizar automáticamente recopilando la información nutricional de múltiples sitios web.

Los retos del web scraping

Aunque el web scraping resulta muy útil para quien utiliza el bot, a veces los sitios web no están dispuestos a compartir su contenido y pueden intentar impedirlo. Algunas de las formas en que pueden hacerlo son:

  • Códigos CAPTCHA: cualquier página puede utilizar CAPTCHAs, aunque no se vean. Si realizas varias solicitudes, es posible que aparezca un código CAPTCHA y que esto provoque un fallo en tu rastreador web.
  • Bloqueo de IP: algunos sitios web optan por bloquear tu IP cuando detectan un tráfico excesivo procedente de tu dispositivo.
  • Bloqueo geográfico: es posible que algunos contenidos solo estén disponibles en determinados países, o que recibas información específica de una región cuando lo que buscas es información de otra.
  • JavaScript: la mayoría de los sitios web actuales utilizan JavaScript de una forma u otra. Algunos muestran su contenido de forma dinámica, lo que complica las cosas, ya que el código fuente de la página no coincide con el contenido que se muestra en pantalla.

Superar estos retos puede suponer mucho trabajo, pero hay alternativas. Para ayudarte, hemos creado WebscrapingAPI, que se encarga de todos estos problemas y te ayuda a desarrollar tu solución más rápido y con menos complicaciones.

Comprender la web

Cada vez que un usuario de Internet accede a un sitio web, el navegador genera una solicitud HTTP (Protocolo de Transferencia de Hipertexto). Una solicitud puede entenderse como un mensaje del cliente (el ordenador del usuario) al servidor (el ordenador en el que se aloja el sitio web), en el que el cliente especifica lo que desea recibir.

Por cada solicitud enviada, recibirás una respuesta. La respuesta puede ser correcta o indicar un error, como el famoso código de error «404: página no encontrada». El contenido de un sitio web suele encontrarse en el cuerpo de la respuesta recibida del servidor.

Diagrama cliente-servidor que muestra las flechas de solicitud y respuesta entre un cliente y un servidor

Tanto las solicitudes como las respuestas contienen un encabezado y un cuerpo que se utilizan para intercambiar información. Además, las solicitudes pueden utilizar distintos métodos, siendo el más habitual el GET (que se utiliza para acceder a una página web). Estos métodos indican la acción que el cliente desea realizar.

Por ejemplo, al registrarte o actualizar tu contraseña en un sitio web, es preferible que tus datos permanezcan ocultos en el navegador, y los sitios web pueden utilizar los métodos POST o PUT para este tipo de solicitud.

El encabezado de una solicitud contiene varias propiedades. Repasemos las más importantes:

  • Host: el nombre de dominio del servidor.
  • User-Agent: información sobre el cliente que ha realizado la solicitud, como el navegador y el sistema operativo.
  • Cookie: conjunto de propiedades asociadas al cliente.
  • Accept: parámetro utilizado para recibir la respuesta del servidor en un tipo específico, como text/plain o application/json.

Sin embargo, las solicitudes no se limitan a las páginas web. También se realizan para imágenes, estilos y código JavaScript, independientemente de la página. Puedes echar un vistazo a todas las solicitudes que realiza tu navegador Google Chrome al acceder a una página web pulsando F12 en una página, seleccionando la pestaña «Red» y actualizando la página en la que te encuentras. Al final deberías ver algo como esto:

Panel «Red» de Chrome DevTools, que muestra las solicitudes y los encabezados de respuesta de una página web

Comprender PHP

PHP es uno de los lenguajes de programación web más antiguos y populares que se utilizan para el backend de las aplicaciones. Existe desde 1995 y actualmente se encuentra en su octava versión.

Los programadores eligen este lenguaje de programación por su sintaxis sencilla y su facilidad de ejecución, ya que lo único que se necesita para ejecutar código PHP es un equipo que tenga PHP instalado. Además, dado que lleva tanto tiempo en el mercado, existen numerosos recursos y asistencia para resolver y depurar errores de PHP.

PHP también cuenta con numerosos marcos de trabajo y CMS (sistemas de gestión de contenidos) muy populares desarrollados en este lenguaje de programación. Algunos ejemplos destacados son WordPress, Drupal, Magento y Laravel.

No obstante, también presenta algunas desventajas. Por ejemplo, resulta más difícil extraer contenido dinámico en comparación con Python o JavaScript. Sin embargo, si solo necesitas información de páginas sencillas, PHP es sin duda una buena solución y te permite guardar o almacenar los datos extraídos con mucha más facilidad.

Lo que necesitarás

¿Todo bien hasta ahora? ¿Listo para crear tu primer rastreador web? Antes de empezar, debes disponer de un medio para ejecutar tu código PHP. Puedes elegir un servidor Apache/Nginx con PHP instalado y ejecutar el código directamente desde tu navegador, o bien puedes ejecutarlo desde la línea de comandos.

Hagámonos la vida más fácil utilizando una biblioteca para procesar el contenido extraído. Algunas de las bibliotecas de scraping más populares para PHP son Goutte, Simple HTML DOM, Panther y htmlSQL. Como alternativa, también puedes optar por procesar el contenido mediante expresiones regulares.

En esta guía utilizaremos Simple HTML DOM. Sin embargo, para solicitudes más avanzadas, también utilizaremos la biblioteca de PHP llamada CURL.

Uso del DOM HTML básico

Simple HTML Dom es una biblioteca desarrollada para las versiones de PHP 5.6 y superiores, y nos permite acceder al contenido de la página de una forma mucho más sencilla: mediante selectores. Puedes descargar la biblioteca desde aquí, y te recomendamos que leas también la documentación.

Del archivo zip que encontrarás en el enlace de descarga, solo necesitarás el archivo simple_html_dom.php, que deberás colocar en la misma carpeta en la que escribirás el código del rastreador.

Para incluir la biblioteca en el código, solo necesitas esta línea de código:

include 'simple_html_dom.php'; // Si la biblioteca se encuentra en otra carpeta, debes escribir: include 'ruta_a_la_biblioteca/simple_html_dom.php'

Instalación de PHP-CURL

Aunque no siempre es necesario, tendrás que enviar diferentes encabezados para las solicitudes más avanzadas. El uso de la biblioteca PHP-CURL te será de ayuda.

Para instalarlo en un equipo con Ubuntu, puedes utilizar el siguiente comando:

sudo apt-get install php-curl

Una vez instalada la biblioteca, no olvides reiniciar tu servidor Apache/Nginx.

Crea tu propio raspador web

Ahora que tenemos todo lo necesario, ¡es hora de extraer los datos! En primer lugar, debes decidir qué sitio web y qué contenido quieres extraer. Para este artículo, extraeremos el contenido de la lista de películas mejor valoradas de IMDB.

1. Revisa el contenido del sitio web

La mayor parte del contenido web se muestra mediante HTML. Dado que necesitamos extraer contenido específico del código fuente HTML, también es necesario comprenderlo. Primero debemos examinar cómo es el código fuente de la página para saber qué elementos debemos extraer de ella.

Para ello, en Google Chrome, haz clic con el botón derecho del ratón sobre el elemento que quieras extraer y selecciona «Inspeccionar elemento». Se abrirá una ventana en el navegador con el código fuente de la página y los estilos aplicados a los elementos. En esta ventana, la única pestaña que debemos consultar es «Elementos», que nos mostrará cómo está estructurado el DOM HTML de la página.

Lista de las películas mejor valoradas en IMDb, con herramientas de desarrollo que analizan el código HTML en busca de un enlace a la película

Por ejemplo, la página contiene una tabla con las clases «chart» y «full-width», como se ve en la imagen anterior. En esta tabla, cada celda tiene su propia clase (posterColumn, titleColumn, etc.), que podemos utilizar para crear un selector. De este modo, podemos acceder únicamente a los datos necesarios.

¿Estás confundido? No te preocupes, los siguientes pasos te lo aclararán todo.

2. Enviar una solicitud desde PHP

Enviar una solicitud, en este caso, significa básicamente acceder directamente al código HTML de una página mediante código PHP. Hay dos formas de hacerlo.

En primer lugar, podemos utilizar la biblioteca PHP-CURL, que también nos permite modificar los encabezados y el cuerpo que enviamos en nuestra solicitud.

<?php
 
header("Content-Type: text/plain"); // We choose to display the content as plain text
 
$ch = curl_init("https://www.imdb.com/chart/top/");
curl_setopt($ch, CURLOPT_HEADER, 0);
$response = curl_exec($ch); // Running the request
 
if (curl_error($ch)) {
    echo curl_error($ch); // Displaying possible errors from the request
} else {
    echo $response; // Displaying the content of the response
}
 
curl_close($ch);
?>

Otra opción es una línea de código que utilice el método `file_get_contents($url) `, pero esto puede resultar insuficiente en algunos casos. Para enviar encabezados en esta solicitud, es necesario utilizar un contexto creado con el método `stream_context_create`.

<?php
 
header("Content-Type: text/plain"); // We choose to display the content as plain text
 
echo file_get_contents('https://www.imdb.com/chart/top/'); // We retrieve and display the contents of the response in a single line
 
?>

Debes decidir qué método utilizar en función de la complejidad del rastreador que quieras crear.

Los dos fragmentos de código anteriores mostrarán el código fuente HTML de la página que estamos rastreando, el mismo que se ve al inspeccionar el sitio web. Usaremos la primera línea del código para mostrar los resultados como texto sin formato. De lo contrario, se mostrarán directamente como HTML.

Si hay alguna diferencia en la estructura HTML, significa que hay un código JavaScript ejecutándose en el sitio web que modifica el contenido en cuanto un usuario accede a él. Más adelante en este artículo te ofrecemos un consejo sobre cómo solucionar este problema.

3. Extraer los datos

De la página seleccionada, extraeremos únicamente el título de las películas y la puntuación asociada a cada una de ellas. Como hemos visto anteriormente, el contenido se muestra en una tabla en la que cada celda tiene su propia clase.

De este modo, podemos extraer todas las filas de la tabla. A continuación, revisamos cada fila por separado en busca de las celdas que nos interesan.

El siguiente fragmento de código debería servir para eso:

<?php
 
header("Content-Type: text/plain"); // We choose to display the content as plain text
 
include 'simple_html_dom.php';
 
$html_dom = file_get_html('https://www.imdb.com/chart/top/'); // We retrieve the contents using file_get_html from simple_html_dom
$table_rows = $html_dom->find('table.chart tbody tr'); // Getting all of the table rows
foreach($table_rows as $table_row) {
    $title_element = $table_row->find('.titleColumn a', 0);
    $rating_element = $table_row->find('.ratingColumn strong', 0);
    if (!is_null($title_element) && !is_null($rating_element)) { // Checking if the row has a title and a rating column
        echo $title_element->innertext . ' has rating ' . $rating_element->innertext . PHP_EOL; // If it does then we print it
    }
}
 
?>

Como puedes ver, hemos utilizado el selector«table.chart tbody tr»para extraer todas las filas de la tabla. Es recomendable utilizar selectores lo más específicos posible, para poder diferenciar los elementos que necesitas del resto.

Tras recuperar las filas, las recorrimos en un bucle, buscando elementos con la clase «titleColumn » o «ratingColumn». Si el código encontraba alguno, mostraba su propiedad «innerText».

Es importante señalar que en este ejemplo hemos utilizado `file_get_html` en lugar de `file_get_contents` . Esto se debe a que esta función procede de la biblioteca `simple_html_dom ` y actúa como envoltura de la función `file_get_contents`.

4. Exportar los datos

En los ejemplos anteriores, hemos recopilado los datos del sitio y los hemos mostrado directamente en la pantalla. Sin embargo, también puedes guardar los datos en PHP con bastante facilidad.

Puedes guardar los datos extraídos en un archivo .txt, en formato JSON, en formato CSV o incluso enviarlos directamente a una base de datos. PHP es muy eficaz para eso. Solo tenemos que almacenarlos en una matriz y guardar el contenido de la matriz en un nuevo archivo.

<?php
 
include 'simple_html_dom.php';
 
$scraped_data = [];
 
$html_dom = file_get_html('https://www.imdb.com/chart/top/'); // We retrieve the contents using file_get_html from simple_html_dom
$table_rows = $html_dom->find('table.chart tbody tr'); // Getting all of the table rows
foreach($table_rows as $table_row) {
    $title_element = $table_row->find('.titleColumn a', 0);
    $rating_element = $table_row->find('.ratingColumn strong', 0);
    if (!is_null($title_element) && !is_null($rating_element)) { // Checking if the row has a title and a rating column
        $scraped_data[] = [
            'title' => $title_element->innertext,
            'rating' => $rating_element->innertext,
        ];
    }
}
 
file_put_contents('file.json', json_encode($scraped_data)); // Saving the scraped data in a .json file
 
// Saving the scraped data as a csv
$csv_file = fopen('file.csv', 'w');
fputcsv($csv_file, array_keys($scraped_data[0]));
 
foreach ($scraped_data as $row) {
    fputcsv($csv_file, array_values($row));
}
 
fclose($csv_file);
 
?>

El código anterior toma el mismo contenido que extrajimos antes y crea dos archivos, uno en formato CSV y otro en formato JSON, con todas las películas mejor valoradas y sus puntuaciones.

Consejos y trucos

1. Gestión de errores

Cuando se programa en PHP y se extraen datos de sitios web que pueden cambiar en cualquier momento, es habitual que surjan errores. Un buen fragmento de código que puedes utilizar para la depuración son las tres líneas siguientes, que deben colocarse al principio de cualquier script de PHP:

ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
error_reporting(E_ALL);

Esto te ayudará a detectar problemas en tu código más rápidamente y a actualizar tu script cuando sea necesario.

2. Configuración de encabezados en las solicitudes de PHP

A veces, al realizar una solicitud, es posible que también tengas que enviar algunos encabezados. Por ejemplo, al trabajar con una API, puede que sea necesario un token de autorización, o quizá prefieras que el contenido se envíe en formato JSON en lugar de texto sin formato. Puedes añadir encabezados tanto con curl como con file_get_contents. A continuación te explicamos cómo hacerlo con curl:

$ch = curl_init("http://httpbin.org/ip");
curl_setopt($ch, CURLOPT_HEADER, [
    'accept: application/json'
]);
$response = curl_exec($ch); // Ejecutar la solicitud

Y en cuanto a `file_get_contents`:

$opts = [
    "http" => [
        "method" => "GET",
        "header" => "accept: application/json\r\n"
    ]
];
$context = stream_context_create($opts);
$result = file_get_contents("http://httpbin.org/ip", false, $context);

3. Uso de curl o file_get_contents con simple_html_dom

Cuando extrajimos contenido de IMDB, utilizamos la función `file_get_html` de `simple_html_dom` para realizar el rastreo. Este método funciona para solicitudes sencillas, pero no necesariamente para las más complejas. Si necesitas enviar encabezados, es mejor que utilices uno de los métodos descritos en el consejo anterior.

Para utilizarlas en lugar de `file_get_html`, basta con extraer el contenido y luego usar `str_get_html` para convertirlo en un objeto DOM, de esta manera:

$opts = [
    "http" => [
        "method" => "GET",
        "header" => "accept: text/html\r\n"
    ]
];
$context = stream_context_create($opts);
$result = file_get_contents("https://www.imdb.com/chart/top/", false, $context);
$html_dom = str_get_html($result);

Además, ten en cuenta que simple_html_dom tiene, por defecto, algunos límites (que se pueden consultar en el archivo simple_html_dom.php). Por ejemplo, el contenido del sitio web puede tener hasta 600 000 caracteres. Si deseas modificar este límite, solo tienes que definirlo al principio del código antes de incluir la biblioteca simple_html_dom:

define('MAX_FILE_SIZE', 999999999);

4. Extracción de contenido dinámico

Si vas a extraer datos de una página web dinámica, tendrás que acceder a ella como lo haría un navegador. De lo contrario, no podrás extraer los datos reales y, en su lugar, obtendrás código JavaScript.

Tendrás que instalar un controlador de navegador, como chromium-chromedriver o firefox-geckodriver. Extraer contenido dinámico en PHP es un tema más avanzado, pero si te interesa, puedes intentar hacerlo leyendo la documentación de la biblioteca Panther.

Otra opción, mucho más sencilla, es utilizar WebScrapingAPI, que resuelve la mayoría de los problemas. La API supera los bloqueos de IP y los captchas utilizando nuestra red de proxies, al tiempo que ejecuta el código JavaScript. El resultado: dispones de inmediato de un rastreador avanzado, lo que reduce el tiempo de desarrollo y de espera.

A continuación se muestra un ejemplo de código que mostrará el contenido de https://httpbin.org/ip directamente en PHP, a través de nuestra API:

$content = 
file_get_contents("https://api.webscrapingapi.com/v1?pi_key=YOUR_API_KEY&url=". urlencode('https://httpbin.org/ip'));
echo $content;

Conclusión

¡Enhorabuena por haber llegado hasta el final! Ahora ya deberías tener todo lo necesario para crear tu rastreador web con PHP. Aunque en este artículo solo hemos visto la biblioteca simple_html_dom, puedes probar otras bibliotecas populares y descubrir por ti mismo cuál te conviene más.

Recuerda que los sitios web cambian constantemente y que sus datos pueden actualizarse de la noche a la mañana. Para solucionar esto, puedes utilizar selectores más específicos. Por supuesto, no hay garantía de que tu rastreador vaya a funcionar para siempre, pero es un buen comienzo. Por eso los rastreadores web requieren actualizaciones continuas que llevan mucho tiempo.

Si no te apetece dedicar todo ese tiempo a investigar y adaptar tu código, ¡siempre puedes probar la versión de prueba gratuita de WebScrapingAPI!

Acerca del autor
Sorin-Gabriel Marica, desarrollador full-stack en WebScrapingAPI
Sorin-Gabriel MaricaDesarrollador full-stack

Sorin Marica es ingeniero Full Stack y DevOps en WebScrapingAPI, donde se encarga de desarrollar funciones para los productos y de mantener la infraestructura que garantiza el buen funcionamiento de la plataforma.

Empieza a crear

¿Estás listo para ampliar tu recopilación de datos?

Únete a más de 2000 empresas que utilizan WebScrapingAPI para extraer datos de la web a escala empresarial sin ningún gasto de infraestructura.