Ingestão de Dados com Web Scraping
Tags: python, learning, dataengineering, datascience
Published: 2023-07-10 21:31:55

Web scraping é uma técnica de extração de dados da web usando um programa ou script para automatizar o processo. É uma forma de coletar informações de sites de forma estruturada, acessando o código HTML das páginas e extraindo os dados desejados. 

Essa ferramenta é valiosa no mundo da Engenharia de Dados, pois permite a obtenção e transformação de dados da web em formatos adequados para análise, integração em sistemas e aplicativos, pesquisa de mercado e monitoramento de informações relevantes. 

Este projeto que decidi compartilhar hoje foi parte da minha experiência cursando o [Bootcamp de Engenharia de Dados](https://howedu.com.br/cohort/engenharia-de-dados/) da How Bootcamps realizado com o auxílio dos facilitadores Rhuan Lima e Rafael Roberto Dias para aprender um pouco mais sobre essa poderosa ferramenta aliada de quem trabalha na área de dados.


![Ilustração com fluxo de página web para web scraping para banco de dados](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jprfaa9ut2awbrvubjvd.png)


## Objetivo do projeto

O objetivo desse primeiro projeto foi conseguir realizar a ingestão de dados a partir do site Viva Real para obter uma base com todos os imóveis à venda em Jacarepaguá utilizando apenas código em Python sem o uso de APIs.

Foi feita uma primeira camada de captura dessas informações através do Google Inspect utilizando a biblioteca Beautiful Soup e Requests modificando ao mínimo os dados. Posteriormente, a ideia é realizar uma segunda camada tratando esses dados com Pandas para análises.

O objetivo, que foi concluído com sucesso, foi de importar todas as informações do site para um arquivo .csv e .xlsx utilizando o código em um virtual environment criado para o projeto.

Um projeto simples, porém satisfatório de fazer por fornecer skills úteis e um banco de dados que pode ser utilizado para projetos futuros.

## Código do projeto

As bibliotecas utilizadas no projeto, como citado anteriormente, foram Pandas, Beautiful Soup e Requests.

```
import requests
from bs4 import BeautifulSoup as bs
import pandas as pd
```
Realizada a importação das bibliotecas, foi feita uma leitura da URL da região específica de onde os dados serão capturados com uma variável i que varia de acordo com a página acessada pelo script e feito um `request `armazenando o resultado em uma variável `soup`.

```
url = 'https://www.vivareal.com.br/venda/rj/rio-de-janeiro/zona-oeste/jacarepagua/?pagina={}'
i = 1
ret = requests.get(url.format(i))
soup = bs(ret.text)
```
Para se certificar que houve uma captura completa dos dados, verifica-se o total de imóveis recebidos via `request `utilizando `soup.find` na classe referente a essa informação.

```
qtd_imoveis = soup.find(
    'strong', {'class': 'results-summary__count js-total-records'})
# Removendo o ponto no número total de imóveis e transformando em float
qtd_imoveis = float(qtd_imoveis.text.replace('.', ''))
```
Logo, é criado o data frame que receberá todas as informações.

```
df = pd.DataFrame(
    columns=[
        'descricao',
        'endereco',
        'area',
        'quartos',
        'wc',
        'vagas',
        'valor',
        'condominio',
        'wlink'
    ]
)
```
Com o df criado, realiza-se um loop utilizando o total de imóveis comparando com o tamanho do df fazendo `while qtd_imoveis > df.shape[0]` e um segundo loop para para passar por todos os imóveis das páginas.

Para cada um dos itens pode dar um erro por falta de valores - por exemplo, imóveis que não tem valor de condomínio no card não vão retornar um valor para variável `condomínio` - e a forma de resolver isso é utilizando `try` e `except` para indicar o que fazer quando não é encontrado um valor desejável.

```
i = 0

while qtd_imoveis > df.shape[0]:
    print(f"Valor i: {i} \t\t qtd_imoveis: {df.shape[0]}")
    i = i+1
    ret = requests.get(url.format(i))
    soup = bs(ret.text, features="lxml")
    houses = soup.find_all(
        'a', {'class': 'property-card__content-link js-card-title'})

    for house in houses:  

        # Capturando os dados dos imóveis
        try:
            # Capturando a descrição no site
            descricao = house.find(
                'span', {'class': 'property-card__title js-cardLink js-card-title'}).text
            descricao = descricao.strip()  # Removendo os espaços
        except:
            descricao = None

        # Realizar o mesmo procedimento para os outros dados desejados
        try:
            endereco = house.find(
                'span', {'class': 'property-card__address'}).text.strip()
        except:
            endereco = None
        try:
            area = house.find(
                'span', {'class': 'js-property-card-detail-area'}).text.strip()
        except:
            area = None
        try:
            # Pegando apenas o span do texto para capturar apenas o número
            quartos = house.find(
                'li', {'class': 'js-property-detail-rooms'}).span.text.strip()
        except:
            quartos = None
        try:
            wc = house.find(
                'li', {'class': 'js-property-detail-bathroom'}).span.text.strip()
        except:
            wc = None
        try:
            vagas = house.find(
                'li', {'class': 'js-property-detail-garages'}).span.text.strip()
        except:
            vagas = None
        try:
            valor = house.find(
                'div', {'class': 'property-card__price'}).p.text.strip()
        except:
            valor = None
        try:
            condominio = house.find(
                'strong', {'class': 'js-condo-price'}).text.strip()
        except:
            condominio = None
        try:
            wlink = 'https://www.vivareal.com.br' + house['href']
        except:
            wlink = None

        df.loc[df.shape[0]] = [
            descricao,
            endereco,
            area,
            quartos,
            wc,
            vagas,
            valor,
            condominio,
            wlink
        ]
```
Por fim, é gerado um arquivo .csv com o banco de dados armazenado na variável `df` para um arquivo imoveis_jacarepagua.csv.

```
df.to_csv('imoveis_jacarepagua.csv', sep=';', index=False)
```

**Resultado final**:
![Resultado final do dataframe com as colunas e linhas desejadas](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1ddyhh5vwzhu54osj6hp.png)

Link do GitHub para o código: https://lnkd.in/dSemzQ52