Executando verificação de segurança...
3

[Tutorial] Como Fazer Web Scraping com o Xcrap - Web Scraping com Node.js

Para quem não conhece, Xcrap é um framework de Web Scraping feito para ser usado no Node.js. Ele abstrai e define camadas como parsing (extração) e transforming (transformação), de forma que o código ganha uma organização escalável e manutenção facilitada.

Neste artigo, vou apenas ensinar o básico sobre como fazer scraping em páginas estáticas, ou seja, páginas que não precisam da execução de JavaScript para exibir informações no documento.


Iniciando projeto

Para iniciar qualquer projeto Node.js, iniciamos um pacote executando o seguinte comando:

npm init -y

Crie uma pasta chamada src e um arquivo chamado index.ts

Instalando as dependências

Para que o projeto funcione, vamos instalar algumas dependências:

npm i @xcrap/core @xcrap/parser @xcrap/transformer

E para que tenhamos todos os tipos necessários e ferramentas de desenvolvimento, instalaremos algumas dependências de desenvolvimento:

npm i --save-dev @types/node typescript ts-node

E, por fim, iremos iniciar o TypeScript no nosso projeto:

npx tsc --init

Configurando scripts

No nosso package.json temos de configurar alguns scripts para executar e compilar o nosso código mais facilmente, executando comandos npm run ao invés de escrevê-los por completo todas as vezes que quisermos realizar aquilo.

{
	...
	"scripts": {
		"build": "npx tsc",
		"dev": "ts-node ./src/index.ts",
		"start": "node ./src/index.js"
	},
	...
}

Proposta da extração

Neste artigo, o nosso objetivo é extrair citações, com o nome de seus autores, links de páginas de autores e tags. Algo parecido com isso:

[
	{
		text: "...",
		tags: ["...", "...", ...],
		author: {
			name: "...",
			pageUrl: "..."
		}
	},
	...
]

A URL do site que iremos extrair essas informações é: https://quotes.toscrape.com/

Primeiros passos

Para começar, primeiramente devemos fazer a requisição e fazer a leitura de forma que possamos manipular a resposta para poder extrair o que nos interessa:

import { HttpClient } from "@xcrap/core"

;(async () => {
	const client = new HttpClient() // Cria uma instância de Cliente HTTP
	const url = "https://quotes.toscrape.com/"
	const response = await client.fetch({ url: url }) // Executa uma requisição usando HTTP do Node Core
})();

E, para poder ler e manipular a resposta da forma certa, vamos pedir ao Xcrap que interprete a resposta como um Parser de HTML:

	...
	const parser = response.asHtmlParser()
})();

Construindo modelos de extração de dados

O framework Xcrap trata a a extração de dados de forma bem singular, não há nada parecido em nenhuma biblioteca existente. Isso não quer dizer que isso seja bom ou ruim necessariamente, é só mais uma das formas de se resolver problemas e manutenibilidade no mundo do Web Scraping.

Até o momento, o framework oferece modelos de parsing para HTML, Markdown e JSON. Aqui, neste exemplo, trataremos apenas do modelo para HTML:

import { extractInnerText, extractHref, HtmlParsingModel } from "@xcrap/parser"

const authorParsingModel = new HtmlParsigModel({
	name: {
		query: ".author", // seletor do elemento
		extrctor: extractInnerText // função extratora de elemento
	},
	pagePath: {
		query: "a", // seletor do elemento
		extractor: extractHref // função extratora de elemento
	}
})

const quoteParsinModel = new HtmlParsingModel({
	text: {
		query: ".text",
		extractor: extractInnerText
	},
	tags: {
		query: ".tag", // seletor dos elementos
		multiple: true, // se deve buscar múltiplos elementos
		extractor: extractInnerText // função extratoras
	},
	author: { // modelo alinhado
		query: ".text+ span", // seletor do elemento pai
		model: authorParsingModel // modelo filho
	}
})

Se você prestou a atenção na definição dos modelos percebeu que, com a declaração deles, descrevemos quais dados iremos querer e como queremos que eles sejam retornados. É quase a forma final que estávamos desejando, exceto por pagePath que deve tornar-se pageUrl.

Para integrar esse código ao resto, é bem simples na verdade:

	...
	const extractedData = await parser.extractMany({
		query: ".quote", // seletor das caixas que contém as citações
		model: quoteParsingModel // modelo no que inclue as regras de extração
	})
	
	console.log(extractedData)
})();

Executando esse código, você terá algo parecido com isso impresso em seu terminal:

[
	{
		text: "...",
		tags: ["...", "...",  ...],
		author: {
			name: "...",
			pagePath: "..."
		}
	},
	...
]

Construindo modelos de transformação de dados

O pagePath retornado pela execução do parsing retorna um link que começa com /, ou seja, necessitaria de uma URL base para que seja acessível de fato, assim como gostaríamos. Para lidar com isso, iremos criar também um modelo de transformação quoteTransformingModel e authorTransformingModel:

import { TransformingModel, StringTransformer, transform } from "@xcrap/transformer"

const authorTransformingModel = new TransformingModel({
    pageUrl: [
        transform({
            key: "pagePath",
            transformer: StringTransformer.resolveUrl("https://quotes.toscrape.com")
        })
    ]
}).after({
    delete: ["pagePath"]
})

const quoteTransformingModel = new TransformingModel({
    author: [
        transform({
            key: "author",
            transformer: (value: any) => {
                const transformer = new Transformer(value)
                return transformer.transform(authorTransformingModel)
            }
        })
    ]
})

Para integrar a camada de transformação de dados no código atual, você vai precisar criar um transformador a partir dos dados extraídos e executar a transformação da seguinte forma:

	...
	const transformedData = await Promise.all(
        extractedData.map(async (quote) => {
            const transformer = new Transformer(quote)
            return await transformer.transform(quoteTransformingModel)
        })
    )
    
    console.log(transformedData)
})();

Executando esse código, você terá impresso no seu terminal algo como o que esperávamos no início do artigo. Então é isso! Caso queiram o código final completo, está aqui: https://github.com/marcuth/web-scraping-with-nodejs

Carregando publicação patrocinada...
1
1
1

Cara, legal teu tutorial. Apenas é extremamente relevante descobrir como o dado está disposto na fonte original, as tags html e até a paginação necessária para pegar ele.

1