Brevenotas Mas allá del scraping web, bitly como ejemplo a una herramienta CLI automática

freishner

Capo
Se incorporó
16 Noviembre 2021
Mensajes
436
Se que hay interés en saber como se hace el scraping web por acá. Así que hoy en esta noche tan fría, les voy a introducir en el arte de pasarse por la raja las limitancias de bitly.com, fabricando enlaces acortados gratis, sin pagar, sin la limitancia de la API a 100 enlaces por cuenta free, sin siquiera abrir el browser.

No voy abordar todo en primera instancia. Vamos a ir progresando y desgranando en la medida que mi precioso tiempo se digne a acompañarme.

Herramientas
  • Linux Debian/Ubuntu/Mate (en virtualbox o instalado en el equipo).
  • Chrome o Chromium (para que se ubiquen con las fotos).
  • Bloc de notas/Gedit/Notepad++/Sublime Text/Visual Studio Code/Atom/Vim/Nano/Netbeans/Visual Studio/Eclipse... cualquiera de éstos.
Objetivos

Simular el comportamiento del formulario que permite acortar un enlace anónimo gratuitamente.
1654228427243.png

Expectativas

Al final del tutorial, vamos a terminar con ésta herramienta.


Empecemos

Abramos el objetivo y presionamos F12 para abrir la herramienta de inspección de código. Vamos a realizar algunas configuraciones.

La pestaña network nos muestra todas las peticiones HTTP que realiza el sitio dentro del navegador. Así que en ella nos vamos a centrar para comprender que y cuando se hace. Además tenemos que marcar la casilla Preserve log, para que al recargar no se nos borre nada.


Lo segundo que haremos, será borrar las cookies, de ésta manera le estaremos indicando al sitio que queremos cargarlo desde 0. Ésto se hace desde la pestaña Application.


Luego recargamos el sitio. Y nos situamos de nuevo en la pestaña Network. Tendremos el histórico de peticiones realizadas, tanto a recursos, como endpoints.


Nos irémos al principio, nuestro objetivo es mirar como se carga el sitio en primera instancia, para saber que cabeceras HTTP son las que podríamos requerir en un futuro.


Ya sabemos que el sitio carga una cookie que quizá utiliza como token para validar el formulario llamada _xsrf.

Nuestro siguiente paso, es observar cómo un enlace es acortado a nivel de petición HTTP. Para ello primero tenemos que borrar las peticiones actuales en el historial.


Proseguimos a acortar "https://google.com". Cuando lo hayamos hecho, tendrémos grabada una petición de tipo xhr, abreviación de XMLHttpRequest, objeto usado en javascript para enviar peticiones asincronas. Ésta petición es la que se realiza cuando presionamos el botón shorten.


Ahora tenemos que hacer algunas presunciones. Nuestra petición quizá lleve algunas cabeceras HTTP, como el token que visualizamos en la carga inicial, y que hace de cookie. Además hay ciertas consideraciones en los mecanismos de funcionamiento, tales como que algunas cabeceras HTTP podrían no aparecer por ninguna parte, o no tengamos garantía de que nuestra petición pueda volver a repetirse con las mismas cabeceras.

Vamos a percatarnos de ésto con la funcionalidad replay del inspector de chrome/chromium. La cual nos permitirá volver a enviar la misma petición para comparar el output de ambas.


Veamos la salida del replay.


Podemos visualizar en el preview de la petición reenviada, que ha sido un éxito. Nos ha devuelto un objeto JSON donde aparece un nuevo enlace acortado. Ésto nos indica que la petición es reenviable, aun sin siquiera mirar como estan las cabeceras del request.

Revisemos dichas cabeceras en el request original.


Hay cosas interesantes que rescatar, lo que está pixelado no es importante. Lo que he marcado en rojo si lo es.
Las cabeceras sec-fetch- le indican al servidor como se maneja la protección cors para dominios cruzados.
La cabecera x-requested-with solo es usada en combinación de sec-fetch-, y forma parte de la seguridad contra ataques CSRF.
Luego tenemos lo importante, hay 2 tokens, uno en la cabecera cookie y otro como cabecera propia, que son el mismo token que se carga al principio del sitio cuando es solicitado sin cokies previas.

Repasemos las cabeceras de la segunda petición que hicimos como replay (reenvío).


Los tokens parecen ser los mismo. Ésto nos indica solo una cosa. Que la cookie no ha cambiado. Y que por lo tanto, pudiéramos ocuparla en una terminal.
Sabiendo ésto, ya podemos tirar manos de la terminal de Linux.

CTRL+ALT+T nos abrirá una terminal funcional.

Pero antes necesitamos obtener la petición en un formato reconocido por bash (la terminal). Vamos a copiar la petición como cURL desde el mismo inspector de chrome/chromium.


Como podemos apreciar, las opciones de copia, son variadas. En ésta ocasión usaremos la herramienta cURL, la cual nos permite realizar peticiones HTTP desde la terminal.

Éste es el primer gran salto que hacemos en alcanzar una herramienta cli automática para bitly.


Muchas cosas tenemos que analizar acá. Primero la petición ha sido un éxito. Nos ha devuelto un nuevo enlace acortado. Segundo, probamos que podemos externalizar dicha petición, y por lo tanto, simular las condiciones que supone su ejecución dentro del browser en una terminal. Y tercero, ya podemos modificar la url que se desea acortar que se aprecia en formato raw (url encode).

Con todas éstas incógnitas resueltas, estamos en condiciones de empezar la fabricación de nuestra herramienta automática.

Manos a la obra

Con nuestro editor favorito, vamos a crear un archivo llamado "bitly-shorter.sh".


He resaltado algunas cosas importantes, como que mantenemos el copy paste de cURL desde chrome/chromium tal cual, excepto por 1 detalle. El ${1}.
Además al principio he agregado la ruta absoluta de bash, para que podamos ejecutar directamente el archivo de texto como un archivo ejecutable de tipo programa.

Tambien hay que notar que mantenemos el token, es decir, mientras la cookie sea válida, podremos usar esta petición. Luego, seguramente tendremos un error.

${1}: éste código corresponde a un parámetro. Se listan desde 0, donde 0 es el nombre del programa ejecutado.
Como adivinarán, ejecutaremos "./bitly-shorten capa9.net", donde "capa9.net" será el parámetro 1, el que reemplazará a "google.com".

Nuestra versión de la herramienta es primitiva, no obstante funcional. Procedamos entonces a brindarle los permisos de ejecución.
Bash:
chmod +x bitly-shorter.sh

Luego ejecutamos
Bash:
bitly-shorter.sh capa9.net

Un objeto json se asoma indicándonos que nuestra cookie aun vive, y nuestro martillo de piedra cumple con su trabajo.

JSON:
{
    "status_code": 200,
    "data": {
        "archived": false,
        "tags": [],
        "created_at": "2022-06-03T04:43:08+0000",
        "deeplinks": [],
        "long_url": "https://capa9.net/",
        "references": {
            "group": ""
        },
        "custom_bitlinks": [],
        "link": "https://bit.ly/3GIH9DG",
        "id": "bit.ly/3GIH9DG"
    },
    "status_txt": "OK"
}

En la próxima entrega, veremos como nos vamos a independizar del navegador, superaremos una problemática que nos impedirá generar enlaces, y nos enfrentaremos al lenguaje de shell o de terminal, que ejecuta bash, conociendo las mas diversas herramientas que todo usuario de Linux debian medianamente adelantado debe conocer para desempeñár todo tipo de tareas con los mas curiosos propósitos.
 
Última modificación:

Tbon

Football total philosophy
Miembro del Equipo
Fundador
ADMIN
Se incorporó
20 Enero 2004
Mensajes
13.672
se va de brevenota por la relevancia del contenido 👍
 
Upvote 0

freishner

Capo
Se incorporó
16 Noviembre 2021
Mensajes
436
Mientras tanto, se aceptan todo tipo de comentarios, dudas, aportes, etc. Así vamos desgranando todo el tema de a poco.
 
Upvote 0

Batou

%安全
Se incorporó
13 Julio 2008
Mensajes
497
Buen post :D, yo tambien hago algo de scraping, pero prefiero usar python, recuerdo que cuando empece usaba php con curl xD!.

Que página es la que te ha dado más problemas?.

Saludos.
 
Upvote 0

Batou

%安全
Se incorporó
13 Julio 2008
Mensajes
497
Por si alguno quiere le interesa la versión en python

Python:
import sys
import requests

data = {"url": sys.argv[1]}
url = "https://bitly.com"
sesion = requests.session()
cookieReq = sesion.get(url)

headers = {"X-XSRFToken": cookieReq.cookies["_xsrf"], "Cookie": "_xsrf="+cookieReq.cookies["_xsrf"]}
req = sesion.post("https://bitly.com/data/anon_shorten", headers=headers, data=data)
print(req.json()["data"]["link"])

uso: python script.py https://www.capa9.net

Saludos.
 
Upvote 0

freishner

Capo
Se incorporó
16 Noviembre 2021
Mensajes
436
Por si alguno quiere le interesa la versión en python

Python:
import sys
import requests

data = {"url": sys.argv[1]}
url = "https://bitly.com"
sesion = requests.session()
cookieReq = sesion.get(url)

headers = {"X-XSRFToken": cookieReq.cookies["_xsrf"], "Cookie": "_xsrf="+cookieReq.cookies["_xsrf"]}
req = sesion.post("https://bitly.com/data/anon_shorten", headers=headers, data=data)
print(req.json()["data"]["link"])

uso: python script.py https://www.capa9.net

Saludos.
Wena, te motivaste.

Aer si luego le ponemos un poco de control de errores.
 
Upvote 0
Subir