Raspar dados do Reddit: Tutorial completo com Bash e jq

O Reddit disponibiliza feeds JSON para cada subreddit. Este artigo demonstra como criar um script Bash para descarregar e analisar uma listagem de publicações de qualquer subreddit. Esta é apenas uma das muitas possibilidades ao utilizar os feeds JSON do Reddit.

Instalação do Curl e JQ

Utilizaremos o curl para obter o feed JSON do Reddit e o jq para processar os dados JSON e extrair os campos desejados dos resultados. Estas duas ferramentas podem ser instaladas com o apt-get no Ubuntu e outras distribuições Linux baseadas em Debian. Em outras distribuições, use o gestor de pacotes da sua preferência.

sudo apt-get install curl jq

Obtenção de Dados JSON do Reddit

Vamos analisar a estrutura do feed de dados. Para isso, use o comando curl para obter as publicações mais recentes do subreddit r/MildlyInteresting:

curl -s -A “exemplo de raspagem do reddit” https://www.reddit.com/r/MildlyInteresting.json

As opções utilizadas antes do URL são as seguintes: `-s` força o curl a operar em modo silencioso, de forma a evitar a apresentação de qualquer output que não sejam os dados dos servidores do Reddit. A opção seguinte, `-A “exemplo de raspagem do reddit”`, define uma string de agente de utilizador personalizada que ajuda o Reddit a identificar o serviço que está a aceder aos seus dados. Os servidores da API do Reddit aplicam limites de taxa com base na string do agente de utilizador. A definição de um valor personalizado permite ao Reddit isolar o nosso limite de taxa dos de outros utilizadores e diminuir a probabilidade de recebermos um erro HTTP 429 (Limite de taxa excedido).

A saída deverá preencher a janela do terminal e apresentar-se semelhante a:

Os dados de output contêm muitos campos, no entanto, iremos focar-nos no Título, Link Permanente e URL. Pode consultar a lista completa de tipos e campos na página de documentação da API do Reddit: https://github.com/reddit-archive/reddit/wiki/JSON

Extração de Dados do Output JSON

O objetivo é extrair o Título, Link Permanente e URL do output, guardando-os num ficheiro delimitado por tabulações. Apesar de podermos utilizar ferramentas como sed e grep, vamos optar pela utilização do jq, uma ferramenta que entende estruturas de dados JSON. Inicialmente, vamos utilizá-la para apresentar e colorir o output. Para isso, repetiremos o comando anterior, mas desta vez, direcionando o output através do jq, de modo a que este processe e apresente os dados JSON.

curl -s -A “exemplo de raspagem do reddit” https://www.reddit.com/r/MildlyInteresting.json | jq .

O ponto (`.`) após o comando serve para processar o input e apresentar o mesmo inalterado. A apresentação do output surge bem formatada e colorida:

Vamos analisar a estrutura dos dados JSON recebidos do Reddit. O resultado root é um objeto que contém duas propriedades: `kind` e `data`. A propriedade `data` contém outra propriedade chamada `children`, que inclui um array de publicações para este subreddit.

Cada elemento do array é um objeto que contém dois campos chamados `kind` e `data`. As propriedades que pretendemos obter encontram-se no objeto `data`. O jq requer uma expressão que pode ser aplicada aos dados de entrada e que produz o output desejado. Esta expressão deverá descrever o conteúdo em termos da sua hierarquia e associação a um array, bem como a forma como os dados devem ser transformados. Vamos executar novamente o mesmo comando, desta vez com a expressão correta:

curl -s -A “exemplo de raspagem do reddit” https://www.reddit.com/r/MildlyInteresting.json | jq ‘.data.children | .[] | .data.title, .data.url, .data.permalink’

O output apresenta o Título, URL e Link Permanente, cada um numa linha própria:

Vamos analisar o comando jq executado:

jq ‘.data.children | .[] | .data.title, .data.url, .data.permalink’

Este comando contém três expressões, separadas por dois símbolos de pipe. O resultado de cada expressão é passado para a expressão seguinte, para posterior processamento. A primeira expressão filtra tudo, com exceção do array de listagens do Reddit. Este output é passado para a segunda expressão e transformado num array. A terceira expressão atua em cada elemento do array e extrai três propriedades. Para mais informações sobre o jq e a sua sintaxe, consulte o manual oficial do jq.

Reunindo Tudo num Script

Vamos reunir a chamada API e o pós-processamento JSON num script que irá gerar um ficheiro com as publicações desejadas. Adicionaremos suporte para obter publicações de qualquer subreddit, e não apenas do r/MildlyInteresting.

Abra o seu editor de texto e copie o conteúdo do trecho seguinte num ficheiro chamado `scrape-reddit.sh`:

#!/bin/bash
if [ -z "$1" ]
  then
    echo "Por favor, especifique um subreddit"
    exit 1
fi

SUBREDDIT=$1
NOW=$(date +"%m_%d_%y-%H_%M")
OUTPUT_FILE="${SUBREDDIT}_${NOW}.txt"

curl -s -A "bash-scrape-topics" https://www.reddit.com/r/${SUBREDDIT}.json |
        jq '.data.children | .[] | .data.title, .data.url, .data.permalink' |
        while read -r TITLE; do
                read -r URL
                read -r PERMALINK
                echo -e "${TITLE}t${URL}t${PERMALINK}" | tr --delete "\"" >> ${OUTPUT_FILE}
        done

Este script irá primeiro verificar se o utilizador forneceu um nome de subreddit. Caso contrário, termina a execução apresentando uma mensagem de erro e um código de retorno diferente de zero.

Em seguida, o script irá armazenar o primeiro argumento como nome do subreddit e criar um nome de ficheiro com um carimbo de data, onde o output será guardado.

O processo inicia-se quando o curl é invocado com um cabeçalho customizado e o URL do subreddit a processar. O output é passado para o jq, onde é processado e reduzido a três campos: Título, URL e Link Permanente. Estas linhas são lidas, uma de cada vez, e guardadas numa variável, utilizando o comando read, dentro de um loop while, que se mantém ativo enquanto houver mais linhas para ler. A última linha do bloco while interno ecoa os três campos, separados por um caractere de tabulação e encaminha para o comando tr, de modo a remover as aspas duplas. O output é posteriormente anexado ao ficheiro.

Antes de executarmos este script, devemos garantir que o mesmo tem permissões de execução. Utilize o comando `chmod` para aplicar estas permissões ao ficheiro:

chmod u+x scrape-reddit.sh

Por fim, execute o script com um nome de subreddit:

./scrape-reddit.sh MildlyInteresting

Será gerado um ficheiro de output na mesma pasta, cujo conteúdo será semelhante a:

Cada linha contém os três campos procurados, separados por um caractere de tabulação.

Indo Além

O Reddit é um verdadeiro tesouro de conteúdo e media interessantes, e tudo está facilmente acessível utilizando a sua API JSON. Agora que já tem uma forma de aceder a estes dados e processar os resultados, pode:

  • Obter as últimas manchetes do r/WorldNews e enviá-las para o seu desktop utilizando o notify-send.
  • Integrar as melhores piadas do r/DadJokes na mensagem do dia do seu sistema.
  • Obter a melhor imagem do dia do r/aww e defini-la como o papel de parede do seu desktop.

Tudo isto é possível utilizando os dados disponíveis e as ferramentas que tem à sua disposição. Boa exploração!