Skip to content

Commit

Permalink
Update mlsucker.py
Browse files Browse the repository at this point in the history
Algumas alterações feitas pelo ML.
Adição de um intervalo randômico
Busca dinâmica por qualquer termo, e não mais fixa
Nomeação automática do arquivo de resultados de acordo com o termo de busca
  • Loading branch information
linces authored Jan 22, 2024
1 parent 742c1cf commit 983b40d
Showing 1 changed file with 49 additions and 46 deletions.
95 changes: 49 additions & 46 deletions mlsucker.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,37 +20,24 @@ def get_cents(node, nome, valor_default=''):
return valor_default
return campo.text

def check_image_size(url):
response = requests.head(url)
content_type = response.headers.get('content-type')

if 'image' not in content_type:
return False

if 'content-length' in response.headers:
content_length = int(response.headers.get('content-length', 0))
if content_length < 200:
return False

return True

i = 1

headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:25.0) Gecko/20100101 Firefox/25.0'}
base_url = "https://lista.mercadolivre.com.br/Texturas-vray"
termo_busca = input("Digite o termo de busca: ")
base_url = f"https://lista.mercadolivre.com.br/{termo_busca}"

# Caminho e nome do arquivo CSV
nome_arquivo = "dados_produtos_ml_texturas.csv"
nome_arquivo = f"dados_produtos_ml_{termo_busca[:10]}.csv"
caminho_arquivo = os.path.abspath(nome_arquivo)

# Valores padrão do WooCommerce
published_default = '0' # Não publicado, 1 para Publicado
is_featured_default = '0' # Não é destaque, obviamente "1" é destaque
published_default = '1' # Publicado, 0 para Não Publicado
is_featured_default = '0' # Não é destaque
visibility_default = 'visible' # Visível no catálogo
short_description_default = '' # Descrição curta em branco
date_sale_price_starts_default = '' # Data de início da promoção em branco
date_sale_price_ends_default = '' # Data de término da promoção em branco
tax_status_default = 'none' # Não tributável
tax_status_default = 'none' # Não Tributável
tax_class_default = '' # Classe de imposto em branco
in_stock_default = '1' # Em estoque
stock_default = '' # Quantidade em estoque em branco
Expand Down Expand Up @@ -79,6 +66,7 @@ def check_image_size(url):
attribute_global_default = '' # Global do atributo em branco
attribute_default_default = '' # Valor padrão do atributo em branco


with open(nome_arquivo, mode='w', newline='', encoding='utf-8') as arquivo_csv:
writer = csv.writer(arquivo_csv, delimiter=',')
writer.writerow([
Expand All @@ -96,12 +84,27 @@ def check_image_size(url):
page = requests.get(base_url, headers=headers)
soup = BeautifulSoup(page.text, "html.parser")

valor = ''

for div in soup.find_all('div', class_='ui-search-result__content-wrapper'):
produto = div.find('h2', class_='ui-search-item__title')
link = div.find("a", class_="ui-search-link")
valor = get_value(div, "span") + "," + get_cents(div, "span")
valor_desconto = float(valor.replace('.', '').replace(',', '.')) * 0.88 # Aplica o desconto de 12%, aqui é uma decisão pessoal para o meu negócio, vc n precisa aplicar desconto algum.
valor_desconto = "{:.2f}".format(valor_desconto).replace('.', ',') # Formata o valor com duas casas decimais e vírgula
valor_node = div.find('span', class_='price-tag-fraction')
cents_node = div.find('span', class_='price-tag-cents')

if valor_node is not None:
valor = valor_node.text.strip()
if cents_node is not None:
valor += ',' + cents_node.text.strip()

valor_float = float(valor.replace('.', '').replace(',', '.'))

# Desconto de 12%
valor_desconto = valor_float * 0.88
valor_desconto_str = "{:.2f}".format(valor_desconto).replace('.', ',')
else:
valor_desconto_str = ''

imagens = []
video = ''

Expand All @@ -119,61 +122,55 @@ def check_image_size(url):
descricao = site_produto.find('p', class_='ui-pdp-description__content')

if descricao:
descricao_text = '<h1>' + produto.text + '</h1>\n\n' + descricao.text.strip().replace("MercadoLivre", "SoftArena").replace("Mercado Livre", "SoftArena").replace("MERCADO LIVRE", "SoftArena").replace("M E R C A D O L I V R E", "SoftArena")
# Substituir todas as variações de "MercadoLivre" por "SoftArena"
descricao_text = '<h1>' + produto.text + '</h1>\n\n' + descricao.text.strip().replace("MercadoLivre", "SoftArena").replace("Mercado Livre", "SoftArena").replace("Marcado Livre", "SoftArena").replace("MarcadoLivre", "SoftArena")
else:
descricao_text = '<h1>' + produto.text + '</h1>\n\nDescrição do produto não encontrada.'
# Quando não encontrar uma descrição, inserir o título do produto
descricao_text = '<h1>' + produto.text + '</h1>\n\n' + produto.text

imagem_tags = site_produto.find_all('img', class_='ui-pdp-image')

for imagem in imagem_tags:
if 'data-src' in imagem.attrs:
if 'youtube' in imagem['data-src']:
video = imagem['data-src']
elif not imagem['data-src'].endswith('.svg'): # Verifica se o link não termina com ".svg"
width = int(imagem['width'])
height = int(imagem['height'])
if width >= 200 and height >= 200:
imagens.append(imagem['data-src'])
elif not imagem['data-src'].endswith('.svg'):
imagens.append(imagem['data-src'])

imagens_str = ', '.join(imagens)

if not imagens:
continue # Pula para a próxima iteração do loop se nenhuma imagem atender aos requisitos

tags = [] # Lista de tags vazia
tags = []

tags_div = site_produto.find('div', class_='ui-pdp-attributes__value-list')
if tags_div:
tags_links = tags_div.find_all('a')
tags = [tag_link.text for tag_link in tags_links]

sku = '' # SKU vazio
sku = ''

sku_span = site_produto.find('span', class_='ui-pdp-buybox__sku-value')
if sku_span:
sku = sku_span.text.strip()
else:
# Criar um código EAN aleatório para o SKU
sku = '' + ''.join(random.choices('3456789', k=13))
# sku = random.choices('3456789', k=13)
sku = '' + ''.join(random.choices('6789', k=13))

if not tags:
tags = ['Texturas/Temas'] # Adicionar a tag padrão quando nenhuma tag for encontrada
tags = ['Ferramentas']

writer.writerow([
i, 'simple', sku, produto.text, '0', is_featured_default, visibility_default,
i, 'simple', sku, produto.text, published_default, is_featured_default, visibility_default,
short_description_default, descricao_text, date_sale_price_starts_default,
date_sale_price_ends_default, tax_status_default, tax_class_default, in_stock_default,
stock_default, low_stock_amount_default, backorders_allowed_default, sold_individually_default,
weight_default, length_default, width_default, height_default, allow_customer_reviews_default,
purchase_note_default, valor_desconto, valor, 'Texturas/Temas', ', '.join(tags), shipping_class_default,
purchase_note_default, valor_desconto_str, valor, 'Ferramentas', ', '.join(tags), shipping_class_default,
imagens_str, download_limit_default, download_expiry_days_default, parent_default,
grouped_products_default, upsells_default, cross_sells_default, external_url_default,
button_text_default, position_default, attribute_name_default, attribute_value_default,
attribute_visible_default, attribute_global_default, attribute_default_default, video
])

print('Código: ' + str(i) + ', Produto: ' + produto.text + ', Valor: ' + valor_desconto)
print('Código: ' + str(i) + ', Produto: ' + produto.text + ', Valor: ' + valor_desconto_str)

print("==========================")

Expand Down Expand Up @@ -214,11 +211,17 @@ def check_image_size(url):
next_url = urljoin(base_url, next_link['href'])
base_url = next_url

# Aguardar 2 segundos entre as solicitações para evitar o bloqueio por sobrecarga no servidor
time.sleep(2)
# Aguardar um tempo aleatório entre 0.5 e 2.5 segundos entre as solicitações para evitar o bloqueio por sobrecarga no servidor
time.sleep(random.uniform(0.5, 2.5))

except ConnectionError as e:
print("Ocorreu um erro de conexão:", e)

print("Arquivo CSV salvo com sucesso:")
print(caminho_arquivo)

except Exception as e:
print('Erro ao processar a página: ' + str(e))
break

print('Arquivo CSV gerado com sucesso em: ' + caminho_arquivo)

print("Arquivo CSV salvo com sucesso:")
print(caminho_arquivo)

0 comments on commit 983b40d

Please sign in to comment.