Hacer web scraping con PHP Simple HTML DOM Parser

En este post intentaremos explicar que es el webscraping y como realizarlo en php mediante la biblioteca PHP Simple HTML DOM Parser.

¿Que es el scraping?

El webscraping es una técnica que nos permite extraer determinada información de paginas web. El proceso es simple: descargamos el código fuente de la pagina web, navegamos a través del dom para localizar los datos que deseamos, y una vez extraídos, los procesamos.

Simple HTML Dom

Simple HTML Dom es una librería que nos facilita parsear contenido html, extrayendo de manera rápida y sencilla los datos que nos interesan.

Podemos descargarla desde su pagina web y consultar su manual.

Evitando problemas

Si queremos scrapear solo una pagina, normalmente no tendremos problemas. La cosa cambia si queremos scrapear cientos de paginas, debido a que es muy sencillo que el servidor donde este alojado la web nos acabe baneando la ip.

Para evitarlo, podemos realizar dos mejoras en nuestro código:

  1. Limitar las peticiones al servidor: podremos hacer que espere x segundos entre scrapeo de pagina y pagina, simulando un comportamiento mas parecido a un «usuario normal».
  2. Utilización de proxys: de esta manera, en caso de producirse un baneo, solo afectara a la ip del proxy, nunca a la ip de nuestro equipo. Tan solo deberemos ir rotando los proxies cada x peticiones

Instalación de PHP Simple HTML Dom Parser

El primer paso es visitar la pagina oficial y nos descargamos los ficheros necesarios.

En fichero zip, podemos encontrar en el raíz el fichero simple_html_dom.php. Este fichero es que necesitamos incluir al comienzo de nuestro código php:

<?php
include('simple_html_dom.php');

Descargando la pagina a scrapear

El primer paso es descargar la pagina a procesar. Personalmente, prefiero descargarla y crear un fichero html en disco, para luego poder procesarla. De esta manera, reducimos el numero de llamadas al servidor, y asi minimizamos el riesgo de ser baneada nuestra ip.

Veamos como descargar la pagina:

  • Simple HTML DOM: es el método mas sencillo, ya que la biblioteca tiene un par de funciones a las que podemos llamar para descargar la pagina de manera sencilla

Con Simple HTML DOM

Mediante las funciones file_get_html() que nos permite obtener el contenido html de una url y save() que grabar dicho contenido en un fichero local, podremos obtener una copia en local de la url.

$html = file_get_html('http://urladescargar.es');
$html->save('nombredelficherourladescargar_es.html');

Extrayendo y procesando los datos que nos interesan

PHP Simple HTML DOM nos permite seleccionar el criterio a emplear para seleccionar el contenido que nos interesa.

Básicamente, podemos utilizar 3 métodos:

  • Utilizando el nombre de la etiqueta html (por ejemplo h2, h3, etc)
  • Utilizando el nombre de la clase de la etiqueta html
  • Utilizando el nombre del id de la etiqueta html

Utilizar el nombre de la etiqueta html

Por ejemplo, si deseamos obtener todos los enlaces (etiqueta «a»):

$html->find('a');

Utilizando el nombre de la clase de la etiqueta

Para obtener los tags html cuya clase sea «titulo»:

$html->find('.titulo');

Utilizando el nombre del id de la etiqueta

Podemos realizar la seccion segun los id de las etiquetas. Por ejemplo para seleccionar la etiqueta div con el id foo:

$html->find('div[id=foo]');

Mejoras en el código

Limitando la velocidad de scrapeo

La velocidad de petición de paginas al servidor de un scraper es mucho mayor que la de un usuario. Para evitar «saturar» al servidor, es muy recomendable realizar una pequeña pausa (entre 2-5 segundos) entre cada petición de la pagina.

De esta forma, ademas evitamos ser baneados por realizar demasiadas peticiones en poco tiempo.

Por ejemplo, colocando el siguiente código dentro del bucle de scrapeo de las paginas hacemos una pausa aleatoria entre 2 y 5 segundos:

sleep(rand(2,5));

Utilización de proxys

La utilización de proxys es muy recomendable, ya que si realizamos múltiples peticiones a un servidor desde la ip en un intervalo de tiempo muy pequeño, seguramente acabemos baneados.

En el siguiente código podemos ver como podemos pasarle parámetros al realizar la llamada a file_get_html y asi utilizar un proxy.

Ademas de un proxy, también podemos aprovechar listas publicas de user-agents, y cambiarlo en cada petición. De esta manera dificultamos el ser baneados.

$context = stream_context_create();
stream_context_set_params($context, array(
			'user_agent' => $useragent, 
			'proxy' => $proxyurl,
			'ignore_errors' => true, 
			'max_redirects' => 10)
		);
$html = file_get_html($url_contains_articles, 0, $context);

Veamos todo lo anterior con un ejemplo

La mejor manera de comprender todo lo anterior es con un ejemplo.

Vamos a scrapear la portada del periodico «El mundo» para obtener los titulares. Si cargamos la pagina en el navegador y revisamos su codigo fuente, podemos comprobar que los titulares de las noticias tienen la clase ue-c-cover-content__link

<?php
	include_once('./simple_html_dom.php');

        //Es posible que cuando pruebes este proxy no este activo, en caso de ser asi, busca uno
        //que si lo este en cualquier pagina de proxies gratuitos en internet
	$proxyurl = '88.198.50.103:8080';

	$context = stream_context_create();
	stream_context_set_params($context, array(
				'proxy' => $proxyurl,
				'ignore_errors' => true, 
				'max_redirects' => 3)
				);

	$html = file_get_html('https://www.elmundo.es', 0, $context);

	echo "Buscando los titulares de las noticias... \n\n";

	echo "\t- Buscando los elementos de la clase .ue-c-cover-content__link ... \n\n";

	$articles_titles = $html->find(".ue-c-cover-content__link");

	foreach($articles_titles as $article_title) {
		echo "\t\t".$article_title->plaintext."\n";
	}

	$html->clear();
	unset($html);
?>

Es importante antes de finalizar llamar a la función clear() y hacer un unset de la variable $html para liberar la memoria de manera adecuada.

Comentar