- Trata-se de um projeto com o objetivo de realizar a busca em um site que exibe o CPF de candidatos aprovados, e ao clicar em cada CPF, é exibido o nome e a nota do candidato. Esta busca consiste em capturar cada número de CPF, nome e nota de todos os candidatos. O site é dividido em aproximadamente 5 mil páginas, contendo 10 candidatos em cada uma delas, finalizando num total de aproximadamente 50 mil candidatos.
- Licença
- Tecnologias utilizadas
- Instruções para rodar o projeto
- Organização e estruturação do projeto
- REST API
- Desenvolvimento
- Testes
Este projeto está sob licença do MIT.
Git
MySQL
Node v16.13.0
- Clone o repositório com o comando git clone:
git clone git@github.com:danielbped/crawler.git
- Entre no diretório que acabou de ser criado:
cd crawler
- Para o projeto funcionar na sua máquina, será necessário instalar suas dependências, para isso, utilize o comando npm install:
npm install
- Para testes locais, é fundamental configurar um arquivo de variáveis de ambiente .env na raiz do projeto, este arquivo deverá possuir as seguintes informações:
MYSQL_USER=root
MYSQL_PASSWORD=password
HOSTNAME=localhost
PORT=3000
PAGE=1
⚠️ Por padrão, a busca irá da página 1 até a última página, caso queira alterar a página de início, é só informar na variável PAGE⚠️
⚠️ Lembre de trocar 'root' pelo seu nome de usuário no MySQL, e 'password' pela sua senha⚠️
- Pronto, agora o projeto está pronto para ser rodado localmente, utilizando o comando npm start:
npm start
- Para visualizar o funcionamento da aplicação no navegador, é só acessar o
localhost:3000
⚠️ 3000 ou na porta que foi informada na variável PORT⚠️
- E para visualizar como as informações ficaram salvas no banco de dados é só seguir os seguinte passos no terminal:
mysql -uroot -p
Digitar a sua senha (A mesma que foi informada na variável MYSQL_PASSWORD)
SHOW DATABASES;
USE CRAWLER;
SHOW TABLES;
SELECT * FROM Candidates;
- O resultado será parecido com o seguinte:
+----+--------------------------------------------+-------+-------------+----------+---------------------+---------------------+
| id | name | score | CPF | validCPF | createdAt | updatedAt |
+----+--------------------------------------------+-------+-------------+----------+---------------------+---------------------+
| 1 | ANTHONY KING | 85.38 | 87645213035 | 1 | 2022-01-26 14:25:42 | 2022-01-26 14:25:42 |
| 2 | ANNE CRAWFORD I II III IV V MD DDS PHD DVM | 72.03 | 87650413217 | 1 | 2022-01-26 14:25:42 | 2022-01-26 14:25:42 |
| 3 | DAVID GONZALEZ | 94.53 | 87650123480 | 1 | 2022-01-26 14:25:42 | 2022-01-26 14:25:42 |
| 4 | PHYLLIS RIVERA | 82.34 | 87650132471 | 1 | 2022-01-26 14:25:42 | 2022-01-26 14:25:42 |
| 5 | JEREMY FREEMAN | 72.85 | 87651023471 | 1 | 2022-01-26 14:25:42 | 2022-01-26 14:25:42 |
| 6 | JOYCE BAKER I II III IV V MD DDS PHD DVM | 96.01 | 87651034244 | 1 | 2022-01-26 14:25:42 | 2022-01-26 14:25:42 |
| 7 | MR DR LOUIS WILLIAMS | 72.94 | 87651043235 | 1 | 2022-01-26 14:25:42 | 2022-01-26 14:25:42 |
| 8 | RICHARD PERRY | 88.15 | 87651204344 | 1 | 2022-01-26 14:25:42 | 2022-01-26 14:25:42 |
| 9 | MARK KNIGHT | 98.45 | 87651230426 | 1 | 2022-01-26 14:25:42 | 2022-01-26 14:25:42 |
| 10 | SHAWN BAKER | 91.34 | 87652013453 | 1 | 2022-01-26 14:25:42 | 2022-01-26 14:25:42 |
+----+--------------------------------------------+-------+-------------+----------+---------------------+---------------------+
Este projeto foi desenvolvido utilizando a arquitetura MSC, que consiste em separar os arquivos por pastas de Models, Services e Controllers, dividindo, assim, as responsabilidades das funções, tornando o código mais limpo e organizado.
Desta forma, o projeto está organizado e estruturado da seguinte forma:
├── .env
├── .README.md
├── api
├── index.js
├── server.js
├── config
├── config.js
├── controllers
├── getCandidates.js
├── root.js
├── middlewares
├── error.js
├── migrations
├── XXXXXXXXXXXXXX-create-user
├── models
├── candidate.js
├── index.js
├── services
├── getCandidates.js
├── populateCandidates.js
├── tests
├── getCandidatesApi.test.js
├── utils
├── errorMessages.js
├── filters.js
├── Regex.js
├── validations.js
Para o desenvolvimento, também foram utilizados alguns princípios SOLID. SOLID é um acrônimo para cinco princípois, os quais são:
- Single responsability principle (Princípio da responsabilidade única)
- Open/Closed principl (Princípio aberto/fechado)
- Liskov substitution principle (Princípio de substituição de Liskov)
- Interface segregation principle (Princípio da segregação da interface)
- Dependency inversion principle (Princípio da inversão da dependência)
Os princípios utilizados aqui foram os de responsabilidade única, aberto/fechado e inversão de dependência, mas o que cada um deles representa de fato?
- Princípio da responsabilidade única: Uma função deve ter uma, e apenas uma, tarefa a realizar dentro do código.
- Princípio aberto/fechado: O comportamento de uma função deve ser extensível sem que precise modificar seu comportamento anterior.
- Princípio da inversão de dependência: Quem chama uma função deve ser capaz de determinar quais outros módulos ela usa em sua lógica.
Para saber mais sobre os princípios SOLID, acesse este link.
Para realizar a busca de todos os candidatos, a requisição não necessita de body nem headers, e a resposta terá um status 200 (OK), e será um array parecido com o seguinte:
[
{
"id": 1,
"name": "ANTHONY KING",
"score": "85.38",
"CPF": "87645213035",
"validCPF": true
},
{
"id": 2,
"name": "ANNE CRAWFORD I II III IV V MD DDS PHD DVM",
"score": "72.03",
"CPF": "87650413217",
"validCPF": true
},
]
-
Caso haja algum problema com a requisição, surgirá uma mensagem de erro:
-
Status 500 (INTERNAL_SERVER_ERROR):
- Internal Server Error. Try again.
-
Para realizar o fetch no site dos candidatos, foi utilizado o client HTTP Axios, obtendo como resposta uma string com o conteúdo HTML da página, parecida com a seguinte:
<html>
<h1>
Approved candidates (all data is fake)
</h1>
<li><a href="/candidate/178.422.117-11">178.422.117-11</a></li>
<li><a href="/candidate/012.346.857-44">012.346.857-44</a></li>
...
<div><a href="/approvals/2">Next page</a></div>
</html>
Para filtrar os dados obtidos, e recuperar apenas o CPF dos candidatos, foram utilizadas as expressões regulares (RegEx). O RegEx também foi utilizado para, ao acessar cada CPF, recuperar apenas o nome e a nota de cada candidato.
Tendo realizado as filtragens, foi necessário realizar uma higienização nos dados, pois mesmo após filtrar os dados com o RegEx, alguns dados ainda ficam com resquícios do HTML. Feito isso, mais algumas alterações foram feitas, como:
- Remover acentuações, pontuações e caracteres especiais.
- Deixar todas as letras dos nomes dos candidatos em maiúsculo.
Após a higienização, é a hora de conectar e inserir os dados no banco de dados. O banco de dados utilizado foi o MySQL, um banco de dados relacional, utilizando a ORM Sequelize.
Algumas funções de valiação foram necessárias, tanto como validar se o CPF é válido quanto para verificar se o CPF já existe no banco de dados, não permitindo a inserção de CPFs repetidos.
Para realizar os testes da resposta da requisição da API, foi utilizada as bibliotecas Chai e Mocha, com 95% de cobertura.
------------------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
------------------------|---------|----------|---------|---------|-------------------
All files | 95.27 | 68.42 | 92.59 | 96.55 |
api | 100 | 100 | 100 | 100 |
index.js | 100 | 100 | 100 | 100 |
config | 100 | 100 | 100 | 100 |
config.js | 100 | 100 | 100 | 100 |
controllers | 94.11 | 100 | 100 | 94.11 |
getCandidates.js | 90.9 | 100 | 100 | 90.9 | 19
root.js | 100 | 100 | 100 | 100 |
middlewares | 83.33 | 100 | 50 | 83.33 |
error.js | 83.33 | 100 | 50 | 83.33 | 5
models | 91.66 | 66.66 | 100 | 91.66 |
candidate.js | 100 | 100 | 100 | 100 |
index.js | 90 | 66.66 | 100 | 90 | 13,30
services | 100 | 75 | 100 | 100 |
getCandidates.js | 100 | 83.33 | 100 | 100 | 16
populateCandidates.js | 100 | 50 | 100 | 100 | 11
utils | 93.75 | 50 | 91.66 | 100 |
Regex.js | 100 | 100 | 100 | 100 |
errorMessages.js | 100 | 100 | 100 | 100 |
filters.js | 100 | 100 | 100 | 100 |
validations.js | 83.33 | 50 | 83.33 | 100 | 9
------------------------|---------|----------|---------|---------|-------------------