/crawler

Node JS + MySQL

Primary LanguageJavaScriptMIT LicenseMIT

mit-license node-version

Projeto Crawler

  • 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.

Link do site

Sumário

Licença

Este projeto está sob licença do MIT.

Tecnologias Utilizadas

Instruções para rodar o projeto

Será necessário ter instalado na sua máquina:

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

.env

  • 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 |
+----+--------------------------------------------+-------+-------------+----------+---------------------+---------------------+

Organização e estruturação do projeto

Arquitetura MSC

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

SOLID

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.

REST API

GET /

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.

Desenvolvimento

Fetch

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>

Filtragem de dados

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.

Higienização dos dados

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.

Banco de dados

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.

Validações

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.

Testes

API

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                 
------------------------|---------|----------|---------|---------|-------------------