d20pfsrd Discord Bot Scraper Abstraktion und Bereitstellung

Aug 16 2020

Ich habe einen Discord-Bot geschrieben, der im Discord-Chat nach Links zum d20pfsrd-Regelbuch lauscht, prüft, ob es sich um Kunststücke oder Magie handelt, und dann die Seite kratzt, formatiert und als formatierten Text in den Chat zurückspuckt. Die Seiten, die ich überprüfe, sind formelhaft genug. Obwohl die von mir verwendeten Cheerio-Selektoren wahrscheinlich ziemlich spröde sind, scheint es in den meisten Fällen zu funktionieren. Die Textformatierer sind jedoch einige hässliche Bestien (obwohl die Logik wahrscheinlich einzigartig ist), und die Axios-Aufrufe könnten auch etwas Aufräumarbeiten gebrauchen.

Mein Problem ist wie folgt: Ich vermutete, dass gut 40 % des Codes umgestaltet werden können, wenn ich ihn richtig verallgemeinere. Meine Lösung bestand darin, etwas zu tun, das man wahrscheinlich als Missbrauch des Spread-Operators bezeichnen könnte:

async function getPage(msg, url){
  let message = "placeholder";
  await axios.get(url).then( (response) => {
      message = responder(...selectResponder(url), response);
    } 
    ).catch((error) => {
      console.error(error.message);
    });
  sendMessage(message, msg);
  
}

Eine Woche später wird mir jetzt klar, dass ich die Funktionen so geschrieben habe, dass sie rückwärts gelesen werden? Abgesehen von der Ästhetik, so funktioniert es am Ende:

function selectResponder(siteUrl){
  if (siteUrl.startsWith("https://www.d20pfsrd.com/feats/")){
      return feats.featsConfig;
    } else if (siteUrl.startsWith("https://www.d20pfsrd.com/magic/")){
      return magic.magicConfig;
  }
}

function responder(parser, formatter, messageFormatter, response){
    const replyData = parser(response.data);
    const formattedData = formatter(replyData);
    return messageFormatter(formattedData);
}

Die Idee ist, dass so viel einzigartige Logik wie möglich in magic.js und feats.js vorhanden ist. Wie kann ich diesen Abschnitt bereinigen? Das Github-Repo ist hier und ich würde mich über Feedback zum gesamten Projekt freuen. Ich habe das meiste gemacht, weil ich es für seltsam hielt, hier einen großen if-Block zu haben und die Axios-Aufrufe zu duplizieren:

client.on('message', msg => {
  

  if(validateUrl(msg.content)){
    const siteUrl = encodeURI(msg.content);
    getPage(msg, siteUrl);
  }
  

});

Außerdem habe ich diesen Kern aufgeschrieben , wie ich es auf einem Himbeer-Pi bereitgestellt habe. Das funktioniert, daher wären Verbesserungsvorschläge sehr willkommen

In groben Zügen dieses Programm:

  1. Lauscht auf eine Nachricht
  2. Validiert die Nachricht
  3. Ruft den Seiteninhalt an der Nachrichten-URL ab
  4. Analysiert den Seiteninhalt
  5. Formatiert den Seiteninhalt neu
  6. Konvertiert den Seiteninhalt in eine Nachricht
  7. Sendet die Nachricht

Antworten

1 TedBrownlow Aug 16 2020 at 10:57

So würde ich es machen. Verschieben Sie die Logik darüber, welche Seiten ein Parser verarbeitet, in den Code für diesen Parser. Auch das Organisieren Ihrer Hilfsdateien in Objekten könnte die Komplexität in Bezug auf die Anzahl der Variablen, die Sie weitergeben, reduzieren, aber das ist eher eine Frage der persönlichen Vorlieben.

class SpecificPageParser {
    match(url) {
        return (
           url.startswith('https://www.d20pfsrd.com/magic/') &&
           !url.endsWith('/magic/')
        );
    }
    format(response) {
        // do your parsing stuff
        const formatted = {...response,'extra':'info'};
        return formatted;
    }
}

const responders = [new SpecificPageParser(),new SomeOtherParser()];

async function getPage(msg, url){
    try {
        const responder = responders.find(responder=>responder.match(url));
        if (!responder) return;
        const response = await axios.get(url);
        const message = responder.format(response);
        sendMessage(message, msg);
    }
    catch(error) {
        console.error(error);
    }
  }
```