使用Selenium处理最多尝试5次的拼图验证码

0 投票
1 回答
249 浏览
提问于 2025-04-14 16:49

我一直在抓取这个网站:https://www.immobilienscout24.de

当我用selenium打开这个网站时,有时候在点击“我不是机器人”的验证码后,网站会让你解一个拼图验证码。问题是,这个网站只允许你移动拼图6次。如果你在第六次之后还是没能把拼图放对位置,就会被禁止进入这个网站。

我的代码可以移动拼图,但我该如何安排循环,让屏幕分成6个准确的部分呢?或者有没有其他的解决方法?

拼图验证码的代码如下:

try:
    slider = driver.find_element(By.CLASS_NAME, 'geetest_slider_button')
    for x in range(0, 200, 10):
        actions.move_to_element(slider).click_and_hold().move_by_offset(x, 0).release().perform()
        time.sleep(0.1)
except:
    print('No slider found. Continuing with the code.')

谢谢。

1 个回答

0

根据我对你问题的理解,你的目标是在六次尝试内验证一个图片验证码。

这个问题非常复杂,我认为最好的解决办法是直接把图片交给人工智能来处理,这样会简单一些。不过,我没有资格去调用相关的人工智能接口。也许你可以试着去激活它们。至于调用人工智能的代码,我觉得这应该不难。

如果不考虑使用人工智能,我认为仅仅通过模拟拖放是无法实现你的目标的。

首先,你需要以任何可能的方式捕捉到验证码区域,最终得到六张乱序的图片。比如,你可以先捕捉一张乱序的图片,然后在本地对其进行切割,或者直接从网页的源代码中获取图片资源。

假设你已经完成了这一步,得到了六张图片,那么你可以继续合并它们并进行图像采样。有很多种采样的方法,比如先把图片转换为灰度图,然后提取轮廓。这样,你就能得到一张轮廓图。通常来说,单张图片的亮度会有渐变,因此不同图片之间会有明显的分界线。当然,为了得到这些清晰的特征线,你可能需要在提取轮廓的过程中不断调整参数。不过,由于这些图片已经下载到本地,你仍然可以通过暴力破解来解决这个问题。

大多数情况下,我们无法在边缘测试中达到100%的匹配,因此你需要为每个边缘匹配结果建立特征值。在完成所有的排列组合后,使用最高的特征值来移动图片。如果还有剩余的尝试次数,你可以继续使用排名较低的序列。

你可能会问,当没有绝对正确的图片用于边缘匹配比较时,如何建立特征值。我认为你可以反向思考这个问题。例如,手动创建一张空白图片,并在分界线的位置人工绘制对比线。之后,提取这张图片的轮廓,作为特征值的参考。

另外,还有一个想法是直接对这六张图片应用边缘匹配算法,成对匹配它们,并计算最终的匹配值。

以上是我的思考过程,下面是可能涉及到的代码。

  1. 边缘匹配
def match_edges(image1, image2):
    # Convert images to grayscale
    gray1 = cv2.cvtColor(image1, cv2.COLOR_BGR2GRAY)
    gray2 = cv2.cvtColor(image2, cv2.COLOR_BGR2GRAY)

    # Detect edges in the images using the Canny algorithm
    edges1 = cv2.Canny(gray1, 50, 150)
    edges2 = cv2.Canny(gray2, 50, 150)

    # Initialize variables for matching edges
    # This example simplifies the matching process for demonstration purposes
    height, width = edges1.shape
    best_match_value = float('inf')
    best_match_position = None
    
    # Assuming edge matching is performed side by side (left/right edges comparison)
    for y in range(height):
        # Calculate the difference between edges of the two images
        match_value = np.sum(np.bitwise_xor(edges1[y,:], edges2[y,:]))
        # Update the best match if the current match is better
        if match_value < best_match_value:
            best_match_value = match_value
            best_match_position = y

    # Return the position and value of the best match
    return best_match_position, best_match_value
  1. 特征提取

# Restore picture 
f = merge(sum_rows,sum_cols,channels,part1,part2,part3,part4)
show_images([f],'Restore picture[1,2,3,4]')

# Gray
gray = cv2.cvtColor(f, cv2.COLOR_BGRA2GRAY)
show_images([gray],'Gray')

# Extract contour
edges = cv2.Canny(gray, 35, 80, apertureSize=3)
show_images([edges],'Extract contour')

  1. 绘制特征线
# f is current unsorted merge-image 
f = merge(sum_rows,sum_cols,channels,part1,part2,part3,part4)
lf = f.copy()
cv2.line(lf, (0, 75), (300, 75), (0, 0, 255), 2)
cv2.line(lf, (150, 0), (150, 150), (0, 0, 255), 2)
show_images([lf],'out of order,The gradient becomes the cross feature line.')
  1. 特征匹配
f = merge(sum_rows,sum_cols,channels,part1,part2,part3,part4)
gray = cv2.cvtColor(f, cv2.COLOR_BGRA2GRAY)
edges = cv2.Canny(gray, 35, 80, apertureSize=3)
show_images([edges],'Extract contour')
# find the split line.
lines = cv2.HoughLinesP(edges,0.01,np.pi/360,60,minLineLength=50,maxLineGap=10)
if lines is None:
    print('No cross feature line found')
else:
    lf = f.copy()
    for line in lines:
        x1, y1, x2, y2 = line[0]
        cv2.line(lf, (x1, y1), (x2, y2), (0, 0, 255), 2)
    show_images([lf])

Reference:

platform.openai.com/docs/guides/function-calling
zhihu.com/p/434851845    
geeksforgeeks.org/feature-detection-and-matching-with-opencv-python

撰写回答