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