Raspado web del lado del cliente con JavaScript usando jQuery y Regex

Cuando estaba construyendo mi primer proyecto de código abierto, codeBadges, pensé que sería fácil obtener datos de perfil de usuario de todos los principales sitios web de aprendizaje de código.

Estaba familiarizado con las llamadas a la API y las solicitudes de obtención. Pensé que podría usar jQuery para obtener los datos de varias API y usarlos.

var name = 'codemzy'; $.get('//api.github.com/users/' + name, function(response) { var followers = response.followers;});

Bueno, eso fue fácil. Pero resulta que no todos los sitios web tienen una API pública de la que puede obtener los datos que desea.

Pero el hecho de que no haya una API pública no significa que debas rendirte. Puede utilizar web scraping para capturar los datos, con solo un poco de trabajo adicional .

Veamos cómo podemos usar el web scraping del lado del cliente con JavaScript.

Por ejemplo, tomaré mi información de usuario de mi perfil público freeCodeCamp. Pero puede seguir estos pasos en cualquier página HTML pública.

El primer paso para extraer los datos es obtener el html de página completa mediante una .getsolicitud de jQuery .

var name = "codemzy";$.get('//www.freecodecamp.com/' + name, function(response) { console.log(response);});

Impresionante, todo el código fuente de la página acaba de registrarse en la consola.

Nota: Si obtiene un error en esta etapa del tipo No ‘Access-Control-Allow-Origin’ header is present on the requested resourceno te preocupes. Desplácese hacia abajo hasta la sección No permita que CORS lo detenga de esta publicación.

Eso fue fácil. Usando JavaScript y jQuery, el código anterior solicita una página de www.freecodecamp.org, como lo haría un navegador. Y freeCodeCamp responde con la página. En lugar de que un navegador ejecute el código para mostrar la página, obtenemos el código HTML.

Y eso es web scraping, extraer datos de sitios web.

Ok, la respuesta no es tan clara como los datos que obtenemos de una API.

Pero ... tenemos los datos, en alguna parte.

Una vez que tenemos el código fuente, la información que necesitamos está ahí, ¡solo tenemos que obtener los datos que necesitamos!

Podemos buscar en la respuesta para encontrar los elementos que necesitamos.

Digamos que queremos saber cuántos desafíos ha completado el usuario, a partir de la respuesta del perfil de usuario que obtuvimos.

En el momento de escribir este artículo, los desafíos completados de un campista están organizados en tablas en el perfil del usuario. Entonces, para obtener el número total de desafíos completados, podemos contar el número de filas.

Una forma es envolver toda la respuesta en un objeto jQuery, para que podamos usar métodos jQuery como .find()obtener los datos.

// number of challenges completedvar challenges = $(response).find('tbody tr').length;

Esto funciona bien: obtenemos el resultado correcto. Pero no es una buena forma de obtener el resultado que buscamos. Convertir la respuesta en un objeto jQuery realmente carga toda la página, incluyendo todos los scripts externos, fuentes y hojas de estilo de esa página… ¡Uh oh!

Necesitamos algunos bits de datos. Realmente no necesitamos que la página se cargue, y ciertamente no todos los recursos externos que vienen con ella.

Podríamos eliminar las etiquetas del script y luego ejecutar el resto de la respuesta a través de jQuery. Para hacer esto, podríamos usar Regex para buscar patrones de script en el texto y eliminarlos.

O mejor aún, ¿por qué no usar Regex para encontrar lo que estamos buscando en primer lugar?

// number of challenges completedvar challenges = response.replace(/[\s|\S]*?/g).match(//g).length;

¡Y funciona! Al usar el código Regex anterior, eliminamos las filas del encabezado de la tabla (que no contenían ningún desafío) y luego hacemos coincidir todas las filas de la tabla para contar el número de desafíos completados.

Es incluso más fácil si los datos que desea se encuentran en la respuesta en texto sin formato. En el momento de escribir este artículo, los puntos de usuario estaban en html como

[ 1498 ]

esperando ser raspado.

var points = response.match(/

\[ ([\d]*?) \]/)[1];

En el patrón Regex anterior, hacemos coincidir el elemento h1 que estamos buscando, incluido el [ ]que rodea los puntos, y agrupamos cualquier número dentro con ([\d]*?).Obtenemos una matriz, el primer [0]elemento es la coincidencia completa y el segundo [1]es nuestra coincidencia de grupo (nuestros puntos ).

Regex es útil para hacer coincidir todo tipo de patrones en cadenas, y es excelente para buscar en nuestra respuesta para obtener los datos que necesitamos.

Puede utilizar el mismo proceso de 3 pasos para extraer datos de perfil de una variedad de sitios web:

  1. Utilice JavaScript del lado del cliente
  2. Usa jQuery para raspar los datos
  3. Utilice Regex para filtrar los datos de la información relevante

Hasta que encontré un problema, CORS.

¡No permita que CORS lo detenga!

CORS o Intercambio de recursos de origen cruzado, puede ser un problema real con el web scraping del lado del cliente.

Por razones de seguridad, los navegadores restringen las solicitudes HTTP de origen cruzado iniciadas desde dentro de los scripts. Y debido a que estamos usando Javascript del lado del cliente en el front-end para web scraping, pueden ocurrir errores CORS.

Aquí hay un ejemplo que intenta extraer datos de perfil de CodeWars ...

var name = "codemzy";$.get('//www.codewars.com/users/' + name, function(response) { console.log(response);});

En el momento de escribir este artículo, ejecutar el código anterior le da un error relacionado con CORS.

Si no hay un Access-Control-Allow-Originencabezado del lugar que está raspando, puede tener problemas.

The bad news is, you need to run these sorts of requests server-side to get around this issue.

Whaaaaaaaat, this is supposed to be client-side web scraping?!

The good news is, thanks to lots of other wonderful developers that have run into the same issues, you don’t have to touch the back end yourself.

Staying firmly within our front end script, we can use cross-domain tools such as Any Origin, Whatever Origin, All Origins, crossorigin and probably a lot more. I have found that you often need to test a few of these to find the one that will work on the site you are trying to scrape.

Back to our CodeWars example, we can send our request via a cross-domain tool to bypass the CORS issue.

var name = "codemzy";var url = "//anyorigin.com/go?url=" + encodeURIComponent("//www.codewars.com/users/") + name + "&callback=?";$.get(url, function(response) { console.log(response);});

And just like magic, we have our response.