Hur man skrapar en lista över ämnen från en Subreddit med Bash

Reddit erbjuder JSON-flöden för varje subreddit. Så här skapar du ett Bash-skript som laddar ner och analyserar en lista med inlägg från vilken subreddit du vill. Detta är bara en sak du kan göra med Reddits JSON-flöden.

Installerar Curl och JQ

Vi kommer att använda curl för att hämta JSON-flödet från Reddit och jq för att analysera JSON-data och extrahera de fält vi vill ha från resultaten. Installera dessa två beroenden med apt-get på Ubuntu och andra Debian-baserade Linux-distributioner. På andra Linux-distributioner, använd din distributions pakethanteringsverktyg istället.

sudo apt-get install curl jq

Hämta lite JSON-data från Reddit

Låt oss se hur dataflödet ser ut. Använd curl för att hämta de senaste inläggen från Milt intressant subreddit:

curl -s -A “reddit scraper example” https://www.reddit.com/r/MildlyInteresting.json

Notera hur alternativen som används före URL:en: -s tvingar curl att köras i tyst läge så att vi inte ser någon utdata, förutom data från Reddits servrar. Nästa alternativ och parametern som följer, -Ett ”reddit scraper example” ställer in en anpassad användaragentsträng som hjälper Reddit att identifiera tjänsten som kommer åt deras data. Reddit API-servrarna tillämpar hastighetsgränser baserat på användaragentsträngen. Om du ställer in ett anpassat värde kommer Reddit att segmentera vår frekvensgräns bort från andra uppringare och minska risken att vi får ett HTTP 429-hastighetsgränsöverskridande fel.

Utdata ska fylla upp terminalfönstret och se ut ungefär så här:

Det finns många fält i utdata, men allt vi är intresserade av är Titel, Permalänk och URL. Du kan se en uttömmande lista över typer och deras fält på Reddits API-dokumentationssida: https://github.com/reddit-archive/reddit/wiki/JSON

Extrahera data från JSON-utgången

Vi vill extrahera titel, permalänk och URL från utdata och spara dem i en tabbavgränsad fil. Vi kan använda textbearbetningsverktyg som sed och grep , men vi har ett annat verktyg till vårt förfogande som förstår JSON-datastrukturer, kallat jq . För vårt första försök, låt oss använda det för att snyggt skriva ut och färgkoda resultatet. Vi kommer att använda samma anrop som tidigare, men den här gången skickar vi utdata genom jq och instruerar den att analysera och skriva ut JSON-data.

curl -s -A “reddit scraper example” https://www.reddit.com/r/MildlyInteresting.json | jq .

Notera perioden som följer kommandot. Detta uttryck analyserar helt enkelt indata och skriver ut det som det är. Utdatan ser snyggt formaterad och färgkodad ut:

Låt oss undersöka strukturen för JSON-data som vi får tillbaka från Reddit. Rotresultatet är ett objekt som innehåller två egenskaper: typ och data. Den senare har en egenskap som kallas barn, som inkluderar en rad inlägg till denna subreddit.

Varje objekt i arrayen är ett objekt som också innehåller två fält som kallas typ och data. Egenskaperna vi vill ta tag i finns i dataobjektet. jq förväntar sig ett uttryck som kan appliceras på indata och producerar önskad utdata. Den måste beskriva innehållet i termer av deras hierarki och medlemskap i en array, samt hur data ska omvandlas. Låt oss köra hela kommandot igen med rätt uttryck:

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

Utdata visar titel, URL och permalänk var och en på sin egen rad:

Låt oss dyka in i jq-kommandot vi kallade:

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

Det finns tre uttryck i detta kommando åtskilda av två rörsymboler. Resultaten av varje uttryck överförs till nästa för ytterligare utvärdering. Det första uttrycket filtrerar bort allt utom mängden Reddit-listor. Denna utdata överförs till det andra uttrycket och tvingas in i en array. Det tredje uttrycket verkar på varje element i arrayen och extraherar tre egenskaper. Mer information om jq och dess uttryckssyntax finns i jqs officiella manual.

Att lägga ihop allt i ett manus

Låt oss lägga API-anropet och JSON-efterbehandlingen tillsammans i ett skript som kommer att generera en fil med de inlägg vi vill ha. Vi kommer att lägga till stöd för att hämta inlägg från vilken subreddit som helst, inte bara /r/MildlyInteresting.

Öppna din editor och kopiera innehållet i detta utdrag till en fil som heter scrape-reddit.sh

#!/bin/bash

if [ -z "$1" ]
  then
    echo "Please specify a 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

Detta skript kommer först att kontrollera om användaren har angett ett subreddit-namn. Om inte, avslutas den med ett felmeddelande och en returkod som inte är noll.

Därefter kommer det att lagra det första argumentet som subreddit-namnet och bygga upp ett datumstämplat filnamn där utdata kommer att sparas.

Åtgärden börjar när curl anropas med en anpassad rubrik och webbadressen till subreddit att skrapa. Utdata skickas till jq där det analyseras och reduceras till tre fält: Titel, URL och Permalänk. Dessa rader läses, en i taget, och sparas i en variabel med hjälp av läskommandot, allt inom en while-loop, som fortsätter tills det inte finns fler rader att läsa. Den sista raden i det inre medan-blocket ekar de tre fälten, avgränsade av ett tabbtecken, och skickar det sedan genom tr-kommandot så att dubbla citattecken kan tas bort. Utdata läggs sedan till en fil.

Innan vi kan köra det här skriptet måste vi se till att det har beviljats ​​körrättigheter. Använd kommandot chmod för att tillämpa dessa behörigheter på filen:

chmod u+x scrape-reddit.sh

Och slutligen, kör skriptet med ett subreddit-namn:

./scrape-reddit.sh MildlyInteresting

En utdatafil genereras i samma katalog och dess innehåll kommer att se ut ungefär så här:

Varje rad innehåller de tre fälten vi är ute efter, separerade med ett tabbtecken.

Går längre

Reddit är en guldgruva av intressant innehåll och media, och allt är lättillgängligt med dess JSON API. Nu när du har ett sätt att komma åt denna data och bearbeta resultaten kan du göra saker som:

Ta de senaste rubrikerna från /r/WorldNews och skicka dem till ditt skrivbord med hjälp av meddela-skicka
Integrera de bästa skämten från /r/DadJokes i ditt systems Message-Of-The-Day
Få dagens bästa bild från /r/aww och gör den till din skrivbordsbakgrund

Allt detta är möjligt med hjälp av den information som tillhandahålls och de verktyg du har på ditt system. Lycka till med hackandet!