i, r0b0t - r3dd1t
decodeHex('3020697320707674')
Fazer scrap e prints do post e comentários do Reddit
Por muito tempo eu usei a biblioteca Cheerio para fazer scrap no node. Porém nesse projeto eu resolvi usar o Puppeteer, já que ele é capaz de abrir um Chromium com a URL que você configurar e a partir disso você pode programar ações reais na tela do navegador. Lembrando que além de capturar os textos para gerar os MP3 depois, eu também preciso printar o post e os comentários.
Antes de sair fazendo scrap, achei importante criar uma função para evitar que o bot pegue publicações +18 do reddit e acabe falando besteira por ai.
O bot faz um GET no sub do reddit, passando alguns parametros para pegar o top 30 e depois é feito um filtro para evitar pegar posts inapropriados.
export const chooseOnePost = async () => {
const response = await fetch("https://www.reddit.com/r/AskReddit/top.json?t=day&limit=30")
const responseData = await response.json()
const posts = responseData.data.children
const safePosts = posts.filter((post) => post.data.whitelist_status !== "nsfw" && !post.data.over_18)
return safePosts[randomInt(0, safePosts.length - 1)].data
}
Depois disso o scrap começa a ser feito. Para quem não conhee o termo Scrap, ele é relacionado com o ato de extrairmos informações de páginas através do esqueleto da página, neste caso é a partir das tags html.
Nessa função eu crio uma instância do Chromium usando o Puppeteer. Depois começo a navegar pela página.
export const getPostContent = async (url: string, postsLimit: number): Promise<PostContent> => {
info("scrapping post")
const browser = await puppeteer.launch({ headless: "new" })
const page = await browser.newPage()
await page.setViewport({ width: 1920, height: 1080 })
await page.goto(url)
success("screenshot post")
const postTitle = await handlePostTitle(page)
success("screenshot post comments")
const comments = await handlePostComments(page, postsLimit)
await browser.close()
const splitedURL = url.split("/")
success("scrapping post")
return {
slug: splitedURL[splitedURL.length - 2],
title: postTitle,
comments,
}
}
Este é um exemplo de uma das funções usadas para capturar informações da página e depois tirar um print apenas do elemento onde essa informação está presente:
const POST_TAG_NAME = "shreddit-post"
const POST_TITLE_CLASS_NAME = ".text-neutral-content-strong"
const handlePostTitle = async (page: Page) => {
await page.waitForSelector(POST_TAG_NAME)
const element = await page.$(POST_TAG_NAME)
await element?.screenshot({ path: "./output/post.png" })
let post = await page.$(`${POST_TAG_NAME} > ${POST_TITLE_CLASS_NAME}`)
const postTitle = await page.evaluate((el) => el.textContent, post)
return postTitle.trim()
}
A resposta dessa função de scrap, é um objeto contendo o título do post e um array de string dos primeiros 5 comentários.