Un cliente con el que trabajé estaba buscando aumentar el tamaño de su base de datos para realizar mailings y me pidió que le diseñe un robotito para extraer las direcciones de correo que estén presentes en las páginas resultantes de ciertas búsquedas de Google.
Si bien personalmente no lo considero algo muy productivo (Discusión aparte sobre la efectividad/ética de enviar correo no deseado o si realmente se trata de correo no deseado cuando se ofrece una solución que realmente va a ayudar a quien lo reciba), me pareció interesante el desafío técnico (y también, hay que reconocerlo, a veces simplemente hay que darle al cliente lo que quiere :)).
Lo primero que se me ocurrió fue que, así como hay APIs para entrar a Gmail, a GoogleDocs y demás, debía haber alguna para usar el motor de búsqueda y obtener los datos en formato JSON, XML o algún otro formato digno de un webservice.
Y ahí vino mi primera sorpresa (Eso es lo que me fascina de la programación: siempre hay cosas nuevas para aprender :)): a Google no le gusta que los robots le usen su motor (Irónico, ¿no? ellos viven de scrappear toda la web, pero…).
De modo que, para lograr esta hazaña había que arremangarse y parsear HTML (Algo como lo que te comenté sobre cómo acceder a sitios que no te dan API) o bien, siendo que se trata de un sitio archi-conocido, buscar en Packagist.org que seguro iba a tener algo piola para arrancar al menos.
Como de costumbre, Packagist no me defraudó y conocí el proyecto SERPS.
Qué es el proyecto SERPS
El proyecto SERPS es un esfuerzo por crear un conjunto de herramientas que permitan suplir esta falta, es decir, es un set de bibliotecas que permite (o, mejor dicho, permitirá) automatizar las búsquedas en diferentes motores (Actualmente sólo Google está implementado).
Es bastante interesante desde su arquitectura, bien modular y de bajo acoplamiento (Se nota la aplicación del patrón strategy).
A nivel práctico, se trata de una capa de abstracción muy útil para «olvidarnos» de la complejidad de interpretar los resultados de una búsqueda (¡y los caprichos de los pedidos!).
Preparando el proyecto para usar SERPS
SERP está diseñado para ser usado con composer. Al principio de su documentación hay un ejemplo de archivo composer.json
que te recomiendo copiar y pegar (Yo intenté incluir las dependencias que iba necesitando y no funcionó nada :p):
{ "require": { "serps/core": "*", "serps/search-engine-google": "*", "serps/http-client-curl": "*" } }
Además de estos paquetes básicos, para que todo funcione hace falta correr estos comandos:
composer require 'serps/search-engine-google' composer require 'guzzlehttp/psr7'
Con esta configuración (y, obviamente, un composer install
) tenés todo lo necesario para hacer queries a Google usando PHP.
Cómo hacer una búsqueda en Google usando SERPS
Como decía al comienzo, a Google no le gustan los robots, así que… hay que hacer de cuenta que la búsqueda la hace una persona. Obviamente, una persona que está usando algún navegador. Todo esto se traduce en usar un User-Agent adecuado.
Te muestro un ejemplo de lo que yo hice:
#!/usr/bin/php <?php use Serps\HttpClient\CurlClient; use Serps\Core\Browser\Browser; use Serps\SearchEngine\Google\GoogleClient; use Serps\SearchEngine\Google\GoogleUrl; require_once 'vendor/autoload.php'; $userAgent = "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.93 Safari/537.36"; $browserLanguage = "es-AR"; $browser = new Browser(new CurlClient(), $userAgent, $browserLanguage); $googleClient = new GoogleClient($browser); $googleUrl = new GoogleUrl(); foreach ( file($argv[1]) as $searchTerms ) { $googleUrl->setSearchTerm($searchTerms); $response = $googleClient->query($googleUrl); $results = $response->getNaturalResults(); foreach ($results as $result) { if ( $result->url ) { echo $result->url . PHP_EOL; } } }
En mi caso, el script toma como parámetro un archivo (que asumo tiene una línea por búsqueda que se quiere hacer) y emite los links encontrados.
Fijate que sencillo:
Se crea un objeto Serps\SearchEngine\Google\GoogleClient
usando un objeto Serps\Core\Browser\Browser
como interface para realizar la comunicación HTTP y otro objeto Serps\SearchEngine\Google\GoogleUrl
para armar la consulta como es debido.
Luego de consultar se obtienen los resultados naturales (Es decir, aquellos resultados no pagos) y, por cada uno se emite el link. En mi caso todo esto va acompañado de otro script que busca direcciones de correo electrónico dentro de una página web y emite los resultados como para ser incorporados a un archivo .csv.
Ejemplo de uso del script
Ya teniendo las dos herramientas (la que busca links en Google y la que busca direcciones de mail dentro de una página), es muy fácil componerlas (Si usás algún sistema operativo POSIX como Linux al menos :p):
./get_links.php terms.csv | ./get_emails.php
En el archivo terms.csv se escribe, línea por línea, las búsquedas que quiero realizar, el script get_links.php emite cada resultado que obtiene y get_emails.php toma sus datos de la entrada estándar… justo lo que se necesita para usar pipes :).
Y claro, la frutilla del postre es guardar la salida de get_emails.php en un nuevo archivo .csv:
./get_links.php terms.csv | ./get_emails.php > mails.csv
Conclusión
La tarea de hacer webscrapping no es muy grata que digamos (Especialmente porque los grandes esfuerzos que se hacen pueden resultar en vano si el sitio a ser scrappeado cambia su layout…), pero… a veces resulta útil.
Y, si bien algunos sitios hacen lo posible para «protegerse» de este tipo de prácticas… es poco lo que pueden hacer para evitarlas al 100%…
¿Qué experiencia tuviste vos con el scrapping?
- Cómo enviarencabezados SOAP desde PHP - 09/12/2024
- Por qué PHP 8 no satisface el requisito ^7.3 de composer - 09/12/2024
- Cómo usar PHPUnit - 03/12/2024