Você está na página 1de 53

API GENÉRICA PARA EXTRAÇÃO DE DADOS DE PÁGINAS

DA INTERNET

Anor Batista Esteves Neto

Projeto de Graduação apresentado ao Curso


de Engenharia Eletrônica e de Computação
da Escola Politécnica, Universidade Federal
do Rio de Janeiro, como parte dos requisitos
necessários à obtenção do tı́tulo de Enge-
nheiro.

Orientador: Flávio Luis de Mello

Rio de Janeiro
Julho de 2021
Declaração de Autoria e de Direitos

Eu, Anor Batista Esteves Neto CPF 146.173.927-69, autor da monografia


API GENÉRICA PARA EXTRAÇÃO DE DADOS DE PÁGINAS DA INTER-
NET, subscrevo para os devidos fins, as seguintes informações:
1. O autor declara que o trabalho apresentado na disciplina de Projeto de Gra-
duação da Escola Politécnica da UFRJ é de sua autoria, sendo original em forma e
conteúdo.
2. Excetuam-se do item 1. eventuais transcrições de texto, figuras, tabelas, conceitos
e idéias, que identifiquem claramente a fonte original, explicitando as autorizações
obtidas dos respectivos proprietários, quando necessárias.
3. O autor permite que a UFRJ, por um prazo indeterminado, efetue em qualquer
mı́dia de divulgação, a publicação do trabalho acadêmico em sua totalidade, ou em
parte. Essa autorização não envolve ônus de qualquer natureza à UFRJ, ou aos seus
representantes.
4. O autor pode, excepcionalmente, encaminhar à Comissão de Projeto de Gra-
duação, a não divulgação do material, por um prazo máximo de 01 (um) ano,
improrrogável, a contar da data de defesa, desde que o pedido seja justificado, e
solicitado antecipadamente, por escrito, à Congregação da Escola Politécnica.
5. O autor declara, ainda, ter a capacidade jurı́dica para a prática do presente ato,
assim como ter conhecimento do teor da presente Declaração, estando ciente das
sanções e punições legais, no que tange a cópia parcial, ou total, de obra intelectual,
o que se configura como violação do direito autoral previsto no Código Penal Bra-
sileiro no art.184 e art.299, bem como na Lei 9.610.
6. O autor é o único responsável pelo conteúdo apresentado nos trabalhos acadêmicos
publicados, não cabendo à UFRJ, aos seus representantes, ou ao(s) orientador(es),
qualquer responsabilização/ indenização nesse sentido.
7. Por ser verdade, firmo a presente declaração.

Anor Batista Esteves Neto

iii
UNIVERSIDADE FEDERAL DO RIO DE JANEIRO
Escola Politécnica - Departamento de Eletrônica e de Computação
Centro de Tecnologia, bloco H, sala H-217, Cidade Universitária
Rio de Janeiro - RJ CEP 21949-900

Este exemplar é de propriedade da Universidade Federal do Rio de Janeiro, que


poderá incluı́-lo em base de dados, armazenar em computador, microfilmar ou adotar
qualquer forma de arquivamento.

É permitida a menção, reprodução parcial ou integral e a transmissão entre bibli-


otecas deste trabalho, sem modificação de seu texto, em qualquer meio que esteja
ou venha a ser fixado, para pesquisa acadêmica, comentários e citações, desde que
sem finalidade comercial e que seja feita a referência bibliográfica completa.

Os conceitos expressos neste trabalho são de responsabilidade do(s) autor(es).

iv
DEDICATÓRIA

Dedico este trabalho à minha mãe, que sempre me deu suporte em todos os
momentos da minha vida.

v
AGRADECIMENTO

Agradeço minha famı́lia por continuamente me apoiarem e motivarem na busca


por educação e conhecimento. Agradeço meus amigos, por estarem sempre presentes.
Agradeço também ao meu orientador pela atenção e solicitude na orientação deste
trabalho.

vi
RESUMO

Com a constante expansão da digitalização à nı́vel global, o uso da Internet torna-


se cada vez mais essencial em todos os sistemas. Por conseguinte, a extração e
consumo de dados vindo da world wide web mostra-se tarefa corriqueira e necessária
para o desenvolvimento de novas aplicações e sistemas. Assim sendo, este trabalho
tem por objetivo facilitar e agilizar o consumo de dados vindos da web ao propor a
criação de uma interface entre a aplicação final e as páginas de Internet que possuem
os dados de interesse. Isto é alcançado através da criação de uma API genérica
para Web Scrapping que recebe requisições configuráveis quanto ao site e os dados
que devem ser extraı́dos da rede, eliminando a necessidade de programação de tal
processo no desenvolvimento de um novo sistema. A API desenvolvida funciona de
forma assı́ncrona, permite a execução de múltiplas rotinas de scrapping em portais
diferentes com uma única requisição e permite a extração de dados de páginas da
Internet com conteúdo dinâmico.

Palavras-Chave: Web Scrapping, Dados, API, Internet, Web.

vii
ABSTRACT

With the constant expansion of global digitization , the use of the Internet becomes
more and more essential to all systems. Therefore, the extraction and consumption
of data coming from the world wide web is a common and necessary task for the
development of new applications and systems. For that reason, this project aims
to facilitate and speed up the consumption of data from the Web by proposing to
create an interface between the final application and the Internet pages that have
the data of interest. This is achieved by creating a generic API for Web Scrapping
that receives configurable requests regarding the site and the data that must be
extracted from the network, eliminating the need to program such a process when
developing a new system. The developed API works asynchronously, allows the
execution of multiple scrapping routines in different portals with one single request
and allows the extraction of data from web pages with dynamic content.

Key-words: Web Scrapping, Data, API, Internet, Web.

viii
SIGLAS

API - Application Programming Interface

CSS - Cascading Style Sheets

HTML - Hypertext Markup Language

HTTP - Hypertext Transfer Protocol

IO - Input/Output

JSON - JavaScript Object Notation

URL - Uniform Resource Locator

XML - Extensible Markup Language

ix
Sumário

1 Introdução 1
1.1 Tema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 Delimitação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.3 Justificativa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.4 Objetivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.5 Metodologia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2

2 Fundamentação Teórica 4
2.1 Coleta Automatizada de Dados na Internet . . . . . . . . . . . . . . . 4
2.2 Páginas Web . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.3 Páginas Web Dinâmicas . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.4 API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.5 Web Scrapping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.6 Execução Assı́ncrona . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.7 Soluções Existentes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

3 Proposta de Solução 12
3.1 Descrição do Problema . . . . . . . . . . . . . . . . . . . . . . . . . . 12
3.2 Arquitetura da solução . . . . . . . . . . . . . . . . . . . . . . . . . . 14
3.2.1 Arquitetura do Web Scrapping . . . . . . . . . . . . . . . . . 16
3.2.2 Arquitetura da API . . . . . . . . . . . . . . . . . . . . . . . . 17
3.3 Implementação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
3.3.1 Classes de Entrada e Saı́da . . . . . . . . . . . . . . . . . . . . 18
3.3.2 Implementação dos endpoints . . . . . . . . . . . . . . . . . . 20
3.4 Instalação do Utilitário . . . . . . . . . . . . . . . . . . . . . . . . . . 23

x
3.5 Testes Realizados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
3.5.1 Sites com HTML estático . . . . . . . . . . . . . . . . . . . . 27
3.5.2 Sites com HTML dinâmico . . . . . . . . . . . . . . . . . . . . 29
3.5.3 Testes Adicionais . . . . . . . . . . . . . . . . . . . . . . . . . 30

4 Conclusão 32
4.1 Conclusão . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
4.2 Pontos passı́veis de melhoria . . . . . . . . . . . . . . . . . . . . . . . 33

Bibliografia 34

A Obtendo seletor CSS de um elemento 37


A.1 Obtendo seletor CSS de um elemento . . . . . . . . . . . . . . . . . . 37

B Informações Complementares 39
B.1 Principais Seletores CSS . . . . . . . . . . . . . . . . . . . . . . . . . 39

xi
Lista de Figuras

2.1 Exemplo de Documento HTML. Código do documento a esquerda e ren-


derização pelo navegador a direita. . . . . . . . . . . . . . . . . . . . . . 6
2.2 Ilustração de uma API. . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.3 Ilustração dos tipos de execução. Tarefas são representadas por cores di-
ferentes e os eixos indicam o tempo corrido. . . . . . . . . . . . . . . . . 10
2.4 Interface de configuração do portia [1]. . . . . . . . . . . . . . . . . . . . 11

3.1 Exemplo de seletor CSS [2] . . . . . . . . . . . . . . . . . . . . . . . . . 13


3.2 Fluxograma Geral do projeto . . . . . . . . . . . . . . . . . . . . . . . 14
3.3 Arquitetura da solução - na parte superior temos as classes de Web Scrap-
ping com o sufixo Scrapper, e na parte inferior os endpoints da API.
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
3.4 UML das classes de Web Scrapping . . . . . . . . . . . . . . . . . . . . 16
3.5 UML dos endpoints de scrapping da API. . . . . . . . . . . . . . . . . . 17
3.6 Configurações de entrada dos endpoints da API . . . . . . . . . . . . . . 19
3.7 Classes de saı́da dos endpoints da API . . . . . . . . . . . . . . . . . . . 20
3.8 Exemplo de configuração e resposta do endpoint “/site”, corpo do request
do lado esquerdo e resposta do lado direito. . . . . . . . . . . . . . . . . 21
3.9 Código do endpoint “/multisite”, uso da função gather() para execução
de tarefas em concorrência. . . . . . . . . . . . . . . . . . . . . . . . . 22
3.10 Exemplo de resposta do endpoint ”/auto” contendo seletores encontrados 22
3.11 Verificação versão instalada do python e pip . . . . . . . . . . . . . . . 23
3.12 Executando aplicação direto da pasta . . . . . . . . . . . . . . . . . . . 23
3.13 Executando aplicação após instalação no sistema . . . . . . . . . . . . . 24
3.14 Importando coleção de requests no Insomnia . . . . . . . . . . . . . . . 25
3.15 Definindo seletores CSS no corpo do request POST para o endpoint ”/auto” 25

xii
3.16 Definindo texto dos elementos de interesse no corpo do request POST para
o endpoint ”/auto” . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
3.17 Exemplo de retorno do endpoint ”/auto” quando atributo ”list url” é de-
finido. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
3.18 Exemplo de uso dos seletores CSS no endpoint ”/site”. . . . . . . . . . . 27
3.19 Exemplo de descoberta automática dos seletores CSS através do texto do
elemento no endpoint ”/auto”. . . . . . . . . . . . . . . . . . . . . . . 27
3.20 Exemplo de erro no endpoint ”/auto”, elemento possui classe mobile:mb-2
que não pode ser usada como seletor CSS. . . . . . . . . . . . . . . . . 28
3.21 Site do ’Ministério da Fazenda’ - texto de uma célula da tabela está divido
entre três elementos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
3.22 Exemplo de extração de dados de página com conteúdo dinâmico . . . . . 30

A.1 Descobrindo elemento HTML de interesse [3] . . . . . . . . . . . . . . . 38


A.2 Copiando o seletor CSS do elemento HTML . . . . . . . . . . . . . . . . 38

xiii
Lista de Tabelas

3.1 Relação Sites Testados . . . . . . . . . . . . . . . . . . . . . . . . . . 24


3.2 Comparação de tempo entre os endpoints ”/site” e ”auto” . . . . . . 29
3.3 Média de tempo por requests simultâneos. . . . . . . . . . . . . . . . 30
3.4 Comparação da média de tempo para realização do processo de scrap-
ping entre a API desenvolvida e a solução comercial Octoparse. . . . 31

B.1 Principais seletores CSS . . . . . . . . . . . . . . . . . . . . . . . . . 39

xiv
Capı́tulo 1

Introdução

1.1 Tema
Este trabalho tem como tema a coleta de dados de páginas da Internet, permitindo
um fácil acompanhamento de alterações em tais dados. Desta forma, o problema a
ser resolvido é simplificar a obtenção desses dados através da criação de uma API
para Web Scrapping.

1.2 Delimitação
Tem-se como delimitação do trabalho a criação de uma interface para extração
de dados da Internet, para que possam ser utilizados e processados por outros pro-
gramas. Deste modo, a aplicação desenvolvida limita-se a ser um serviço para for-
necimento de dados presentes em páginas da web.

1.3 Justificativa
Com a expansão constante da digitalização dos sistemas e, consequentemente, do
uso da Internet, o volume de dados disponı́veis na rede torna-se cada vez maior
[4, 5]. À vista disso, a necessidade do consumo de dados da web por aplicativos
e programas, seja para análise ou exibição, é recorrente. Ademais, esses dados
apresentam-se de forma não estruturada pelas páginas da rede e os sites que os
contêm raramente fornecem uma API gratuita para sua obtenção, sendo necessário

1
recorrer a soluções comerciais tendo em vista que as soluções de código aberto são
escassas e voltadas para usos especı́ficos.

Logo, o uso de Web Scrapping por aplicações para atingir seus objetivos finais é
corriqueiro, desviando o foco principal e gastando muito tempo desnecessariamente
no desenvolvimento de programas. As soluções existentes para este problema são,
em sua grande maioria, de cunho comercial ou muito especializadas - funcionando
apenas para coleta de dados de fontes especı́ficas.

1.4 Objetivos
O objetivo deste trabalho é, então, criar uma interface genérica para Web Scrap-
ping, possibilitando a coleta de dados independente da fonte e fornecendo-os para
consumo por outras aplicações. Por conseguinte, tem-se como objetivos especı́ficos:

1. Coleta de dados de páginas de internet, independente da fonte

2. Possibilidade de coleta de dados de páginas geradas dinamicamente por Ja-


vascript

3. Possibilidade de coleta de dados de múltiplas fontes simultaneamente

4. Fornecimento de tais dados de forma simplificada, através do formato JSON

5. Automatização e simplificação do processo de coleta de dados, quando possı́vel

1.5 Metodologia
O trabalho consiste na criação de uma API em python, usando como principais
bibliotecas: requests-html, usada como base para parte de Web Scrapping, e fastapi,
usada como base para criação da API.

A API recebe configurações referentes a quais sites e que dados desses sites de-
vem ser coletados através de um JSON enviado pelo método http POST. Após o
recebimento desse request pela API, ela baixa o HTML do site ( renderizando-o

2
previamente caso seja um site criado dinamicamente por Javascript ) e então faz a
busca dos dados requisitados, retornando-os para o usuário no formato JSON.

Para se definir quais dados devem ser coletados de uma página tem-se 2 opções:
passar os seletores HTML/CSS do elemento que se deseja extrair o texto na página,
ou passar o texto que se deseja de uma página base. Neste segundo caso a API
tentará definir qual é o seletor HTML/CSS que contém o texto desejado, e o usará
para fazer a busca nas outras páginas passadas na configuração.

Foram utilizados conceitos de arquitetura de software, quando aplicáveis, na


criação do projeto, com o intuito de manter o código organizado e de permitir a
alteração e inclusão de funcionalidades de forma simples e rápida.

O código-fonte da API desenvolvida neste trabalho está disponı́vel para download


em :

ˆ https://github.com/anorneto/tcc_anor

3
Capı́tulo 2

Fundamentação Teórica

2.1 Coleta Automatizada de Dados na Internet


A globalização digital e o uso da Internet pela sociedade moderna tem atingido pa-
tamares antes inimagináveis. São cerca de 5 bilhões de pessoas utilizando a Internet
em 2020, um pouco mais que 60% da população global [6] [7] .

Nesse contexto, a expansão da Web como forma de disponibilização e de troca de


dados é assı́dua [8, 5]. Tendo em vista o grande volume de informações presente na
Internet, o seu consumo por aplicações e sistemas mostra-se extremamente relevante,
visto que pode guiar práticas de negócios de forma mais eficaz, melhorar a produ-
tividade de empresas ou até mesmo criar novos campos de atuação [9, 10]. Com o
rápido ritmo de progresso nas áreas de aprendizado de máquina e inteligência arti-
ficial, os dados presentes na rede servem, por exemplo, como ótimos datasets para
treinar e classificar algoritmos preditivos.

Entretanto, são poucos os sites que disponibilizam APIs para consumo de seus
dados, e, geralmente, quando os fazem impõem limites de volume ou frequência na
requisição de tais dados ou os disponibilizam com estruturas próprias. Mesmo com
a tentativa de criação de padrões para publicação e uso de dados na Internet, eles
mostram-se majoritariamente desestruturados e representados de formas distintas
ao longo da rede.

4
Segundo a W3C (World Wide Web Consortium) [8], ”[...] A abertura e flexibi-
lidade da Web criam novos desafios para editores e consumidores de dados, como
representar, descrever e disponibilizar os dados de uma maneira que seja fácil de en-
contrar e entender. Em contraste com bancos de dados convencionais, por exemplo,
onde existe um único modelo de dados para representar os dados e um sistema de ge-
renciamento (SGBD) para controlar o acesso aos dados, os dados na Web permitem
a existência de várias maneiras de representar e acessar os dados.”

Dessarte, a necessidade de obtenção de dados da Web de forma fácil, independen-


temente da fonte e de forma estruturada é legı́tima e se mostra vultosa.

2.2 Páginas Web


HTML é o o acrônimo de HyperText Markup Language ( em português, Lingua-
gem de Marcação de HiperTexto) e é a base de construção de páginas de Internet
[11]. O HTML descreve a estrutura dessas páginas através de uma série de elemen-
tos que indicam para o navegador como a página deve ser exibida. Esses elementos
determinam onde e o que será exibido na página, e são separados do texto em um
documento HTML pela definição de tags delimitadas por < e > que indicam o tipo
de informação a ser exibida. Outras tecnologias também são comumente utilizadas
em conjunto com o HTML para definir a aparência (CSS) e/ou o comportamento
(Javascript) de páginas da Web no navegador.

O CSS (Cascading Style Sheets) é uma linguagem de estilo usada para descrever
a apresentação de documentos escritos em linguagens de marcação [12], no caso de
páginas da Web o CSS é usado para definir o estilo dos elementos do documento
HTML. Essa estilização dos elementos da página pode ser feita direto no documento
HTML ao se setar a propriedade style do elemento, ou através de seletores definidos
nos elementos da página e definindo-se a aparência desses seletores em um arquivo
separado (.css). No CSS, os seletores podem ser do tipo id (identificador único para
cada elemento do documento ) ou class(identificador que pode estilizar múltiplos
elementos em um documento ).

5
Figura 2.1: Exemplo de Documento HTML. Código do documento a esquerda e rende-
rização pelo navegador a direita.

O Javascript é uma linguagem de programação interpretada e baseada em protótipos


[13], que tem como sua maior aplicação o uso como linguagem de script em páginas
da web com o intuito de proporcionar interatividade e dinamismo na exibição do
documento HTML pelo navegador.

O uso corriqueiro do CSS e do Javascript em páginas da Web traz dificuldades


na realização de Web Scrapping. No caso do CSS, o uso de seletores do tipo class
repetidos nos elementos do documento HTML dificulta a correta extração de dados
da página visto que esse identificador não é único. Já no caso do Javascript, a difi-
culdade mencionada refere-se a criação de páginas web dinâmicas, que será melhor
detalhada na seção abaixo (2.3).

2.3 Páginas Web Dinâmicas


A navegação por páginas definidas somente em HTML é estática, pois a estrutura
da página definida pelo documento HTML é imutável. Porém, com o avanço das
tecnologias usadas nas Internet, uma página da web pode também proporcionar uma
experiência dinâmica na navegação, atualizando o documento HTML da página de
forma interativa com as ações do usuário.

6
A manipulação do HTML para gerar páginas dinâmicas pode ser feita de 2 formas :
client-side rendering e server-side rendering[14]. No client-side rendering o próprio
navegador do usuário é responsável por modificar o HTML da página que está
sendo exibida através da execução do script em Javascript presente na página. Já
no server-side rendering o HTML dinâmico é gerado no servidor de acordo com
interações do usuário vindas do navegador, onde modifica-se o conteúdo do HTML
somente na navegação entre páginas.

Para lidar com páginas dinâmica nesse projeto faz-se o uso da biblioteca pyppeteer
[15], que é a adaptação em Python de uma famosa biblioteca feita em Javascript
chamada puppeteer. A biblioteca pyppeteer [15] faz o uso de um navegador sem
interface gráfica para renderizar o conteúdo das páginas geradas dinamicamente por
Javascript, retornando o HTML já processado pelo navegador.

2.4 API
API é a sigla para Application Programming Interface (em portugês, Interface de
Programação de Aplicações), e é um serviço para ser utilizado por outras aplicações,
fornecendo dados tratados e funções de forma transparente e abstraindo os detalhes
relacionados a implementação [16]. Uma API é responsável por receber requisições
de outras aplicações e retornar os resultados destes requerimentos.

Figura 2.2: Ilustração de uma API.

Quando usada no contexto Web, uma API define especificações de como receber
requisições através do protocolo HTTP e da estrutura de suas respostas, geralmente

7
nos formatos JSON ou XML. A API disponibiliza suas funções para execução por
uma aplicação cliente através de endpoints, que são URLs definidas pela API onde
o serviços disponibilizados podem ser acesados[16]. A comunicação entre a API e
a aplicação cliente da-se através de requisições da aplicação cliente nos endpoints
da API utilizando o protocolo HTTP. Os principais métodos do protocolo HTTP
utilizados na comunicação com uma API Web são o HTTP GET e o HTTP POST;
ambos retornam resultados para aplicação requerente porém apenas o método HTTP
POST envia informações para a API.

2.5 Web Scrapping


Da-se o nome de Web Scrapping ao processo automatizado de extração de dados
de um website [17]. O processo de Web Scraping foca na obtenção e transformação
de dados desestruturados provindos da Web, tipicamente em formato HTML, em
dados estruturados que podem ser analisados e armazenados [18].

De forma simplificada, o fluxo de funcionamento de um programa de Web Scrap-


ping se divide em 3 passos[5, 19]: obtenção do conteúdo da página de internet,
extração dos dados requisitados e fornecimento dos dados extraı́dos de forma estru-
turada.

Desse modo, o programa de Web Scrapping deve inicialmente obter o conteúdo


da página requerida através do método HTTP GET, que retornará a estrutura da
página no formato HTML. Tal estrutura fica salva temporariamente na memória do
programa como um bloco de texto.

Em seguida, o programa extrai os dados requisitados da estrutura HTML da


página citada anteriormente. Isso é realizado através da análise do texto da página
(chamado em inglês de parsing), onde o programa irá percorrer o texto da página
procurando os dados de interesse e salvando-os em variáveis e ignorando o resto.

8
De posse dos dados coletados da página, o programa de Scrapping os fornece
reorganizados de forma estruturada, de modo que possam ser utilizados por outros
programas.

As bibliotecas de Scrapping de código aberto e mais utilizadas pela comunidade


de desenvolvedores são a Scrapy [20] e a PySpider [21]. Entretanto, tais bibliotecas
tem um foco maior em ser um framework para uso como um programa separado do
que um conjunto de funções auxiliares, o que dificulta a configuração dinâmica de
Web Scrapping - que é um dos focos deste trabalho. Portanto, escolheu-se usar a
biblioteca Requests-HTML [22], que é a junção de diversas bibliotecas de extração
e manipulação de dados da Web em 1 único pacote; proporcionando funções para
obtenção do documento HTML da página, análise e extração de texto e integração
com a biblioteca de renderização de páginas dinâmicas (pyppeteer [15]) mencionada
anteriormente na Seção 2.3 .

2.6 Execução Assı́ncrona


No desenvolvimento de aplicações e sistemas existem basicamente duas formas
de se realizar tarefas de forma não sequencial: Concorrência e Paralelismo. A
concorrência acontece quando duas ou mais tarefas são executadas num perı́odo
de tempo que se sobrepõem, mas não necessariamente ao mesmo tempo, onde a
execução de uma tarefa progride enquanto espera-se resposta de outra [23]. O pa-
ralelismo ocorre quando duas tarefas ou múltiplas partes de uma mesma tarefa são
executadas ao mesmo tempo, seja em threads ou processos separados, e fazendo uso
de processadores com mais de 1 núcleo (multicore) [23].

O Python possui no seu interpretador padrão (CPython) um mecanismo que im-


possibilita a execução de mais de 1 thread ao mesmo tempo, chamado GIL (Global
Interpreter Lock) [24]. Esse mecanismo foi criado para possibilitar a rápida e fácil
inclusão de bibliotecas externas em C, que não tem um manuseamento thread-safe de
memória [24]. Por conseguinte, somente conseguimos realizar paralelismo no Python
através de múltiplos processos, o que inclui um nı́vel de maior complexidade e traz
poucos benefı́cios para aplicações onde não se faz uso intenso da CPU. Portanto,

9
Figura 2.3: Ilustração dos tipos de execução. Tarefas são representadas por cores dife-
rentes e os eixos indicam o tempo corrido.

escolheu-se para esse projeto o uso de concorrência para execução de tarefas de


forma assı́ncrona através do uso da biblioteca Asyncio [25].

O funcionamento da biblioteca Asyncio [25] baseia-se no conceito de Laço de Even-


tos (Event Loop), que é responsável por coordenar qual tarefa deve ser executada de
acordo com os eventos ocorridos. Quando, por exemplo, uma função definida como
async está sendo executada e encontra a expressão await, ela sinaliza que precisa
esperar informações ( seja uma resposta de um request HTTP, a leitura de algum IO
do sistema ou a execução de alguma outra aplicação) e cede o controle de execução
de volta pra o Laço de Eventos realizar outras tarefas [26]. O Laço de Eventos checa
periodicamente se as tarefas que estavam em estado de espera podem finalizar sua
execução.

2.7 Soluções Existentes


Atualmente, existem diversas soluções para Web Scrapping, sendo elas prepon-
derantemente de caráter comercial. As soluções comerciais cobram uma assinatura

10
mensal que geralmente tem valor de entrada entre U$30 e U$50, podendo chegar até
planos de U$ 900 no caso da octoparse [27] , e oferecem diversas funções, como: ren-
derização de páginas dinâmicas, rotação de IP através do uso de proxy, exportação
automática de dados, entre outros. Algumas dessas soluções oferecem planos gra-
tuitos, que apesar de limitados em relação a funcionalidades e a quantidade de
requisições diárias, servem para testar a qualidade dos serviços oferecidos; sendo
alguma delas: octoparse [27], parsehub [28], scrappingbot [29]. A solução comercial
que mais se assemelha com a proposta desse trabalho é a webscrapper [30], visto que
oferece uma API para configuração dos scrappers e obtenção dos dados.

Dentre as poucas soluções de código aberto, a que se destaca é o framework Scrapy


[20] com seus vários módulos de extensão (plugins) desenvolvidos pela comunidade.
Um projeto interessante baseado no framework Scrapy é o portia [1], que permite
anotações visuais de que dados devem ser extraı́dos de uma página, permitindo que
pessoas sem muito conhecimento em programação configurem crawlers visualmente.

Figura 2.4: Interface de configuração do portia [1].

11
Capı́tulo 3

Proposta de Solução

3.1 Descrição do Problema


Como mencionado nos capı́tulos anteriores, o consumo de dados provenientes da
Internet é prática comum no desenvolvimento de aplicações. Devido a natureza
do documento HTML, tais dados apresentam-se de forma semi-estruturada e de-
suniforme ao longo da rede, principalmente quando pensa-se em centralizar dados
provindos de diferentes fontes.

Para realizar a extração de dados de um site deve-se obter o documento HTML


da página e analisá-lo, a fim de se definir o seletor CSS que contém o dado de
interesse a ser extraı́do. Caso a página seja gerada dinamicamente, deve-se renderiza-
la antecipadamente em um navegador para que o HTML final da página seja gerado.
Na extração de dados de tabelas, principalmente as geradas dinamicamente, tem-
se, também, o problema de os seletores CSS serem iguais para campos distintos,
dificultando a correta estruturação dos dados extraı́dos. Para extrair, por exemplo,
o tı́tulo da notı́cia da página de Internet abaixo (Figura 3.1), poderia-se usar o
seletor CSS : ”header.postHeader >h3.postTitle >a” .

Desse modo, selecionar e copiar dados manualmente de páginas da Internet é um


trabalho demorado e tedioso. O programa de Web Scrapping automatiza o processo
manual de humanos visitarem sites periodicamente para pesquisar e armazenar da-
dos de interesse, fazendo o mesmo trabalho em uma fração do tempo e podendo ser
configurado para funcionar com qualquer site ou construı́do de forma personalizada

12
Figura 3.1: Exemplo de seletor CSS [2]

para um site especı́fico. No entanto, os softwares genéricos de Web Scrapping po-


dem não fornecer qualquer opção para extrair o conteúdo necessário devido ao seus
modelos intransigentes e à falta de opções de configurações.

Portanto, neste trabalho busca-se facilitar e agilizar o processo de extração de


dados da Internet através da criação de um API, visto que desenvolver a lógica de
coleta de dados todas as vezes que for necessária em uma aplicação desvia o foco

13
principal e atrasa o desenvolvimento da aplicação final. Outrossim, tem-se também
como objetivo automatizar o máximo possı́vel do processo de Web Scrapping, reti-
rando a necessidade da definição manual dos seletores CSS que contém os dados de
interesse, ao fazer-se o processo inverso do usual, onde o usuário define o texto de
interesse e a aplicação descobre o seletor CSS de interesse a ser usado em páginas
similares.

3.2 Arquitetura da solução

Figura 3.2: Fluxograma Geral do projeto

O serviço proposto tem a função de ser uma interface para extração de dados
de páginas da Internet, fornecendo os dados extraı́dos de forma estruturada para
serem consumidos por outras aplicações. Além disso, o programa deve ser de fácil
utilização e instalação, e deve permitir o recebimento de configurações para que
funcione independente da fonte (site) de onde os dados estão sendo extraı́dos.

Isto posto, desenvolveu-se uma API para extração de dados da Web em Python,
que é uma linguagem de programação de alto nı́vel, interpretada e orientada ao
objeto. Ela foi escolhida por ser disponibilizada com uma licença open-source, ter
executáveis para os principais sistemas operacionais de computadores (Windows,
Linux e Mac OS) e por ser muito utilizada por desenvolvedores, tendo uma grande
comunidade e diversas bibliotecas disponı́veis.

A API desenvolvida recebe requisições com as configurações de scrapping no for-


mato JSON através de requisições HTTP. As rotinas de Web Scrapping são sempre

14
executadas de forma assı́ncrona pelo programa, permitindo que não fique travado
em apenas uma tarefa e possa continuar recebendo requisições em seus endpoints.
As respostas da API são também no formato JSON, trazendo estrutura e pratici-
dade para os dados extraı́dos da Internet e facilitando seu consumo pelas aplicações
finais.

Assim, a arquitetura do projeto divide-se em duas partes: Web Scrapping e API,


como pode ser visto na Figura 3.3.

Figura 3.3: Arquitetura da solução - na parte superior temos as classes de Web Scrapping
com o sufixo Scrapper, e na parte inferior os endpoints da API.

Na parte referente ao Web Scrapping faz-se o uso das bibliotecas Requests-HTML


[22] ( para extração e análise de dados da Web) e pyppeteer [15] ( para renderização

15
de páginas dinâmicas da Internet e extração do seu HTML). Na parte referente à
API usa-se as bibliotecas FastApi [31] (para estruturação da API e definição de
endpoints assı́ncronos) e Asyncio [25] (para execução assı́ncrona de tarefas).

3.2.1 Arquitetura do Web Scrapping

Figura 3.4: UML das classes de Web Scrapping

Para realização do Web Scrapping tem-se três Classes (ver Figura 3.4) definidas
no arquivo Crawlers.py, sendo a classe IBaseScrapper a classe pai, e AsyncScrap-
per e AutoScrapper as classes filhas. A classe pai IBaseScrapper define variáveis
necessárias para as configurações de scrapping, os métodos para inı́cio e término
das sessões de scrapping e um métodos abstrato chamado scrap, implementado pe-
las classes filhas (AsyncScrapper e AutoScrapper), que definem como a extração de
dados nos sites serão realizadas e a sua resposta.

16
3.2.2 Arquitetura da API

Figura 3.5: UML dos endpoints de scrapping da API.

A API é estruturada em três endpoints ( Figura 3.5 ) que recebem requests HTTP
to tipo POST com as configurações de scrapping no corpo do request no formato
JSON. Tais endpoints executam o método de scrap da classe de scrapping pertinente
de forma assı́ncrona, com as configurações recebidas pelo request POST, e retornam
seu resultado. A API contêm dois endpoints que recebem seletores CSS ( campo
”selectors”), um para realizar scrapping em um único site ( endpoint ”/site”) e um
para vários sites ( endpoint ”/multisite”), que recebe uma lista de configurações no
formato ScrapConfig e internamente chama o método de scrapping de site único
para os n sites.

O terceiro endpoint , ”/auto” , funciona de forma mais automatizada e descobre


os seletores CSS dos elementos a partir do texto de interesse, ou seja, funciona de
forma oposta aos outros dois endpoints, visando a facilidade de uso. Este endpoit
pode tanto os seletores CSS encontrados para os elementos, ou o resultado da coleta
de dados nos sites definidos no campo ”list url” - caso seja definido - ao chamar
internamete o endpoint ”/multisite” passando os seletores CSS descobertos.

17
3.3 Implementação
Como dito anteriormente na Seção 3.2, o projeto foi desenvolvido na linguagem
de programação Python devido a quantidade de bibliotecas disponı́veis e a portabi-
lidade do programa quanto a ser executado em diferentes sistemas operacionais. Os
endpoints da API parametrizam como os métodos de Web Scrapping são configura-
dos e executados, e retornam para a aplicação cliente as respostas de tais métodos
com os dados extraı́dos de forma estruturada. Todas os endpoints e funções de
scrapping da API funcionam de forma assı́ncrona para que ela possa realizar todas
as ações requisitadas pelas aplicações clientes de forma concorrente. As respostas
dos endpoints da API são sempre retornadas no formato JSON para que fiquem
estruturadas e possam ser utilizadas facilmente por outras aplicações.

3.3.1 Classes de Entrada e Saı́da

A API define qual o formato da configuração que deve ser recebida em cada
um dos endpoints através das classes ScrapConfig e AutoScrapConfig (Figura
3.6). Tais classes são criadas pelos endpoints a partir do JSON recebido no corpo
do request HTTP POST, e seus atributos são passados como parâmetros para as
funções de scrapping pertinentes a cada endpoint. Tem-se em comum entre as classes
de configuração os campos:

ˆ config name - define o nome da configuração recebida. O valor passado é


retornado na resposta do método chamado.

ˆ base url - define a URL base de onde os dados serão extraı́dos.

ˆ response as list - define se a resposta deve ser dada no formato de lista, onde
separa-se na resposta o nome dos campos selecionados para extração em uma
lista e os valores extraı́dos em outra. Utilizado principalmente para melhor
estruturação de dados extraı́dos de tabelas.

ˆ render page - define se o HTML da página deve ser renderizado pela bibli-
oteca pyppeter [15] em segundo plano em um navegador sem interface gráfica
(Chromium Headless) antes da extração dos dados. Utilizado para extração
de dados de páginas criadas dinamicamente com javascript.

18
Os campos response as list e render page possuem valor padrão definido como
falso, pois são campos opcionais dado que servem para tratar os problemas es-
pecı́ficos descritos. Para a classe ScrapConfig, os seletores CSS são definidos por
um dicionário onde a chave é o nome do campo que conterá o dado extraı́do e o valor
é o seletor CSS de onde deve-se extrair o dado requerido. Na classe AutoScrap-
Config define-se os textos dos elementos de interesse através do campo ”strings”,
que é um dicionário no modelo ”nomeCampoResposta”:”textoDoElemento”.

1 class ScrapConfig ( BaseModel ) :


2 config_name : str
3 base_url : str
4 selectors : Dict [ str , str ]
5 response_as_list : bool = False
6 render_page : bool = False
7

8 class AutoScrapConfig ( BaseModel ) :


9 config_name : str
10 base_url : str
11 strings : Dict [ str , str ]
12 response_as_list : bool = False
13 render_page : bool = False
14 list_url : List [ str ] = []

Figura 3.6: Configurações de entrada dos endpoints da API

As respostas da API são definidas pelas classes ScrapResponse e AutoScra-


pResponse (Figura 3.7), e retornam os seguintes campos em comum :

ˆ config name - nome da configuração que foi recebida no request

ˆ url - URL em que foi realizada a coleta de dados.

ˆ render page - identifica se a página foi renderizada pelo navegador em se-


gundo plano.

A classe AutoScrapResponse define no campo ”selectors” os seletores CSS en-


contrados no formato de um dicionário, onde a chave é o nome recebido pelas con-

19
1 class ScrapResponse ( BaseModel ) :
2 config_name : str
3 url : str
4 render_page : bool = False
5 headers : List [ str ] = None
6 items : Union [ Dict [ str , List [ str ]] , List [ List [ str ]]]
7

8 class AutoS crapRe sponse ( BaseModel ) :


9 config_name : str
10 url : str
11 render_page : bool = False
12 selectors : Dict [ str , Dict [ str , str ]]

Figura 3.7: Classes de saı́da dos endpoints da API

figurações do request e o valor é outro dicionário contendo o seletor CSS completo e


a última tag HTML do elemento que contêm o texto recebido nas configurações.

Na resposta modelada pela classe ScrapResponse os dados encontrados após o


processo de scrapping encontram-se no atributo ”items”. Se a configuração ”res-
ponse as list” tiver sido recebida com valor verdadeiro, o campo ”headers” conterá
uma lista com o nome dos campos passados para a API e o campo ”items” será uma
lista contendo sublistas que representam os conjuntos de dados encontrados para os
valores presentes no campo ”headers”. Do contrário, o campo ”items” conterá um
dicionário em que a chave é o nome do campo recebido nas configurações do endpoint
e o valor é uma lista com os dados encontrados para o seletor CSS definido.

3.3.2 Implementação dos endpoints

O endpoint ”/site” recebe os campos da configuração ScrapConfig e realiza a ex-


tração de dados de uma única URL ( definida pelo parâmetro base url), através dos
seletores CSS provenientes do campo ”selectors” ( Figura 3.8), retornando uma res-
posta JSON definida pela classe ScrapResponse. Esse endpoint instancia a classe
AsyncScrapper com as configurações recebidas e em seguida executa de forma
assı́ncrona seu método scrap(), que itera sobre o HTML da página procurando o

20
texto presente nos seletores CSS especificados, e retorna a resposta de tal método
para a aplicação cliente. Para uma melhor taxa de sucesso na extração dos dados dos
documentos HTML remove-se elementos raiz desnecessários como as tags <script >
e <head >, procurando-se os dados de interesse apenas nas tags pertencentes a tag
raiz body, que representa o corpo da página.

Figura 3.8: Exemplo de configuração e resposta do endpoint “/site”, corpo do request do


lado esquerdo e resposta do lado direito.

O endpoint ”/multisite” funciona de forma semelhante ào endpoint ”/site”, entre-


tanto recebe uma lista de configurações no formato da classe ScrapConfig e retorna
uma lista de objetos JSON definidos pela classe ScrapResponse. Este endpoint
instancia a classe AsyncScrapper e executa o método de scrap() para cada con-
figuração de site de forma assı́ncrona. Isto é realizado através do uso da função
gather() da biblioteca asyncio, que executa os métodos de forma concorrente e
retorna uma lista agregada com os resultados (Figura 3.9).

O endpoint ”/auto” recebe configurações no formato da classe AutoScrapConfig


e tem um funcionamento diferenciado em relação aos outros 2 endpoints. Neste end-
point o método scrap() da classe AutoScrapper recebe um dicionário de strings
( campo ”strings”, Figura 3.6 ) e encontra os seletores CSS no HTML da URL
base através da procura das tags HTML que contém o texto presente nos valores
desse dicionário. Caso o atributo ”list url” não seja definido, são retornados no
campo ”selectors” os seletores CSS encontrados dos elementos HTML que contém
os textos procurados, no formato ”full”( caminho completo do elemento HTML do

21
Figura 3.9: Código do endpoint “/multisite”, uso da função gather() para execução de
tarefas em concorrência.

body até o elemento final com suas classes) e ”last”( elemento final com suas clas-
ses), ver Figura 3.10 . Neste caso, a resposta deste endpoint é definido pela classe
AutoScrapResponse.

Figura 3.10: Exemplo de resposta do endpoint ”/auto” contendo seletores encontrados

Caso seja passado uma lista de URLs para o campo ”list url”, usa-se os seletores
CSS encontrados para realização do scrapping em tais sites chamando-se interna-
mente o endpoint ”/multisite” - de forma concorrente ao fazer-se uso da função
gather(). Isto é útil quando quer-se coletar dados de forma automatizada de várias
páginas no mesmo domı́nio que possuem a mesma estruturação dos elementos, tal
como em sites de notı́cias, supermercado, fóruns.

Quando o dado requerido encontra-se em uma tabela faz-se uma tratativa diferente
para se definir o elemento que contém o dado. Tendo em vista que colunas diferentes
da tabela podem possuir as mesmas classes, para que o seletor CSS do elemento de
interesse seja definido corretamente é determinado o ı́ndice da coluna correspondente

22
ao elemento, que é adicionado ao final dos seletores CSS encontrados através do
seletor de posição ”:nth-of-type”.

3.4 Instalação do Utilitário


Para fazer uso do programa deste trabalho deve-se inicialmente instalar o python 3
e o gerenciador de pacotes pip, disponı́veis em https://www.python.org/downloads/
e https://pip.pypa.io/en/stable/installing/ respectivamente. Pode-se verifi-
car se o python e o pip estão instalados corretamente executando o comando ”python
–version”e ”pip –version”no terminal, que retornarão as suas versões instaladas no
sistema, conforme Figura 3.11.

Figura 3.11: Verificação versão instalada do python e pip

Tem-se, então, duas formas de executar a aplicação: rodá-la diretamente do di-


retório do programa ou instalá-la no sistema. Para rodar a aplicação diretamente de
seu diretório deve-se executar o comando ”pip install requests-html pyppeteer fastapi
uvicorn pydantic”para instalar as bibliotecas necessárias e então abrir o terminal na
pasta onde o trabalho se encontra e executar o comando ”python aplicacao”(Figura
3.12).

Figura 3.12: Executando aplicação direto da pasta

23
Para instalar a aplicação no sistema deve-se abrir o terminal na pasta do traba-
lho e rodar o comando ”pip install .”, que instalará as bibliotecas necessárias para
execução do projeto automaticamente. Desse modo, a aplicação poderá ser inicia-
lizada de qualquer pasta pelo terminal executando o comando ”tcc-anor”( Figura
3.13 ).

Figura 3.13: Executando aplicação após instalação no sistema

O código-fonte está disponı́vel para download em :

ˆ https://github.com/anorneto/tcc_anor

3.5 Testes Realizados


Para averiguar o funcionamento da aplicação desenvolvida foram testados diversos
portais, com conteúdo estático e dinâmico. A relação dos sites testados e o tipo de
conteúdo de suas páginas pode ser visto na Tabela 3.1 .

Tabela 3.1: Relação Sites Testados


Site Link Tipo documento HTML
Normas Ministério
http://normas.receita.fazenda.gov.br/ Estático
da Fazenda
Consultas Anvisa https://consultas.anvisa.gov.br/ Dinâmico
Dados Abertos Governo https://dados.gov.br/ Estático
Destaques Diário
https://www.in.gov.br/servicos/diario-oficial-da-uniao/destaques-do-diario-oficial-da-uniao Dinâmico
Oficial União
Relatórios Controladoria
https://eaud.cgu.gov.br/relatorios/ Dinâmico
Geral da União
Data Rio https://www.data.rio/ Dinâmico
Portal da Transparência http://www.portaldatransparencia.gov.br/receitas/consulta Dinâmico
Investing https://br.investing.com/ Estático
Pão de Açucar https://www.paodeacucar.com/ Estático
StackOverflow https://stackoverflow.com/ Estático
Globo https://www.globo.com/ Estático

Os testes foram realizados utilizando a ferramenta Insomnia [32] - programa


cliente de APIs. Eles podem ser replicados importando no Insomnia o arquivo de

24
coleção de requests de nome ”Colecao Testes Insomnia.json” disponı́vel na pasta
”Testes” do projeto ( ver Figura 3.14 ).

Figura 3.14: Importando coleção de requests no Insomnia

Conforme explicado na Seção 3.2.2, as configurações de scrapping são definidas no


formato JSON e enviadas para API no corpo do request POST. Para os endpoints
”/site” e ”/multisite” define-se os seletores CSS no atributo ”selectors” do JSON
de configuração, no formato ”nomeCampo” : ”seletorCSS” ( ver Figura 3.15 ). A
explicação de como obter manualmente o seletor CSS do elemento de uma página
pode ser vista no Apêndice A.1, e uma lista com os principais seletores CSS pode
ser vista no Apêndice B.1.

Figura 3.15: Definindo seletores CSS no corpo do request POST para o endpoint ”/auto”

25
Para a descoberta do seletor CSS de um elemento através do uso do endpoint
”/auto”, deve-se enviar no JSON de configuração os textos dos elementos de interesse
no atributo ”strings”, no formato ”nomeCampo:” ”textoDoElemento” ( ver Figura
3.16). Caso seja passada uma lista de sites através do campo ”list url”, será realizada
a extração de dados dos sites dessa lista usando-se os seletores CSS descobertos no
site base - definido no atributo ”base url” ( Figura 3.17 ).

Figura 3.16: Definindo texto dos elementos de interesse no corpo do request POST para
o endpoint ”/auto”

Figura 3.17: Exemplo de retorno do endpoint ”/auto” quando atributo ”list url” é defi-
nido.

26
3.5.1 Sites com HTML estático

Conforme esperado, foi possı́vel extrair facilmente os dados de interesse de todos os


portais com conteúdo estático. Isto foi possı́vel usando os seletores CSS diretamente
através dos endpoints ”/site”e ”/multisite”, e também - na maioria dos casos - pela
descoberta do seletor CSS do elemento de interesse através do texto do elemento
passado para o endpoint ”/auto”.

Figura 3.18: Exemplo de uso dos seletores CSS no endpoint ”/site”.

Figura 3.19: Exemplo de descoberta automática dos seletores CSS através do texto do
elemento no endpoint ”/auto”.

O endpoint ”/auto” nem sempre retorna resultados satisfatórios, pois o elemento


que contém o dado de interesse pode conter classes incomuns que não funcionam
como um seletor CSS ( Figura 3.20 ) ; ou porque o texto escolhido está presente
em diferentes elementos pela página, inviabilizando a descoberta do seletor CSS cor-
reto. A descoberta do seletor CSS correto a partir do texto do elemento em tabelas

27
também fica impossibilitada quando a célula da tabela é composta por diversos ele-
mentos, como no caso do site do ’Ministério da Fazenda’ onde o texto de uma célula
está dividido entre três elementos ”div” ( Figura 3.21).

Figura 3.20: Exemplo de erro no endpoint ”/auto”, elemento possui classe mobile:mb-2
que não pode ser usada como seletor CSS.

Figura 3.21: Site do ’Ministério da Fazenda’ - texto de uma célula da tabela está divido
entre três elementos .

Ademais, devido a natureza de estruturação em árvore dos elementos no docu-


mento HTML e da grande quantidade de elementos em uma página, a pesquisa por
textos dentro do documento mostra-se demorada frente ao uso direto dos seletores

28
CSS. Observou-se aumentos de até 14 vezes no tempo de execução dos scrappers
entre o endpoint ”/site” e ”auto” , como pode ser visto na Tabela 3.2. Dependo do
uso desta função pela aplicação cliente, o aumento de tempo observado pode não
ser um problema caso a aplicação não dependa de troca de dados em tempo real.

Tabela 3.2: Comparação de tempo entre os endpoints ”/site” e ”auto”


Tempo scrapping Tempo descoberta
Site de Teste Aumento de Tempo
seletor CSS - endpoint ”/site” seletor CSS - endpoint ”/auto”
StackOverflow 510 ms 4,6 s + 910 %
Normas Ministerio da Fazenda 1,15 s 16.3 s + 1417 %
Globo 390 ms 5,54 s + 1420 %

3.5.2 Sites com HTML dinâmico

Como mencionado anteriormente na seção 3.3, para extração de dados de páginas


com conteúdo dinâmico é necessária a renderização da página em um navegador
em segundo plano. Tal fato resulta em um aumento significativo para realização do
scrapping do site, o projeto está configurado para esperar ao menos 6 segundos antes
de iniciar o processo de extração dos dados - este tempo foi definido empiricamente
para assegurar que o navegador em segundo plano tenha tempo de terminar de
renderizar o HTML da página.

Dependendo dos scripts utilizados no site para manipulação do documento HTML


ou do uso de algum framework Javascript que constrói o body do documento HTML
inteiro, o programa desenvolvido neste projeto não consegue realizar o processo de
scrapping. A página do ’Portal da Transparência’, por exemplo, não retorna dados
pois o navegador em segundo plano não consegue renderizar as tabelas com os dados,
e a página do ’Data Rio’ algumas vezes não consegue ser carregada dado que ela é
toda construı́da por um framework Javascript.

Nos demais sites testados com conteúdo dinâmico foi possı́vel extrair os dados de
interesse normalmente ( Figura 3.22 ), tendo como único ponto negativo a demora
para realização do processo. O tempo médio para realização de scrapping em páginas
com conteúdo dinâmico foi cerca de 10 segundos, chegando a pouco mais de 13
segundos em alguns casos, como no portal do ’Diário Oficial da União’.

29
Figura 3.22: Exemplo de extração de dados de página com conteúdo dinâmico

3.5.3 Testes Adicionais

Foi testado o comportamento da API desenvolvida no caso de requisições con-


correntes usando-se a ferramenta ab [33] no endpoint ”/site” com o arquivo de
configuração ”configuracao teste.json” disponı́vel na pasta ”Testes” do projeto. O
teste foi executado com cem requisições e N requisições simultâneas. Foi observado
um aumento significativo, aproximando-se da linearidade, no tempo de resposta da
API frente ao aumento da quantidade de requets simultâneos, como pode ser visto
na Tabela 3.3.

Quantidade de requets simultâneas Média de tempo (s) da resposta


1 0.4
10 2.92
25 6.4
50 13.2
100 22

Tabela 3.3: Média de tempo por requests simultâneos.

30
Site de Teste Tempo médio API - endpoint ”/site” Tempo médio Octoparse
Globo 532 ms 1.1 s
StackOverflow 758 ms 1.8 s
Anvisa 9.8 s 1.42 m
Dados Governo 2.11 s 27 s

Tabela 3.4: Comparação da média de tempo para realização do processo de scrapping


entre a API desenvolvida e a solução comercial Octoparse.

Comparando-se o tempo médio de cinco execuções do processo de scrapping da


API desenvolvida com o plano gratuito da solução comercial Octoparse [27], percebe-
se que a API possui uma performance superior. A discrepância no tempo de execução
é expressiva (Tabela 3.4), principalmente no site da ”Anvisa”, que, como exposto
anteriormente, é um site com conteúdo dinâmico e que precisa ser renderizado em
segundo plano antes da realização do processo de web scrapping.

31
Capı́tulo 4

Conclusão

4.1 Conclusão
Conforme apresentado no Capı́tulo 1.4, o objetivo deste trabalho foi criar uma in-
terface genérica para Web Scrapping que consiga extrair dados de diferentes fontes,
independente de codificações no programa especı́ficas para cada site. Foram apre-
sentadas alternativas comerciais que solucionam o problema da coleta automatizada
de dados da Internet (Capı́tulo 2.1 ), e algumas open-source que se assemelham a
este trabalho. Entretanto, dentre as soluções de código aberto não se tem nenhum
projeto que ofereça uma API para Web Scrapping nem que permita a realização do
Web Scrapping de forma dinâmica e programática.

Ao criar uma API que recebe requisições configuráveis de forma assı́ncrona para
realização de extração de dados da Internet e retorna respostas simples no formato
JSON, este trabalho atendeu todos os objetivos propostos. A criação de um endpoint
para scrapping automático facilita a descoberta dos seletores CSS corretos para os
dados de interesse e, junto da possibilidade da API receber vários links em uma
única requisição, agiliza o processo de extração de dados. O uso de polimorfismo e
herança na criação dos Scrappers agilizou o processo de desenvolvimento e manu-
tenção do projeto, e possibilita e inclusão de novos Scrappers e funcionalidades de
forma simples.

A coleta de dados de páginas dinâmicas mostrou-se como o maior desafio do


projeto, dada a necessidade de renderização prévia do HTML da página por um

32
navegador em segundo plano - introduzindo grandes acrescimentos de tempo no
processo de coleta dos dados. Apesar de funcional em casos simples, a renderização
em segundo plano de sites dinâmicos mostrou-se inconsistente visto que não é total-
mente funcional, principalmente nos casos em que a página é totalmente construı́da
no navegador no momento do acesso por frameworks Javascripts.

4.2 Pontos passı́veis de melhoria


Com a realização dos testes de funcionamento da aplicação desenvolvida ( capı́tulo
3.5 ) foram encontrados os seguintes pontos passı́veis de melhorias :

1. Tempo de execução do AutoScrapper

2. Inconsistência na renderização de páginas dinâmicas

Para o primeiro problema pode-se averiguar a possibilidade e o impacto do uso


de multithreading ou multiprocessamento no algoritmo de pesquisa de texto dentro
de elementos do documento HTML. Para o segundo problema é possı́vel o estudo
de outras soluções para renderização do HTML de páginas dinâmicas, sendo uma
delas o uso da biblioteca PyQt ( possui WebKit como parte de seus componentes )
e a outra o uso do projeto Splash - disponibiliza um navegador como serviço através
de uma API.

Outra possı́vel melhoria ao projeto seria a adição de um banco de dados, preferen-


cialmente NoSQL em virtude das informações serem não estruturadas, para possibi-
litar o armazenamento dos dados obtidos do scrapping, das configurações enviadas
à API, cacheamento de dados para os Requests mais demorados, etc. Ademais, a
elaboração de um método genérico para busca de dados em páginas referenciadas
por links dentro da página em que se está extraindo o dado de interesse também
mostra-se como um possı́vel trabalho futuro.

33
Referências Bibliográficas

[1] “portia”, https://github.com/scrapinghub/portia, (Acesso em 10 Fevereiro


2021).

[2] “Gizmodo”, https://gizmodo.uol.com.br, (Acesso em 18 Janeiro 2021).

[3] “Anvisa”, https://consultas.anvisa.gov.br/medicamentos/q/?nomeProduto=IBuprofeno,


(Acesso em 6 Junho 2021).

[4] DIGITAL, O., “Dados mostram o crescimento impressionante da internet em


10 anos”, https://olhardigital.com.br/2019/05/17/noticias/dados-mostram-o-
crescimento-impressionante-da-internet-em-10-anos/, 2020, (Acesso em 5 De-
zembro 2020).

[5] CHANG, C.-H., KAYED, M., GIRGIS, M. R., et al., “A Survey of Web In-
formation Extraction Systems”, IEEE TRANSACTIONS ON KNOWLEDGE
AND DATA ENGINEERING, v. 18, pp. 1411 – 1428, 2006.

[6] “INTERNET USAGE STATISTICS”, https://www.internetworldstats.com/stats.htm,


2020, (Acesso em 18 Dezembro 2020).

[7] KEMP, S., “DIGITAL 2020: GLOBAL DIGITAL OVERVIEW”,


https://datareportal.com/reports/digital-2020-global-digital-overview, 2020,
(Acesso em 18 Dezembro 2020).

[8] W3C, “Data on the Web Best Practices”,


https://www.w3.org/TR/dwbp/intro, 2020, (Acesso em 18 Dezembro 2020).

[9] LYSEGGENU, J., Outside Insight: Navigating a World Drowning in Data.


Ideapress Publishingn, 2017.

34
[10] FAYZRAKHMANOV, R. R., SALLINGER, E., SPENCER, B., et al., “Brow-
serless Web Data Extraction: Challenges and Opportunities”, WWW ’18: Pro-
ceedings of the 2018 World Wide Web Conference, pp. 1095 – 1104, 20018.

[11] MOZILLA, “HTML: HyperText Markup Languages”,


https://developer.mozilla.org/en-US/docs/Web/HTML, (Acesso em 15
Janeiro 2021).

[12] MOZILLA, “CSS: Cascading Style Sheets”, https://developer.mozilla.org/en-


US/docs/Web/CSS, (Acesso em 15 Janeiro 2021).

[13] MOZILLA, “JavaScript”, https://developer.mozilla.org/en-


US/docs/Web/JavaScript, (Acesso em 15 Janeiro 2021).

[14] ISKANDAR, T. F., LUBIS, M., KUSUMASARI, T. F., et al., “Comparison


between client-side and server-side rendering in the web development”, IOP
Conference Series: Materials Science and Engineering, v. 801, pp. 012136, 2020.

[15] “pyppeteer”, https://github.com/miyakogi/pyppeteer, (Acesso em 10 Fevereiro


2021).

[16] MASSE, M., REST API Design Rulebook: Designing Consistent RESTful Web
Service Interfaces. O’Reilly Media, 2011.

[17] SCHRENK, M., Webbots, Spiders, and Screen Scrapers: A Guide to Developing
Internet Agents with PHP/CURL. No Starch Press, 2007.

[18] VARGIU, E., URRU, M., “Exploiting web scraping in a collaborative filtering-
based approach to web advertising”, Artificial Intelligence Research, v. 2, 2013.

[19] T, K., SEKARAN, K., D., R., et al., “Personalized Content Extraction and
Text Classification Using Effective Web Scraping Techniques”, International
Journal of Web Portals, v. 11, 2019.

[20] “scrapy”, https://scrapy.org, (Acesso em 10 Fevereiro 2021).

[21] “pyspider”, https://github.com/binux/pyspider, (Acesso em 10 Fevereiro


2021).

35
[22] “Requests-HTML”, https://requests.readthedocs.io/projects/requests-
html/en/latest/, (Acesso em 10 Fevereiro 2021).

[23] PALACH, J., Parallel Programming with Python: Develop Efficient Parallel
Systems Using the Robust Python. Packt Publishing, 2014.

[24] “GlobalInterpreterLock”, https://wiki.python.org/moin/GlobalInterpreterLock,


(Acesso em 22 Janeiro 2021).

[25] “asyncio”, https://docs.python.org/3/library/asyncio.html, (Acesso em 10 Fe-


vereiro 2021).

[26] “Coroutines and Tasks”, https://docs.python.org/3/library/asyncio-task.html,


(Acesso em 22 Janeiro 2021).

[27] “octoparse”, https://www.octoparse.com/, (Acesso em 10 Fevereiro 2021).

[28] “parsehub”, https://www.parsehub.com/, (Acesso em 10 Fevereiro 2021).

[29] “scrappingbot”, https://www.scraping-bot.io/, (Acesso em 10 Fevereiro 2021).

[30] “webscrapper”, https://webscraper.io, (Acesso em 10 Fevereiro 2021).

[31] “fastapi”, https://fastapi.tiangolo.com/, (Acesso em 10 Fevereiro 2021).

[32] “Insomnia”, https://insomnia.rest/download, (Acesso em 17 Abril 2021).

[33] “ab - Apache HTTP server benchmarking tool”,


https://httpd.apache.org/docs/2.4/programs/ab.html, (Acesso em 7 Ju-
lho 2021).

36
Apêndice A

Obtendo seletor CSS de um


elemento

A.1 Obtendo seletor CSS de um elemento


Os navegadores modernos permitem de forma rápida e fácil a obtenção do seletor
CSS correto correspondente ao elemento de interesse na página. O passo-a-passo a
seguir foi realizado utilizando o navegador Google Chrome, mas o procedimento é
basicamente o mesmo nos demais navegadores existentes.

Primeiramente, deve-se clicar com o botão direito nos dados de interesse da página
e selecione ”Inspecionar”( Figura A.1 ). Tal comando abrirá a janela de desenvolvi-
mento do navegador na aba ”Elementos”, exibindo o código fonte da página com o
elemento requerido selecionado.

Em seguida, clica-se com o botão direito no código do elemento HTML e seleciona-


se o comando ”Copiar >Copiar Seletor”, que irá copiar para área de transferência
o seletor CSS referente ao elemento ( Figura A.2 ). No caso do exemplo mostrado o
seletor é :

#containerTable > table > tbody > tr:nth-child(2) > td.col-xs-2.ng-binding

37
Figura A.1: Descobrindo elemento HTML de interesse [3]

Figura A.2: Copiando o seletor CSS do elemento HTML

38
Apêndice B

Informações Complementares

B.1 Principais Seletores CSS

Tabela B.1: Principais seletores CSS


Seletor Exemplo Descrição
.class .intro Seleciona todos os elementos com class=”intro”
#id #firstname Seleciona o elemento com id=”firstname”
* * Seleciona todos os elementos
elemento p Seleciona todos <p>
elemento, elemento div, p Seleciona todos <div>e todos elementos <p>
elemento elemento div p Seleciona todos elementos <p>dentro de elementos <div>
elemento >elemento div >p Seleciona todos <p>onde o pai é um elemento <div>
elemento+elemento div + p Seleciona todos <p>que estão imediatamente depois de um elemento <div>
elemento1 ∼elemento2 p ∼ul Seleciona todo elemento <ul>que precede um elemento <p>
[attribute] [target] Seleciona todos os elementos com um atributo target
[attribute=value] [target= blank] Seleciona todos os elementos com target=” blank”
[attribute∼=value] [title∼=flower] Seleciona todos os elementos com um atributo title contendo a palavra ”flower”
[attribute—=value] [lang—=pt-br] Seleciona todos os elementos com um atributo lang, cujo valor do atributo comece com ”pt-br”
[attributeˆ=value] a[hrefˆ=”https”] Seleciona todo elemento <a>que tem um atributo href com o valor começando com ”https”
[attribute$=value] a[href$=”.pdf”] Seleciona todo elemento <a>que tem um atributo href com o valor terminando com ”.pdf”
[attribute*=value] a[href*=”tableless”] Seleciona todo elemento <a>que tem um atributo href com o valor contendo ”tableless”
:empty p:empty Seleciona todo elemento <p>que não tem filhos, incluindo texto
:first-child p:first-child Seleciona todo elemento <p>que é o primeiro filho do seu pai
::first-letter p::first-letter Seleciona a primeira letra de todo elemento <p>
::first-line p::first-line Seleciona a primeira linha de todo elemento <p>
:first-of-type p:first-of-type Seleciona todo elemento <p>que é o primeiro filho do seu pai
:last-child p:last-child Seleciona todo elemento <p>que é o último filho de seu pai
:last-of-type p:last-of-type Seleciona todo elemento <p>que é o último elemento do tipo <p>do seu pai
:not(Seletor) :not(p) Seleciona todo elemento elemento que não é um elemento <p>
:nth-child(n) p:nth-child(2) Seleciona todo elemento <p>que é o segundo filho do seu pai
:nth-last-child(n) p:nth-last-child(2) Seleciona todo elemento <p>que é o segundo filho do seu pai, contando com o último filho
:nth-last-of-type(n) p:nth-last-of-type(2) Seleciona todo elemento <p>que é o segundo <p>do seu pai

39

Você também pode gostar