Comunidad de diseño web y desarrollo en internet online

Capturar datos de sitios web externos con PHP

Muchas veces necesitamos alimentar nuestros programas con una ingente cantidad de datos, y es posible que ello requiera un costoso trabajo manual y una estúpida y enorme pérdida de tiempo. También es posible que sabiendo dónde buscar (o a quién preguntar) encontremos esa información disponible en Internet. Muchos de los contenidos de Internet pueden leerse de manera fácil, mediante webservices que ofrece el propio sitio (como los feed rss) sin embargo, puede que la información que nos interesa sólo sea visible desde el código html de la propia web. Si necesitamos sacar mucha información, o muchas veces, tampoco nos servirá hacerlo manualmente, y por tanto podemos utilizar un script en php, que sólo coja la información que necesitamos filtrándola mediante expresiones regulares.

Pongamos que queremos mostrar un array con los nicks de los últimos usuarios que postearon en cada uno de los foros de Cristalab (Que se encuentran al lado derecho del nombre de los foros). Lo primero que debemos hacer es analizar con detenimiento el código html de los foros y aislar la estructura que buscamos (Fijense en el texto en rojo):

 <td class="row1" width="470"><span class="forumlink"><a
  href="viewforum.php?f=3&amp;sid=ad53bb1802154d60f74d42e240698e47">Aportes</a></span><br
  />

<span class="genmed subdatos">Sugerencias, y colaboraciones. Si quieres apoyar a la web con algún tipo de material, etc.</span><br />
<span class="genmed"><span class="infoTutos">Moderadores:</span> <a href="profile.php?mode=viewprofile&amp;u=248&amp;sid=ad53bb1802154d60f74d42e240698e47">La100rra</a>, <a href="profile.php?mode=viewprofile&amp;u=1225&amp;sid=ad53bb1802154d60f74d42e240698e47">danielsemper</a></span></td>
<td class="row2" align="center" valign="middle" height="50"><span class="genmed subdatos">494</span></td>
<td class="row1" align="center" valign="middle" height="50"><span class="genmed subdatos">2532</span></td>
<td class="row2" align="center" valign="middle" height="50" nowrap="nowrap"><span class="genmed subdatos">Vie Ene 19, 2007 5:15 pm<br /><a href="profile.php?mode=viewprofile&amp;u=18064&amp;sid=ad53bb1802154d60f74d42e240698e47">sfa</a> <a href="viewtopic.php?p=234900&amp;sid=ad53bb1802154d60f74d42e240698e47#234900"><img src="templates/smartBlue/images/icon_latest_reply.gif" border="0" alt="Ver último mensaje" title="Ver último mensaje" /></a></span> </td>

</tr>
<tr>
<td class="row1" align="center" valign="middle" height="50"><img src="templates/smartBlue/images/folder_big.gif" alt="No hay mensajes nuevos" title="No hay mensajes nuevos" /></td>
<td class="row1" width="470"><span class="forumlink"><a href="viewforum.php?f=16&amp;sid=ad53bb1802154d60f74d42e240698e47">Weblog</a></span><br />
<span class="genmed subdatos">El mismo weblog del home, vinculado al foro para poner comentarios</span><br />
<span class="genmed"><span class="infoTutos">Moderadores:</span> <a href="profile.php?mode=viewprofile&amp;u=248&amp;sid=ad53bb1802154d60f74d42e240698e47">La100rra</a>, <a href="profile.php?mode=viewprofile&amp;u=250&amp;sid=ad53bb1802154d60f74d42e240698e47">Elecash</a>, <a href="profile.php?mode=viewprofile&amp;u=1225&amp;sid=ad53bb1802154d60f74d42e240698e47">danielsemper</a>, <a href="profile.php?mode=viewprofile&amp;u=2645&amp;sid=ad53bb1802154d60f74d42e240698e47">Maikel</a></span></td>

<td class="row2" align="center" valign="middle" height="50"><span class="genmed subdatos">373</span></td>
<td class="row1" align="center" valign="middle" height="50"><span class="genmed subdatos">14145</span></td>
<td class="row2" align="center" valign="middle" height="50" nowrap="nowrap"><span class="genmed subdatos">Sab Ene 20, 2007 10:07 pm<br />Ardilla Roja_blog <a href="viewtopic.php?p=235369&amp;sid=ad53bb1802154d60f74d42e240698e47#235369"><img src="templates/smartBlue/images/icon_latest_reply.gif" border="0" alt="Ver último mensaje" title="Ver último mensaje" /></a></span> </td>

Este código corresponde a los foros de Weblog y Aportes. Vemos que las estructuras son distintas si el último usuario está registrado (en este caso hay un link hacia su perfil) o no. De todas formas, tienen en común que van detrás de un salto de línea (etiqueta </ br>) y delante de la imagen de "Mostrar último mensaje" (todo esto, texto en verde), con lo que los usuarios (texto en rojo) quedan suficientemente acotados.

Ahora ya sabemos como tendrá que ser nuestra expresión regular, así que manos a la obra:

Lo primero que hacemos es decir php que lea el html del foro de clab:

<?php
$contenido=file_get_contents('http://www.cristalab.com/foros');

Ahora tenemos que formar nuestra expresión regular. Usaremos varios subpatrones (que son trozos de una expresión regular que van entre paréntesis), y a todos salvo al que nos interesa les pondremos el modificador ?:, que significa que serán evaluados para ver si la cadena coincide, pero no serán tenidos en cuenta para listar las coincidencias de subpatrones. También hay que saber que el punto (.) significa cualquier carácter salvo saltos de línea (a no ser que se indique con un modificador s) y la barra (/) sirve para marcar las expresiones regulares. Por tanto si los queremos con significado de carácter, tendremos que escaparlos, anteponiendoles la contrabarra (\), al igual que el carácter de espacio, si queremos que tenga significado. Esto pueden hacerlo con el comando buscar/reemplazar de su editor favorito. Ahora queda decir que el carácter interrogación (?) después de un carácter o subpatrón sirve para decir que ese elemento se repite 1 o ninguna veces, asterisco (*) que se repite 0 o más veces y suma (+) que se repite 1 o más veces.

Ahora ya podemos escribir la expresión:

$regexp = '/(?:<br \/>)(?:<a href="profile\.php.*>)?(.+)(?:<\/a>)?(?:\ <a href="viewtopic\.php.*"><img src="templates\/smartBlue\/images\/icon_latest_reply\.gif")/';

Aquí tenemos 5 subpatrones:

  1. Siempre empieza por un salto de línea.(?:<br \/>)
  2. Puede seguir con el link hacia algún perfil, como no sabemos cual, ponemos .* después de profile.php, y como es una posiblidad, lleva ? al final. (?:<a href="profile\.php.*>)?
  3. Ahora va el nombre que interesa y por tanto no lleva :?, con seguridad más de un carácter. (.+)
  4. Puede que se cierre la etiqueta del link. (?:<\/a>)?
  5. Seguro que acaba con la imagen. (?:\ <a href="viewtopic\.php.*"><img src="templates\/smartBlue\/images\/icon_latest_reply\.gif")

Ahora usamos la función preg_match_all para que todas las coincidencias con ese patrón del html del foro se metan en el array $matches. El índice 0 del array será el array de las coincidencias con todo el patrón, y los siguientes índices serán las coincidencias con cada subpatrón que no lleve :?. Nosotros tenemos un subpatrón que será el índice 1. Y ese será el que dibujemos:

preg_match_all($regexp,$contenido,$matches);
print_r($matches[1]);
?>

¿Sabes SQL? ¿No-SQL? Aprende MySQL, PostgreSQL, MongoDB, Redis y más con el Curso Profesional de Bases de Datos que empieza el martes, en vivo.

Descargar Archivo

Publica tu comentario

El autor de este artículo ha cerrado los comentarios. Si tienes preguntas o comentarios, puedes hacerlos en el foro

Entra al foro y participa en la discusión

o puedes...

¿Estás registrado en Cristalab y quieres
publicar tu URL y avatar?

¿No estás registrado aún pero quieres hacerlo antes de publicar tu comentario?

Registrate