Abstração e implantação do Discord Bot Scraper d20pfsrd

Aug 16 2020

Eu escrevi um bot de discórdia que escuta links para o livro de regras d20pfsrd no chat de discórdia, verifica se são talentos ou magia e, em seguida, raspa a página, formata-a e a coloca de volta no chat como texto formatado. As páginas que estou verificando são estereotipadas o suficiente, portanto, embora os seletores cheerio que estou usando sejam provavelmente bastante frágeis, parece funcionar na maioria dos casos. Os formatadores de texto são bestas feias (embora a lógica seja provavelmente única), e as chamadas axios também precisam de alguma limpeza.

Meu problema é o seguinte: suspeitei que uns bons 40% do código podem ser refatorados se eu generalizá-lo adequadamente. Minha solução foi fazer algo que provavelmente poderia ser descrito como um abuso do operador de spread:

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);
  
}

Uma semana depois, agora estou percebendo que escrevi as funções de uma maneira que as faz ler de trás para frente? Deixando de lado a estética, acaba ficando assim:

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);
}

A ideia é que o máximo possível de lógica única que eu possa separar existe em magic.js e feats.js. Como posso limpar esta seção? O repositório do github está aqui e eu adoraria receber um feedback sobre todo o projeto. Fiz a maior parte disso porque achei estranho ter um grande bloco if aqui e duplicar as chamadas axios:

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

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

});

Também escrevi esta essência sobre como o implantei em um raspberry pi. Isso funciona, então sugestões sobre como melhorá-lo seriam muito apreciadas

Em linhas gerais, este programa:

  1. Escuta uma mensagem
  2. Valida a mensagem
  3. Obtém o conteúdo da página no URL da mensagem
  4. Analisa o conteúdo da página
  5. Reformata o conteúdo da página
  6. Converte o conteúdo da página em uma mensagem
  7. Envia a mensagem

Respostas

1 TedBrownlow Aug 16 2020 at 10:57

Aqui está como eu faria isso. Mova a lógica sobre quais páginas um analisador consome no código do referido analisador. Além disso, organizar seus arquivos auxiliares em objetos pode reduzir a complexidade em termos do número de variáveis ​​que você passa, mas isso é mais uma questão de preferência pessoal.

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);
    }
  }
```