Olá analisei e resolvi criar minha versão para lhe ajudar:
Ai olha o que encontrei:
- Tratamento da resposta da API: Não há um tratamento específico para verificar a estrutura da resposta antes de processá-la.
- Formato das datas: O formato de data pode não coincidir com o esperado pela API.
- Autenticação: A API pode exigir autenticação que não está sendo fornecida.
- Estrutura de resposta: A verificação
dados.get("ultimaPagina", True)
assume uma estrutura específica de resposta que pode não corresponder à realidade.
- Rate limiting: A API pode estar limitando o número de requisições.
Corrigindo:
- Tratamento robusto de erros para requisições e parsing JSON
- Sistema de retry para lidar com falhas temporárias
- Verificação mais detalhada da estrutura de resposta
- Headers de navegador para simular um cliente real
- Pausas entre requisições para evitar rate limiting
- Análise e salvamento dos resultados em um arquivo Excel
- Logging mais detalhado para facilitar a depuração
Para solucionar seu problema específico, é importante verificar:
- Se o site permite esse tipo de scraping automatizado
- Se o formato correto da API está sendo usado (pode ter mudado)
- Se há necessidade de autenticação ou token de acesso
- Se você consegue fazer uma requisição manual com sucesso usando ferramentas como Postman
Olhe também se a resposta da API contém a estrutura esperada, como "contratacoes" e "ultimaPagina". A API pode ter mudado ou pode retornar outras informações.
import requests
import pandas as pd
from datetime import datetime, timedelta
import time
import json
"Content-Type": "application/json",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
}
def buscar_editais_filtrados(estado, palavras_chave, data_inicio, data_fim, max_tentativas=3):
resultados = []
pagina = 1
while True:
print(f"Buscando página {pagina}...")
payload = {
"uf": estado,
"dataInicioRecebimentoProposta": data_inicio,
"dataFimRecebimentoProposta": data_fim,
"pagina": pagina,
"tamanhoPagina": 100
}
# Tentativas com retry em caso de falha
tentativas = 0
while tentativas < max_tentativas:
try:
resposta =
requests.post(URL, headers=HEADERS, json=payload, timeout=30)
# Verificar se a resposta foi bem-sucedida
if resposta.status_code == 200:
break
else:
print(f"Erro na tentativa {tentativas+1}: Status code {resposta.status_code}")
if resposta.status_code == 429: # Too Many Requests
wait_time = 10 * (tentativas + 1)
print(f"Rate limit atingido. Aguardando {wait_time} segundos...")
time.sleep(wait_time)
else:
time.sleep(2)
except requests.exceptions.RequestException as e:
print(f"Erro na requisição (tentativa {tentativas+1}): {e}")
time.sleep(5)
tentativas += 1
# Se todas as tentativas falharam
if tentativas == max_tentativas:
print("Número máximo de tentativas atingido. Encerrando busca.")
break
# Tentativa de parsing do JSON
try:
dados = resposta.json()
except json.JSONDecodeError:
print(f"Erro ao decodificar JSON na página {pagina}. Resposta: {resposta.text[:200]}...")
break
# Verificar se a estrutura esperada está presente
if "contratacoes" not in dados:
print(f"Estrutura de dados inesperada na página {pagina}. Chaves disponíveis: {list(dados.keys())}")
# Exibir uma amostra da resposta para debug
print(f"Amostra da resposta: {json.dumps(dados)[:300]}...")
break
registros = dados.get("contratacoes", [])
print(f"Encontrados {len(registros)} registros na página {pagina}")
if not registros:
print("Nenhum registro encontrado nesta página.")
break
# Processar os registros
for edital in registros:
objeto = edital.get("objeto", "").lower() if edital.get("objeto") else ""
if any(palavra.lower() in objeto for palavra in palavras_chave):
resultados.append({
"Objeto": edital.get("objeto", ""),
"Modalidade": edital.get("modalidade", ""),
"Data Fim Proposta": edital.get("dataFimRecebimentoProposta", ""),
"Órgão": edital.get("orgao", {}).get("nome", "") if edital.get("orgao") else "",
"Município": edital.get("municipio", ""),
"UF": edital.get("uf", ""),
"Link PNCP": edital.get("urlPNCP", "")
})
# Verificar se é a última página
if dados.get("ultimaPagina") or pagina >= dados.get("totalPaginas", 1):
print("Última página alcançada.")
break
pagina += 1
# Pausa para evitar sobrecarga no servidor
time.sleep(1)
print(f"Busca finalizada. Total de {len(resultados)} editais correspondentes encontrados.")
return resultados
# Execução principal
try:
print(f"Iniciando busca de editais para UF: {estado}")
print(f"Palavras-chave: {', '.join(palavras_chave)}")
print(f"Período: {data_inicio} a {data_fim}")
editais_filtrados = buscar_editais_filtrados(estado, palavras_chave, data_inicio, data_fim)
if editais_filtrados:
# Criação do DataFrame
df = pd.DataFrame(editais_filtrados)
# Formatação de data se necessário
if "Data Fim Proposta" in df.columns:
try:
df["Data Fim Proposta"] = pd.to_datetime(df["Data Fim Proposta"]).dt.strftime('%d/%m/%Y')
except:
print("Não foi possível formatar a coluna de data.")
print(f"\nTotal de editais encontrados com as palavras-chave: {len(df)}")
# Salvar em Excel
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
arquivo_excel = f"editais_pncp_{estado}_{timestamp}.xlsx"
df.to_excel(arquivo_excel, index=False)
print(f"Resultados salvos em {arquivo_excel}")
# Exibir as primeiras linhas
print("\nPrimeiros registros encontrados:")
print(df.head().to_string())
else:
print("Nenhum edital encontrado com os filtros especificados.")
except Exception as e:
print(f"Erro durante a execução: {str(e)}")