Minet es una herramienta de minado de datos que nos permite obtener y extraer datos de una gran variedad de fuentes: Facebook, CrowdTangle, YouTube, Twitter, Media Cloud etc. Esto nos ayudó a automatizar el proceso de recabado de información con el que construimos nuestro dataset. Esta herramienta se usa por medio de la línea de comandos, así que optamos por crear un script en python que nos facilitara el proceso.
Este script simplemente ejecuta el comando que Minet utiliza para recabar información de hashtags de Twitter, el script lo ejecuta iterativamente utilizando una lista que nosotros le proporcionamos en formato .csv de una columna:
#day
#happy
#sunshine
Es necesario instalar algunas librerías para poder usar el script correctamente:
pip install pandas
pip install minet
Explicación del código
En esta parte del código simplemente importamos las librerías a utilizar.
import pandas as pd
import numpy as np
import os
import argparse
Aquí se analiza y separa los argumentos que se le pasaron al script. Esto para poder modificar los outputs del código sin tener que modificar el código en sí.
parser = argparse.ArgumentParser(description=’Scrap minet!’)
parser.add_argument(‘-c’, ‘–csv’, type=str, help=’Csv to use for scraping’)
parser.add_argument(‘-d’, ‘–dir’, type=str, help=’Directory name to use for saving the results’)
parser.add_argument(‘-l’, ‘–limit’, type=str, help=’Max quantity of tweets for each query’)
args = parser.parse_args()
Este if verifica que todos los argumentos hayan sido dados, de lo contrario muestra un mensaje de error en consola.
if args.csv is not None and args.dir is not None and args.limit is not None:
«»»Main code»»»
else:
print(«One or more args are missing»)
Esta parte perteneciente al if, guarda las rutas de archivo que necesita el script para obtener y guardar información.
os.chdir(«..»)
working_directory = os.getcwd()
results_dir = working_directory + «/results»
codes_dir = working_directory + «/codes»
resources_dir = working_directory + «/resources»
csv_path = os.path.join(resources_dir, args.csv)
Aquí simplemente leemos la información escrita en el archivo .csv y nos posicionamos en la carpeta de resultados
df_hashtags = pd.read_csv(csv_path, header=None)
os.chdir(path = results_dir)
En el if verificamos que el directorio de resultados exista, de lo contrario lo crea. Posteriormente guardamos una última ruta de archivo que nos indique el directorio de la carpeta en la que se ingresarán los resultados. Finalmente nos posicionamos en ese directorio para empezar a descargar la información.
if not os.path.exists(args.dir):
os.makedirs(args.dir)
wdif = results_dir + «/» + args.dir
os.chdir(path=wdif)
El for es el que hace la magia. Simplemente ejecuta iterativamente el comando de scraping y descarga de imágenes de Minet. Guarda en dos archivos .csv el scraping y en una carpeta las imágenes, ambos con el mismo nombre del hashtag. Esto lo hace por cada una de las filas del archivo .csv. Por último, se posiciona en el directorio inicial.
for hashtag in df_hashtags.loc[:].values[:]:
os.system(‘minet twitter scrape tweets \»‘ + hashtag[0] + ‘ filter:images\» –limit ‘ + args.limit + ‘ > tw_’ + hashtag[0][1:] + ‘.csv’)
os.system(‘minet fetch media_urls tw_’ + hashtag[0][1:] + ‘.csv –separator \»|\» -d images –throttle 0 –domain-parallelism 5 > rep_’ + hashtag[0][1:] + ‘.csv’)
os.chdir(path=codes_dir)
Para poder correr el programa, se debe hacer lo siguiente:
- Abrimos una terminal
- Creamos en shared_volume las carpetas codes, results y resources ejecutando:
mkdir -p /shared_volume/nanook-2021-cdas-project/text_analysis/codes/
mkdir -p /shared_volume/nanook-2021-cdas-project/text_analysis/results/
mkdir -p /shared_volume/nanook-2021-cdas-project/text_analysis/resources/
- Añadimos en la carpeta resources el archivo hashtags.csv con los hashtags a los que se les vamos a hacer scrapping. Los hashtags deben estar separados con un enter entre ellos y debe llevar el simbolo de hashtag o numeral (#). Ej.
#ClimateChangeIsReal
#climateaction
#EarthDay
#globalwarming
#FridaysForFuture
#ClimateChange
- Nos ubicamos en la carpeta codes ejecutando:
cd shared_volume/nanook-2021-cdas-project/text_analysis/codes/
- En la carpeta codes debemos descargar el script de bash append.sh
- Ejecutamos el comando:
python3 minet_scrap.py -c hashtags.csv -d tweets -l 500
- -c nos indica el documento de donde vamos a sacar los hashtags
- -d como vamos a nombrar a la carpeta donde guardamos los resultados
- -l la cantidad de tweets a scrapear por hashtag
Nota: el cambiar los argumentos de los parámetros -c y -d puede afectar el funcionamiento del resto de los scripts. El parámetro -l no tiene problemas con ser alterado, solo recuerda que los tweets contienen imagenes y una gran cantidad de ellos, ocupa una gran cantidad de memoria
- Ejecutamos el script append.sh con el comando:
bash append.sh
- Tendremos nuestros resultados en la carpeta
/shared_volume/nanook-2021-cdas-project/text_analysis/results/tweets/
Los resultados del programa anterior son de la siguiente manera.
Esta carpeta (tweets) contendrá un archivo .csv para el reporte del hashtag y otro para relacionar las imagenes con los hashtag. Si utilizaste el script append.sh, también tendrás dos archivos extras que contengan la información de todos los demás:
Por último, en la carpeta images se encontrarán todas las imágenes descargadas. Cada una tendrá de nombre un identificador con el que se podrá relacionar en su respectivo archivo .csv:
CrowdTangle
CrowdTangle es una herramienta de facebook que nos facilita el scrapping de publicaciones en redes sociales con sus respectivos multimedia. Para facilitar la descarga de imágenes se creó un script de python que nos permite descargar todas las imágenes de las publicaciones que contiene un archivo .csv. Este archivo proviene de la plataforma (https://www.crowdtangle.com/), por lo que debemos crear una cuenta y una lista de publicaciones para poder descargarlas en formato .csv.
Nota: Este archivo tiene un formato muy específico. Si no proviene de la plataforma de CrowdTangle es altamente probable que no funcione.
Explicación del código
En esta parte del código simplemente importamos las librerías a utilizar
import pandas as pd
import numpy as np
import requests
from urllib.request import urlopen
from shutil import copyfileobj
from pathlib import Path
import argparse
import os
Aquí se analiza y separa los argumentos que se le pasaron al script para poder modificar los outputs del código sin tener que modificar el código en sí, esto nos permite tener un código más flexible.
parser = argparse.ArgumentParser(description=’CrowdTangle image downloader’)
parser.add_argument(‘-c’, ‘–csv’, type=str, help=’Csv to use’)
parser.add_argument(‘-a’, ‘–api_key’, type=str, help=’CrowdTangle API key’)
args = parser.parse_args()
Esta parte perteneciente al if guarda las rutas de archivo que necesita el script para obtener y guardar información.
df_directory = os.getcwd()
os.chdir(«..»)
working_directory = os.getcwd()
working_directory += «/CrowdTangle_Results»
Aquí simplemente leemos la información escrita en el archivo .csv, guardamos el API key en una variable junto con el url base a consultar. También inicializamos las variables page_id y post_id que nos indicará la publicación específica de la cual descargaremos las imagenes.
df = pd.read_csv(df_directory + «/» + args.csv)
token = args.api_key
ct_base_url = «https://api.crowdtangle.com/post/»
page_id = «»
post_id = «»
Ahora desmenucemos el siguiente for:
for index, row in df.iterrows():
page_id = row[«Facebook Id»]
post_id = row[«URL»].split(«/»)[-1]
ct_url = ct_base_url + str(page_id) + «_» + post_id
r = requests.get(ct_url, params={‘token’: token})
r = r.json()
try:
media = r[«result»][«posts»][0][«media»]
for image in media:
path = working_directory+»/ct_imgs/»+str(page_id) + «_» + post_id+»/»
p = Path(path)
p.mkdir(parents=True, exist_ok=True)
image_identifier = image[«url»].split(«?»)[0].split(«/»)[-1]
try:
with urlopen(image[«url»]) as in_stream, open((path + image_identifier), ‘wb’) as out_file:
copyfileobj(in_stream, out_file)
except urllib.error.HTTPError as e:
print(e)
except:
print(«Something else failed»)
except:
print(«Error in the result: » + str(r))
Primero obtenemos el page_id y post_id. Posteriormente daremos formato a nuestro endpoint de consulta con dichas variables.
page_id = row[«Facebook Id»]
post_id = row[«URL»].split(«/»)[-1]
ct_url = ct_base_url + str(page_id) + «_» + post_id
Hacemos la consulta y la guardamos en un diccionario.
r = requests.get(ct_url, params={‘token’: token})
r = r.json()
Utilizamos un try-catch para poder verificar que el resultado de la consulta fuera exitoso, pues de caso contrario al intentar acceder al atributo result del objeto r nos daría un error.
try:
media = r[«result»][«posts»][0][«media»]
for image in media:
path = working_directory+»/ct_imgs/»+str(page_id) + «_» + post_id+»/»
p = Path(path)
p.mkdir(parents=True, exist_ok=True)
image_identifier = image[«url»].split(«?»)[0].split(«/»)[-1]
try:
with urlopen(image[«url»]) as in_stream, open((path + image_identifier), ‘wb’) as out_file:
copyfileobj(in_stream, out_file)
except urllib.error.HTTPError as e:
print(e)
except:
print(«Something else failed»)
except:
print(«Error in the result: » + str(r))
Este for itera entre todas las imagenes de la publicación y las descarga, veamos que es lo que hace detenidamente.
for image in media:
path = working_directory+»/ct_imgs/»+str(page_id) + «_» + post_id+»/»
p = Path(path)
p.mkdir(parents=True, exist_ok=True)
image_identifier = image[«url»].split(«?»)[0].split(«/»)[-1]
try:
with urlopen(image[«url»]) as in_stream, open((path + image_identifier), ‘wb’) as out_file:
copyfileobj(in_stream, out_file)
except urllib.error.HTTPError as e:
print(e)
except:
print(«Something else failed»)
En esta parte establecemos el path en el que se guardaran las imagenes de esta publicación en específico. Con ayuda de la clase Path validaremos si la carpeta existe, de lo contrario se creará. Por último obtendremos el nombre y el tipo de archivo del identificador de la imagen.
path = working_directory+»/ct_imgs/»+str(page_id) + «_» + post_id+»/»
p = Path(path)
p.mkdir(parents=True, exist_ok=True)
image_identifier = image[«url»].split(«?»)[0].split(«/»)[-1]
Finalmente, descargamos el archivo de la url en la que esta guardada la imagen y copiamos los bytes en un archivo de la pc con su mismo nombre (en la dirección de la respectiva carpeta creada). De surgir un error sería resuelto en el try-catch y lo imprimiría en consola, sin detener o alterar el flujo dentro del programa.
try:
with urlopen(image[«url»]) as in_stream, open((path + image_identifier), ‘wb’) as out_file:
copyfileobj(in_stream, out_file)
except urllib.error.HTTPError as e:
print(e)
except:
print(«Something else failed»)
Nota 1: La cantidad de descargas esta sujeta a la cantidad permitida por tu API key (por publicación)
Nota 2: Lamentablemente CrowdTangle esta teniendo algunos problemas en su servicio. Por esto, posiblemente no se descarguen correctamente las imágenes. De ser el caso recomendamos consultar con el soporte técnico de la plataforma.
Una vez tengamos este archivo .csv que contenga la lista de las publicaciones que queremos scrapear de facebook. Debemos ponerlo en el mismo directorio que el script.
Ahora debemos instalar algunas librerías necesarias para utilizar el código. Los siguientes pasos asumen que ya se tiene instalado python en el sistema. De lo contrario, se deberá visitar https://www.python.org/downloads/ y descargar la versión más reciente (estable).
- Instalamos las siguientes librerías:
pip install pandas requests urllib3
Nota: Si estas trabajando con python 3.3 o anteriores, añade esta librería extra:
pip install pathlib
- Solicitamos una API key en la plataforma de CrowdTangle.
- Ejecutamos el script download_images_crowdtangle.py de la siguiente forma:
python download_images_crowdtangle.py -c <nombre del archivo .csv> -a <API key de CrowdTangle>
Nota: Los delimitadores del comando pueden ser -c o –csv y -a o –api_key.