Cómo obtener información de un sitio que no tiene API usando PHP

Me encontré recientemente con este problema desarrollando un sistema para un cliente y creo (¡y espero!) que mi experiencia pueda ayudar a otros.

El desafío era el siguiente: nuestro cliente es una empresa que se dedica a la administración de activos financieros. Como parte de su operatoria, requieren la consolidación de información que actualmente está dispersa en una serie de planillas Excel.

Parte de esa información se refiere a movimientos de acciones y bonos. Una de las tareas que se realizaba manualmente era el cálculo de cuánto dinero se había movido al realizar una compra o venta de alguno de estos instrumentos (Simple: cantidad de títulos por precio del título al día de la transacción).

La complejidad de este cálculo reside en cómo conseguir el precio que tenía el activo al día en que se realizó la transacción. Antes de la intervención de Leeway esta tarea estaba a cargo de una empleada de la compañía (Entre muchas otras, tenía que buscar en el sitio de Yahoo Finance u otro similar y completar ese dato).

Desarrollamos una aplicación que fuera capaz de consultar esa información y realizar ese cálculo en forma automatizada.

No es realmente complicado hacerlo cuando se cuenta con una API bien hecha y documentada (Incluso mejor si tenemos a mano un SDK para PHP).

Lo complicado del tema fue sacar la información de bonos, para la cual no encontramos ninguna fuente pública que tuviera buena información (¿Conocés alguna?, te invito a que dejes un comentario 🙂 ), con lo cual… no quedó opción más que arremangarse y hacer algo de web scrapping (Todo sea por ahorrarle unas horas de rastreo todos los meses a un cliente).

Así que ahí nos metimos, cURL y SimpleHTMLDom en mano, a remover la maleza y a ver qué encontrábamos.

Y la verdad… lo que encontramos no fue nada bonito. La primera misión fue entender todo el camino que un usuario humano tenía que recorrer para llegar a la información que nosotros queríamos obtener.

Una vez que tuvimos esa información, nuestro primer intento fue apuntarle a la última URL con un simple GET y escarbar el resultado… no señor, ¿tan fácil iba a ser el tema?

Lo primero que notamos era que la URL final tenía poco en común con la inicial (y sin acceso a la base de datos que andaba por detrás… difícil hacer la conversión…). Bien, retrocedamos dos casilleros.

Nuevamente, bajemos el contenido de la primera URL y busquemos el link que necesitamos (¡Gracias S.C. Chen y compañía por ponerle sintaxis tipo jQuery al SimpleHTMLDom!).

¡Primera prueba superada! Tenemos una nueva página que está un pasito más cerca. Veámosla un poco más de cerca… ¡ahá! ¡Se trata de un formulario que va por POST! Ningún problema, nuestro amigo FireBug nos mostrará el camino. Ah, pero esto es muy simple… una pequeña llamada Ajax y voilà.

Otra vez… ¡no tan rápido! Faltan los parámetros invisibles que se generan del lado del servidor… jejeje (Léase con risa de programador malicioso). Ok, volvamos a revisar ese HTML. Bien, acá están esos input hidden, no hay problema, los agregamos y listo.

¿Cómo que 404? ¡Si estoy viendo la información! ¿qué te pasa cURL?

¿Cómo? ¿Que el valor de un campo no es un literal si no una expresión?… qué ganas de complicarle la vida al prójimo… bueno… usemos el eval de php. Esta parte sí te la puedo mostrar:

foreach ( $dom->find('.ajax-token') as $token ) {
  if ( $token->attr['name'] == '__atcrv' ) {
    $atcrv = eval('return '.$token->attr['value'].';');
  }
}<div class="open_grepper_editor" title="Edit &amp; Save To Grepper">

Y ahora, ¿qué otra sorpresita hay por ahí? ¿La respuesta (si da 200) viene gzipeada? 0 problema: gzdecode se encarga y por fín, tenemos a mano la tablita con los precios del bono buscado para el día buscado. Muchas gracias, buenas noches.


La historia fue para poner en contexto, pasando en limpio (para generalizar un poco también):

  1. Todo lo que un navegador hace, cURL puede hacerlo también (Iba a decir, todo lo que una persona hace, pero después me vino a la mente el reCaptcha).
  2. Este mecanismo no es ni de lejos ideal. Basta con un pequeño cambio en el maquetado del sitio para que todo se rompa (Pero bueno… si no disponemos de una buena API, no creo que haya otro mucho mejor)
  3. No hay que temerle a un poco de ingeniería inversa 🙂
  4. La solapa Net de FireBug da un montón de información súper útil.

¿Me olvidé de algo importante?

mchojrin

Por mchojrin

Ayudo a desarrolladores PHP a acceder mercados y clientes más sofisticados y exigentes