Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # This script was written by Matheus S. Serpa
- # Contact: [email protected]
- import pandas as pd
- import numpy as np
- import requests
- from bs4 import BeautifulSoup
- from datetime import datetime
- import logging
- logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(message)s")
- logger = logging.getLogger(__name__)
- # Raspagem de dados de cotações de commodities agrícolas como soja, milho, café, etc.
- BASE_URL = "https://www.noticiasagricolas.com.br/cotacoes/"
- CROPS_LINK = {
- "Soja": "soja/soja-mercado-fisico-sindicatos-e-cooperativas",
- "Trigo": "trigo/trigo-mercado-fisico",
- "Milho": "milho/milho-mercado-fisico-sindicatos-e-cooperativas",
- }
- TABLE_COLUMNS = 3
- def extract_data(base_url: str, links: dict, columns: int) -> pd.DataFrame:
- """
- Extracts commodity prices data from noticiasagricolas.com.br
- Args:
- base_url (str): Base URL of the website
- links (dict): Dictionary of commodities links
- columns (int): Number of columns in the prices table
- Returns:
- pd.DataFrame: Dataframe containing the places and prices data
- """
- df = pd.DataFrame()
- for crop, link in links.items():
- url = base_url + link
- # Acessa a página e obtém todo conteúdo HTML
- try:
- response = requests.get(url)
- response.raise_for_status()
- html_page = response.text
- except requests.exceptions.RequestException:
- logging.exception(f"Não foi possível acessar a página: {url}")
- continue
- # Realiza o parser e busca pela tabela de cotações
- try:
- soup = BeautifulSoup(html_page, "html.parser")
- table_data = soup.find("table", {"class": "cot-fisicas"}).find_all(
- "td"
- )
- except Exception:
- logging.exception(
- "Não foi possível encontrar a tabela de cotações"
- )
- continue
- # Obtém o nome de todas praças / locais
- places = []
- PLACE_COLUMN = 0
- for element in range(PLACE_COLUMN, len(table_data), columns):
- places.append(table_data[element].text)
- # Obtém o preço / quotações de todas praças / locais
- prices = []
- PRICE_COLUMN = 1
- for element in range(PRICE_COLUMN, len(table_data), columns):
- prices.append(table_data[element].text)
- # Cria um dataframe com os dados obtidos
- data = {"place": places, "price": prices}
- df_crop = pd.DataFrame(data)
- # Ajusta o formato da moeda e do nome da cultura
- df_crop["crop"] = crop
- df_crop["currency"] = "BRL"
- # Adiciona o dataframe da cultura atual ao dataframe geral
- df = pd.concat([df, df_crop])
- return df
- # Limpeza dos dados para adequar ao formato brasileiro e também ajustar tipos dos dados
- def data_cleaning(df: pd.DataFrame) -> pd.DataFrame:
- """
- Clean data to adjust to Brazilian format and also adjust data types.
- Args:
- df: The DataFrame containing the prices and places.
- Returns:
- pd.DataFrame: Cleaned DataFrame.
- """
- # Ajusta o formato do preço
- df["price"] = df["price"].str.replace(",", ".")
- df["price"] = df["price"].apply(
- lambda x: np.nan if x == "s/ cotação" else x
- )
- df["price"] = df["price"].astype(float)
- # Remove linhas com valores nulos
- df = df.dropna().reset_index(drop=True)
- return df
- def save_data(df: pd.DataFrame, now_str: str) -> bool:
- """
- Save the data to a CSV file.
- Args:
- df: The DataFrame containing the prices and places.
- now_str: The current date and time string in the format 'YYYY-MM-DD_HH-MM-SS'.
- Returns:
- A boolean value indicating whether the save operation was successful.
- """
- logger.info("Salvando dados...")
- logger.info(f"Shape: {df.shape}")
- logger.info(f"Arquivo: cotacoes_{now_str}.csv")
- if df.empty:
- logger.warning("Não há dados a serem salvos")
- return False
- df.to_csv(f"cotacoes_{now_str}.csv", index=False)
- return True
- def main():
- NOW = datetime.now()
- NOW_STR = NOW.strftime("%Y-%m-%d_%H-%M-%S")
- logger.info("Iniciando raspagem de dados...")
- df = extract_data(BASE_URL, CROPS_LINK, TABLE_COLUMNS)
- df = data_cleaning(df)
- save_data(df, NOW_STR)
- NOW = datetime.now()
- logger.info("Raspagem de dados finalizada...")
- if __name__ == "__main__":
- main()
Advertisement
Add Comment
Please, Sign In to add comment