Add files via upload

This commit is contained in:
Idalecio Schvartz Sobrinho
2026-05-30 18:51:00 -03:00
committed by GitHub
commit 421c4fdb52
+193
View File
@@ -0,0 +1,193 @@
#!/usr/bin/env python3
import requests
from bs4 import BeautifulSoup
from influxdb_client import InfluxDBClient, Point
from influxdb_client.client.write_api import SYNCHRONOUS
import re
from datetime import datetime
import time
INFLUXDB_URL = "http://xx.xxx.xx.xxx:8086"
INFLUXDB_TOKEN = "XXXXXXXXXXXX"
INFLUXDB_ORG = "XXXXX"
INFLUXDB_BUCKET = "XXXXX"
CRAVIL_URL = "https://www.cravil.com.br/cotacoes/"
INTERVALO_COLETA = 300
def parse_valor(valor_str: str) -> float:
if not valor_str:
return 0.0
valor_limpo = re.sub(r'[^\d,.]', '', valor_str)
valor_limpo = valor_limpo.replace('.', '').replace(',', '.')
try:
return float(valor_limpo)
except ValueError:
return 0.0
def coletar_cotacoes() -> list[dict]:
cotacoes = []
try:
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}
response = requests.get(CRAVIL_URL, headers=headers, timeout=30)
response.raise_for_status()
soup = BeautifulSoup(response.content, 'html.parser')
# xpath: /html/body/main/section[2]/div/div/div/div[1]/ul/li (lista com todos os valores)
section = soup.select('main section')
if len(section) >= 2:
ul = section[1].find('ul')
if ul:
lis = ul.find_all('li')
for li in lis:
try:
h3 = li.find('h3')
titulo = h3.get_text(strip=True) if h3 else None
divs = li.find_all('div', recursive=False)
valor_str = None
for div in divs:
inner_divs = div.find_all('div', recursive=False)
if len(inner_divs) >= 2:
valor_div = inner_divs[1].find_all('div', recursive=False)
if len(valor_div) >= 2:
valor_str = valor_div[1].get_text(strip=True)
break
elif inner_divs[1]:
valor_str = inner_divs[1].get_text(strip=True)
break
if not valor_str:
for elem in li.find_all(string=re.compile(r'R?\$?\s*\d+[,\.]\d+')):
valor_str = elem.strip()
break
if titulo and valor_str:
valor = parse_valor(valor_str)
cotacoes.append({
'titulo': titulo,
'valor': valor,
'valor_raw': valor_str
})
print(f"{titulo}: {valor_str} -> {valor}")
except Exception as e:
print(f" ✗ Erro ao processar item: {e}")
continue
if not cotacoes:
print("Tentando método alternativo de extração...")
items = soup.select('li')
for li in items:
h3 = li.find('h3')
if h3:
titulo = h3.get_text(strip=True)
texto = li.get_text()
match = re.search(r'R?\$?\s*([\d.,]+)', texto)
if match:
valor_str = match.group(0)
valor = parse_valor(valor_str)
if valor > 0:
cotacoes.append({
'titulo': titulo,
'valor': valor,
'valor_raw': valor_str
})
print(f"{titulo}: {valor_str} -> {valor}")
except requests.RequestException as e:
print(f"Erro ao acessar {CRAVIL_URL}: {e}")
return cotacoes
def enviar_influxdb(cotacoes: list[dict]):
if not cotacoes:
print("Nenhuma cotação para enviar.")
return
try:
client = InfluxDBClient(
url=INFLUXDB_URL,
token=INFLUXDB_TOKEN,
org=INFLUXDB_ORG
)
write_api = client.write_api(write_options=SYNCHRONOUS)
for cotacao in cotacoes:
produto_tag = cotacao['titulo'].lower().replace(' ', '_')
produto_tag = re.sub(r'[^a-z0-9_]', '', produto_tag)
point = (
Point("cotacao_agricola")
.tag("produto", produto_tag)
.tag("produto_nome", cotacao['titulo'])
.tag("fonte", "cravil")
.field("valor_saco", cotacao['valor'])
.field("valor_raw", cotacao['valor_raw'])
)
write_api.write(bucket=INFLUXDB_BUCKET, record=point)
print(f" → Enviado: {cotacao['titulo']}")
client.close()
print(f"\n{len(cotacoes)} cotações enviadas para InfluxDB2")
except Exception as e:
print(f"Erro ao enviar para InfluxDB: {e}")
def main():
print("=" * 50)
print("COLETOR DE COTAÇÕES AGRÍCOLAS - CRAVIL")
print(f"Intervalo de coleta: {INTERVALO_COLETA // 60} minutos")
print("=" * 50)
ciclo = 1
while True:
print(f"\n{'' * 50}")
print(f"📅 CICLO #{ciclo} - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print(f"{'' * 50}")
print(f"\n📥 Coletando cotações de {CRAVIL_URL}...")
cotacoes = coletar_cotacoes()
if cotacoes:
print(f"\n📊 Total de {len(cotacoes)} cotações coletadas")
print(f"\n📤 Enviando para InfluxDB2 ({INFLUXDB_URL})...")
enviar_influxdb(cotacoes)
else:
print("\n⚠ Nenhuma cotação encontrada!")
proxima_coleta = datetime.now().timestamp() + INTERVALO_COLETA
proxima_hora = datetime.fromtimestamp(proxima_coleta).strftime('%H:%M:%S')
print(f"\n⏰ Próxima coleta em {INTERVALO_COLETA // 60} minutos ({proxima_hora})")
print(" (Ctrl+C para encerrar)")
try:
time.sleep(INTERVALO_COLETA)
except KeyboardInterrupt:
print("\n\n🛑 Coleta encerrada pelo usuário.")
break
ciclo += 1
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("\n\n🛑 Programa encerrado.")