matheus__serpa

MatheusSerpaRaspagem

May 30th, 2023
1,057
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.54 KB | Source Code | 0 0
  1. # This script was written by Matheus S. Serpa
  2.  
  3. import pandas as pd
  4. import numpy as np
  5. import requests
  6.  
  7. from bs4 import BeautifulSoup
  8. from datetime import datetime
  9.  
  10. import logging
  11.  
  12. logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(message)s")
  13. logger = logging.getLogger(__name__)
  14.  
  15. # Raspagem de dados de cotações de commodities agrícolas como soja, milho, café, etc.
  16. BASE_URL = "https://www.noticiasagricolas.com.br/cotacoes/"
  17. CROPS_LINK = {
  18.     "Soja": "soja/soja-mercado-fisico-sindicatos-e-cooperativas",
  19.     "Trigo": "trigo/trigo-mercado-fisico",
  20.     "Milho": "milho/milho-mercado-fisico-sindicatos-e-cooperativas",
  21. }
  22. TABLE_COLUMNS = 3
  23.  
  24.  
  25. def extract_data(base_url: str, links: dict, columns: int) -> pd.DataFrame:
  26.     """
  27.    Extracts commodity prices data from noticiasagricolas.com.br
  28.  
  29.    Args:
  30.        base_url (str): Base URL of the website
  31.        links (dict): Dictionary of commodities links
  32.        columns (int): Number of columns in the prices table
  33.  
  34.    Returns:
  35.        pd.DataFrame: Dataframe containing the places and prices data
  36.    """
  37.     df = pd.DataFrame()
  38.  
  39.     for crop, link in links.items():
  40.         url = base_url + link
  41.  
  42.         # Acessa a página e obtém todo conteúdo HTML
  43.         try:
  44.             response = requests.get(url)
  45.             response.raise_for_status()
  46.             html_page = response.text
  47.         except requests.exceptions.RequestException:
  48.             logging.exception(f"Não foi possível acessar a página: {url}")
  49.             continue
  50.  
  51.         # Realiza o parser e busca pela tabela de cotações
  52.         try:
  53.             soup = BeautifulSoup(html_page, "html.parser")
  54.             table_data = soup.find("table", {"class": "cot-fisicas"}).find_all(
  55.                 "td"
  56.             )
  57.         except Exception:
  58.             logging.exception(
  59.                 "Não foi possível encontrar a tabela de cotações"
  60.             )
  61.             continue
  62.  
  63.         # Obtém o nome de todas praças / locais
  64.         places = []
  65.         PLACE_COLUMN = 0
  66.         for element in range(PLACE_COLUMN, len(table_data), columns):
  67.             places.append(table_data[element].text)
  68.  
  69.         # Obtém o preço / quotações de todas praças / locais
  70.         prices = []
  71.         PRICE_COLUMN = 1
  72.         for element in range(PRICE_COLUMN, len(table_data), columns):
  73.             prices.append(table_data[element].text)
  74.  
  75.         # Cria um dataframe com os dados obtidos
  76.         data = {"place": places, "price": prices}
  77.  
  78.         df_crop = pd.DataFrame(data)
  79.  
  80.         # Ajusta o formato da moeda e do nome da cultura
  81.         df_crop["crop"] = crop
  82.         df_crop["currency"] = "BRL"
  83.  
  84.         # Adiciona o dataframe da cultura atual ao dataframe geral
  85.         df = pd.concat([df, df_crop])
  86.  
  87.     return df
  88.  
  89.  
  90. # Limpeza dos dados para adequar ao formato brasileiro e também ajustar tipos dos dados
  91. def data_cleaning(df: pd.DataFrame) -> pd.DataFrame:
  92.     """
  93.    Clean data to adjust to Brazilian format and also adjust data types.
  94.  
  95.    Args:
  96.        df: The DataFrame containing the prices and places.
  97.  
  98.    Returns:
  99.        pd.DataFrame: Cleaned DataFrame.
  100.    """
  101.     # Ajusta o formato do preço
  102.     df["price"] = df["price"].str.replace(",", ".")
  103.     df["price"] = df["price"].apply(
  104.         lambda x: np.nan if x == "s/ cotação" else x
  105.     )
  106.     df["price"] = df["price"].astype(float)
  107.  
  108.     # Remove linhas com valores nulos
  109.     df = df.dropna().reset_index(drop=True)
  110.  
  111.     return df
  112.  
  113.  
  114. def save_data(df: pd.DataFrame, now_str: str) -> bool:
  115.     """
  116.    Save the data to a CSV file.
  117.  
  118.    Args:
  119.        df: The DataFrame containing the prices and places.
  120.        now_str: The current date and time string in the format 'YYYY-MM-DD_HH-MM-SS'.
  121.  
  122.    Returns:
  123.        A boolean value indicating whether the save operation was successful.
  124.    """
  125.     logger.info("Salvando dados...")
  126.     logger.info(f"Shape: {df.shape}")
  127.     logger.info(f"Arquivo: cotacoes_{now_str}.csv")
  128.  
  129.     if df.empty:
  130.         logger.warning("Não há dados a serem salvos")
  131.         return False
  132.     df.to_csv(f"cotacoes_{now_str}.csv", index=False)
  133.     return True
  134.  
  135.  
  136. def main():
  137.     NOW = datetime.now()
  138.     NOW_STR = NOW.strftime("%Y-%m-%d_%H-%M-%S")
  139.  
  140.     logger.info("Iniciando raspagem de dados...")
  141.  
  142.     df = extract_data(BASE_URL, CROPS_LINK, TABLE_COLUMNS)
  143.  
  144.     df = data_cleaning(df)
  145.  
  146.     save_data(df, NOW_STR)
  147.  
  148.     NOW = datetime.now()
  149.     logger.info("Raspagem de dados finalizada...")
  150.  
  151.  
  152. if __name__ == "__main__":
  153.     main()
  154.  
Advertisement
Add Comment
Please, Sign In to add comment