att
This commit is contained in:
parent
87568422b4
commit
c93ff700f4
@ -16,7 +16,7 @@ import json
|
||||
|
||||
# Configuração da data
|
||||
USE_MANUAL_DATE = False # False = usar dia anterior automaticamente; True = usar MANUAL_DATE_STR
|
||||
MANUAL_DATE_STR = "16112025" # Formato DDMMAAAA, usado quando USE_MANUAL_DATE=True
|
||||
MANUAL_DATE_STR = "20112025" # Formato DDMMAAAA, usado quando USE_MANUAL_DATE=True
|
||||
|
||||
# Configuração de intervalo de datas (execução dia por dia)
|
||||
USE_DATE_RANGE = False # True = usar intervalo de datas; False = usar USE_MANUAL_DATE
|
||||
@ -132,17 +132,20 @@ def main():
|
||||
# Configurar opções do Chrome para ambiente Kubernetes/Docker
|
||||
chrome_options = Options()
|
||||
|
||||
# CONFIGURAÇÃO: Defina como False para ver o navegador (útil para debug no Windows)
|
||||
USE_HEADLESS = True # True = modo headless (sem interface), False = com interface
|
||||
|
||||
# Configurações essenciais para rodar em Docker/Kubernetes (sem interface gráfica)
|
||||
chrome_options.add_argument('--headless') # Modo headless (sem interface gráfica)
|
||||
if USE_HEADLESS:
|
||||
chrome_options.add_argument('--headless=new') # Novo modo headless (mais estável)
|
||||
|
||||
chrome_options.add_argument('--no-sandbox') # Necessário para rodar como root
|
||||
chrome_options.add_argument('--disable-dev-shm-usage') # Evita problemas de memória compartilhada
|
||||
chrome_options.add_argument('--disable-gpu') # Desabilita GPU (não necessária em headless)
|
||||
|
||||
# Configurações adicionais recomendadas para Kubernetes
|
||||
# Configurações adicionais recomendadas
|
||||
chrome_options.add_argument('--disable-software-rasterizer')
|
||||
chrome_options.add_argument('--disable-extensions')
|
||||
chrome_options.add_argument('--disable-setuid-sandbox')
|
||||
chrome_options.add_argument('--remote-debugging-port=9222')
|
||||
chrome_options.add_argument('--disable-blink-features=AutomationControlled') # Evita detecção de automação
|
||||
|
||||
# Configurações de janela
|
||||
chrome_options.add_argument('--window-size=1920,1080')
|
||||
@ -150,7 +153,8 @@ def main():
|
||||
|
||||
# Desabilitar notificações e popups
|
||||
chrome_options.add_argument('--disable-notifications')
|
||||
chrome_options.add_experimental_option('excludeSwitches', ['enable-logging'])
|
||||
chrome_options.add_experimental_option('excludeSwitches', ['enable-logging', 'enable-automation'])
|
||||
chrome_options.add_experimental_option('useAutomationExtension', False)
|
||||
|
||||
# Definir pasta de download
|
||||
# Tenta usar Desktop, se não existir usa /tmp (para Kubernetes/Docker)
|
||||
@ -178,13 +182,26 @@ def main():
|
||||
|
||||
# Inicializar o driver do Chrome
|
||||
print("Iniciando o navegador...")
|
||||
print(f"Modo headless: {USE_HEADLESS}")
|
||||
|
||||
try:
|
||||
# Criar o service apontando para o chromedriver do sistema (Kubernetes/Docker)
|
||||
# Comentar a linha abaixo se estiver rodando localmente no Windows
|
||||
# from selenium.webdriver.chrome.service import Service
|
||||
# service = Service('/usr/bin/chromedriver')
|
||||
# driver = webdriver.Chrome(service=service, options=chrome_options)
|
||||
|
||||
# Para rodar localmente no Windows, use:
|
||||
driver = webdriver.Chrome(options=chrome_options)
|
||||
print("Navegador iniciado com sucesso!")
|
||||
except Exception as e:
|
||||
print(f"Erro ao iniciar o navegador: {e}")
|
||||
print("\nPossíveis soluções:")
|
||||
print("1. Verifique se o Chrome está instalado")
|
||||
print("2. Verifique se o ChromeDriver está instalado e atualizado")
|
||||
print("3. Execute: pip install --upgrade selenium")
|
||||
print("4. Tente desabilitar o modo headless (USE_HEADLESS = False)")
|
||||
raise
|
||||
|
||||
try:
|
||||
# Acessar a URL
|
||||
@ -442,13 +459,17 @@ def main():
|
||||
]
|
||||
}
|
||||
try:
|
||||
print("Abrindo arquivo CSV para leitura...")
|
||||
# Detectar delimitador e ler
|
||||
with open(downloaded_file, 'r', encoding='utf-8-sig', errors='ignore') as f:
|
||||
print("Detectando delimitador do CSV...")
|
||||
sample = f.read(4096)
|
||||
f.seek(0)
|
||||
try:
|
||||
dialect = csv.Sniffer().sniff(sample, delimiters=';,\t|')
|
||||
except Exception:
|
||||
print(f"Delimitador detectado: '{dialect.delimiter}'")
|
||||
except Exception as e:
|
||||
print(f"Erro ao detectar delimitador, usando ';' por padrão: {e}")
|
||||
class Simple(csv.Dialect):
|
||||
delimiter = ';'
|
||||
quotechar = '"'
|
||||
@ -458,8 +479,11 @@ def main():
|
||||
lineterminator = '\n'
|
||||
quoting = csv.QUOTE_MINIMAL
|
||||
dialect = Simple
|
||||
|
||||
print("Lendo cabeçalhos do CSV...")
|
||||
reader = csv.DictReader(f, dialect=dialect)
|
||||
original_headers = reader.fieldnames or []
|
||||
print(f"Cabeçalhos encontrados: {original_headers}")
|
||||
|
||||
# Construir novos headers, removendo colunas e substituindo Produto
|
||||
new_headers = []
|
||||
@ -480,8 +504,15 @@ def main():
|
||||
if 'SKU' not in new_headers:
|
||||
new_headers.extend(['SKU', 'Descricao'])
|
||||
|
||||
print(f"Novos cabeçalhos processados: {new_headers}")
|
||||
print("Processando linhas do CSV...")
|
||||
|
||||
rows_out = []
|
||||
row_count = 0
|
||||
for row in reader:
|
||||
row_count += 1
|
||||
if row_count % 100 == 0:
|
||||
print(f"Processadas {row_count} linhas...")
|
||||
new_row = {}
|
||||
for h in original_headers:
|
||||
nh = _normalize_label(h)
|
||||
@ -508,7 +539,11 @@ def main():
|
||||
new_row.setdefault('PRECO_MEDIO', '')
|
||||
rows_out.append(new_row)
|
||||
|
||||
print(f"Total de linhas processadas: {row_count}")
|
||||
print(f"Total de linhas válidas: {len(rows_out)}")
|
||||
|
||||
# Inserir os dados tratados no banco de dados
|
||||
print("Preparando para inserir dados no banco...")
|
||||
def _find_header(headers, targets):
|
||||
targets_norm = { _normalize_label(t) for t in targets }
|
||||
for hh in headers:
|
||||
@ -542,11 +577,10 @@ def main():
|
||||
print("Aviso: coluna de Preço Médio não encontrada; valores serão inseridos como 0.00.")
|
||||
|
||||
# Conectar ao SQL Server
|
||||
print("Escolhendo driver SQL Server...")
|
||||
driver_name = choose_sql_driver()
|
||||
try:
|
||||
available_drivers = pyodbc.drivers()
|
||||
except Exception:
|
||||
available_drivers = []
|
||||
print(f"Driver selecionado: {driver_name}")
|
||||
|
||||
connection_string = (
|
||||
f'DRIVER={{{driver_name}}};'
|
||||
f'SERVER=10.77.77.10;'
|
||||
@ -560,20 +594,28 @@ def main():
|
||||
|
||||
# Converter data para formato aceito pelo banco (date)
|
||||
data_db = datetime.strptime(data_formatada, '%d%m%Y').date()
|
||||
print(f"Data para inserção no banco: {data_db}")
|
||||
|
||||
print("Conectando ao banco de dados...")
|
||||
inserted = 0
|
||||
with pyodbc.connect(connection_string) as conn:
|
||||
print("Conexão estabelecida com sucesso!")
|
||||
conn.autocommit = False
|
||||
cur = conn.cursor()
|
||||
|
||||
# Apagar dados existentes para a data
|
||||
print(f"Deletando dados existentes para a data {data_db}...")
|
||||
cur.execute("DELETE FROM [GINSENG].[dbo].[rgb_sales_selenium] WHERE [Data] = ?", data_db)
|
||||
print("Dados antigos deletados.")
|
||||
|
||||
# Inserir linhas
|
||||
print("Preparando inserção de dados...")
|
||||
insert_sql = (
|
||||
"INSERT INTO [GINSENG].[dbo].[rgb_sales_selenium] ([Data],[PDV],[SKU],[DESCRICAO],[VENDAS],[PRECO_MEDIO]) "
|
||||
"VALUES (?,?,?,?,?,?)"
|
||||
)
|
||||
batch = []
|
||||
batch_count = 0
|
||||
for r in rows_out:
|
||||
pdv_val = r.get(pdv_header, '')
|
||||
try:
|
||||
@ -591,26 +633,41 @@ def main():
|
||||
pdv_val = None
|
||||
batch.append((data_db, pdv_val, sku_val, desc_val, vendas_val, preco_medio_val))
|
||||
if len(batch) >= 1000:
|
||||
batch_count += 1
|
||||
print(f"Inserindo lote {batch_count} ({len(batch)} registros)...")
|
||||
cur.executemany(insert_sql, batch)
|
||||
inserted += len(batch)
|
||||
batch = []
|
||||
if batch:
|
||||
batch_count += 1
|
||||
print(f"Inserindo lote final {batch_count} ({len(batch)} registros)...")
|
||||
cur.executemany(insert_sql, batch)
|
||||
inserted += len(batch)
|
||||
|
||||
print("Fazendo commit das alterações...")
|
||||
conn.commit()
|
||||
print("Commit realizado com sucesso!")
|
||||
|
||||
print(f"Dados inseridos no banco: {inserted} registros para a data {data_db}.")
|
||||
|
||||
# Remover arquivo original
|
||||
print(f"Removendo arquivo temporário: {downloaded_file}")
|
||||
try:
|
||||
os.remove(downloaded_file)
|
||||
except Exception:
|
||||
pass
|
||||
print("Arquivo removido com sucesso.")
|
||||
except Exception as e:
|
||||
print(f"Aviso: não foi possível remover o arquivo: {e}")
|
||||
|
||||
# Salvar estado apenas após sucesso completo
|
||||
if USE_DATE_RANGE:
|
||||
print("Salvando estado do processamento...")
|
||||
_save_date_state(data_formatada)
|
||||
|
||||
print("Processamento concluído com sucesso!")
|
||||
except Exception as e:
|
||||
print(f"Falha ao tratar o CSV: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
else:
|
||||
print("Não foi possível detectar o arquivo baixado dentro do tempo limite.")
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user