Automatização de Login com Captchas de Deslize usando Python

Captcha de Deslize Simples

Para o site http://admin.emaotai.cn/login.aspx, esse tipo de captcha requer apenas arrastar o slider para a posição especificada. Antes de arrastar, é necessário rolar até o elemento desejado.


import tempo
from selenium import webdriver
from selenium.webdriver import ActionChains

# Instanciar o navegador Selenium
navegador = webdriver.Firefox()

# URL da página de login
url = 'http://admin.emaotai.cn/login.aspx'

# Navegar para a página de login
navegador.get(url)
navegador.maximize_window()
navegador.implicitly_wait(5)

# Encontrar o elemento arrastável
elemento_arrastavel = navegador.find_element_by_id('nc_1_n1z')

# Rolar até o elemento
navegador.execute_script("arguments[0].scrollIntoView();", elemento_arrastavel)
tempo.sleep(2)

# Iniciar a ação de arrastar
ActionChains(navegador).click_and_hold(elemento_arrastavel).perform()

# Mover o slider para a direita (ajustar o offset conforme necessário)
ActionChains(navegador).move_by_offset(xoffset=247, yoffset=0).perform()

# Soltar o slider
ActionChains(navegador).release().perform()

Captcha de Quebra-Cabeça Deslizante

Para sites como o oumo.cn, que usam captchas de quebra-cabeça, podemos usar detecção de bordas com OpenCV e correspondência de template para localizar a peça do puzzle.

Detecção de Borda

Instale o OpenCV com pip: pip install opencv-python

Usamos o operador Canny para detecção de bordas, pois demonstra o melhor desempenho em testes.


import cv2

limiar_minimo = 0
limiar_maximo = 100

def atualizar_limiar_baixo(valor):
    blur = cv2.GaussianBlur(imagem, (3, 3), 0)
    bordas = cv2.Canny(blur, valor, limiar_maximo)
    cv2.imshow('bordas', bordas)

def atualizar_limiar_alto(valor):
    blur = cv2.GaussianBlur(imagem, (3, 3), 0)
    bordas = cv2.Canny(blur, limiar_minimo, valor)
    cv2.imshow('bordas', bordas)

# Carregar imagem em escala de cinza
imagem = cv2.imread('captcha.png', 0)

cv2.namedWindow('bordas', cv2.WINDOW_NORMAL | cv2.WINDOW_KEEPRATIO)
cv2.createTrackbar('Limiar mínimo', 'bordas', limiar_minimo, 500, atualizar_limiar_baixo)
cv2.createTrackbar('Limiar máximo', 'bordas', limiar_maximo, 1000, atualizar_limiar_alto)
atualizar_limiar_baixo(0)

# Pressione Esc para sair
if cv2.waitKey(0) == 27:
    cv2.destroyAllWindows()

Após testes, um limiar mínimo de 100 e máximo de 500 produzem resultados ideais.

Correspondência do Quebra-Cabeça

Usamos cv2.matchTemplate com o método TM_CCOEFF_NORMED para correspondência.


import cv2
import numpy as np

def corresponder_imagens(caminho_fundo, caminho_puzzle):
    # Carregar imagens originais
    fundo_original = cv2.imread(caminho_fundo)
    puzzle_original = cv2.imread(caminho_puzzle)

    # Converter para escala de cinza e aplicar detecção de bordas
    fundo_cinza = cv2.imread(caminho_fundo, 0)
    fundo_blur = cv2.GaussianBlur(fundo_cinza, (3, 3), 0)
    fundo_bordas = cv2.Canny(fundo_blur, 100, 500)
    cv2.imwrite('temp_fundo_bordas.png', fundo_bordas)

    puzzle_cinza = cv2.imread(caminho_puzzle, 0)
    puzzle_blur = cv2.GaussianBlur(puzzle_cinza, (3, 3), 0)
    puzzle_bordas = cv2.Canny(puzzle_blur, 100, 500)
    cv2.imwrite('temp_puzzle_bordas.png', puzzle_bordas)

    # Carregar imagens com bordas
    alvo = cv2.imread('temp_fundo_bordas.png')
    template = cv2.imread('temp_puzzle_bordas.png')

    # Realizar correspondência de template
    altura_template, largura_template = template.shape[:2]
    resultado = cv2.matchTemplate(alvo, template, cv2.TM_CCOEFF_NORMED)
    cv2.normalize(resultado, resultado, 0, 1, cv2.NORM_MINMAX, -1)
    _, _, _, posicao_maxima = cv2.minMaxLoc(resultado)

    # Desenhar retângulo na área correspondente (opcional para visualização)
    cv2.rectangle(alvo, posicao_maxima, (posicao_maxima[0] + largura_template, posicao_maxima[1] + altura_template), (0, 0, 255), 2)

    # Retornar a posição x da correspondência
    return posicao_maxima[0]

# Exemplo de uso
posicao = corresponder_imagens('imagem_fundo.png', 'imagem_puzzle.png')
print(f"Posição x encontrada: {posicao}")

Programa Completo

O fluxo completo inclui: 1. Instanciar o navegador. 2. Clicar no botão de login para exibir o captcha. 3. Abrir novas abas para as imagens de fundo e puzzle. 4. Captuarr e recortar as imagens. 5. Usar correspondência para obter a posição. 6. Converter a posição para deslocamento na página. 7. Arrastar o slider.


import tempo
import cv2
import modulo_correspondencia  # Assume que o código de correspondência está em um módulo
from selenium import webdriver
from selenium.webdriver import ActionChains

# Instanciar navegador
navegador = webdriver.Firefox()
url = 'https://www.om.cn/login'
navegador.get(url)
identificador_principal = navegador.current_window_handle
navegador.implicitly_wait(3)

# Clicar no botão de login para exibir o captcha
botao_login = navegador.find_element_by_class_name('login_btn1')
botao_login.click()

# Mudar para o iframe do captcha
iframe_captcha = navegador.find_element_by_id('tcaptcha_iframe')
navegador.switch_to.frame(iframe_captcha)
tempo.sleep(1)

# Obter URLs das imagens
url_imagem_fundo = navegador.find_element_by_id('slideBg').get_attribute('src')
url_imagem_puzzle = navegador.find_element_by_id('slideBlock').get_attribute('src')

# Nova aba para imagem de fundo
navegador.execute_script("window.open('');")
navegador.switch_to.window(navegador.window_handles[1])
navegador.get(url_imagem_fundo)
tempo.sleep(3)
navegador.save_screenshot('captura_fundo.png')

# Recortar imagem de fundo (ajustar dimensões conforme necessário)
largura_fundo = 680
altura_fundo = 390
imagem_fundo = cv2.imread('captura_fundo.png')
tamanho_fundo = imagem_fundo.shape
y_inicial = int((tamanho_fundo[0] - altura_fundo) / 2)
y_final = y_inicial + altura_fundo
x_inicial = int((tamanho_fundo[1] - largura_fundo) / 2)
x_final = x_inicial + largura_fundo
imagem_fundo_recortada = imagem_fundo[y_inicial:y_final, x_inicial:x_final]
cv2.imwrite('fundo_recortado.png', imagem_fundo_recortada)

# Nova aba para imagem do puzzle
navegador.execute_script("window.open('');")
navegador.switch_to.window(navegador.window_handles[2])
navegador.get(url_imagem_puzzle)
tempo.sleep(3)
navegador.save_screenshot('captura_puzzle.png')

# Recortar imagem do puzzle
largura_puzzle = 136
altura_puzzle = 136
imagem_puzzle = cv2.imread('captura_puzzle.png')
tamanho_puzzle = imagem_puzzle.shape
y_p_inicial = int((tamanho_puzzle[0] - altura_puzzle) / 2)
y_p_final = y_p_inicial + altura_puzzle
x_p_inicial = int((tamanho_puzzle[1] - largura_puzzle) / 2)
x_p_final = x_p_inicial + largura_puzzle
imagem_puzzle_recortada = imagem_puzzle[y_p_inicial:y_p_final, x_p_inicial:x_p_final]
cv2.imwrite('puzzle_recortado.png', imagem_puzzle_recortada)

# Voltar para a aba principal
navegador.switch_to.window(identificador_principal)

# Corresponder imagens para obter posição
posicao_x = modulo_correspondencia.corresponder_imagens('fundo_recortado.png', 'puzzle_recortado.png')

# Calcular distância de arrasto (ajustar conforme a escala da página)
distancia_arrasto = int(posicao_x / 2 - 27.5) + 2

# Encontrar o slider e arrastar
elemento_slider = navegador.find_element_by_id('tcaptcha_drag_thumb')
ActionChains(navegador).click_and_hold(elemento_slider).perform()
ActionChains(navegador).move_by_offset(xoffset=distancia_arrasto, yoffset=0).perform()
ActionChains(navegador).release().perform()

tempo.sleep(10)

Nota: Pode ser necessário tentar novamente se o captcha falhar. Verifique se o elemento 'slideBg' ainda existe; se não, o captcha foi resolvido com sucesso.


def verificar_existencia_elemento(navegador, id_elemento):
    try:
        navegador.find_element_by_id(id_elemento)
        return True
    except:
        return False

# Exemplo de uso em um loop de repetição
while verificar_existencia_elemento(navegador, 'slideBg'):
    # Repetir o processo de arrasto ou outras ações necessárias
    pass

Tags: Selenium OpenCV Python CAPTCHA Automação Web

Publicado em 7-14 07:25