Cool, I finally implemented the selenium image slider verification code! [With code]

Due to various reasons, we were unable to achieve the goal of the vision. Recording the intermediate results here can be regarded as an ending. This article is mainly about individual cases of using selenium to solve the slider verification code.

Ideas:

  • Use selenium to open the specified website in the browser

  • Download incomplete block images and background images to local

  • Compare the similarities between the two pictures and calculate the distance to slide

  • Plan a route, move the slider

01. Implementation steps

01. Use selenium to open the browser and browse the specified website

1. Find the path of chromedriver.exe

Click Start to find the Google icon==》Right-click for more==》Open file location==》Right-click on Google shortcut==》Properties ==>Open file location==>Copy path

2. Code

from selenium import webdriver

# chrome_path should be changed to your own path

chrome_path = r"C:\Users\11248\AppData\Local\Google\Chrome\Application\chromedriver.exe"

url = 'https://icas.jnu.edu.cn/cas/login'

driver = webdriver.Chrome(chrome_path)

driver.get(url)

02, download the incomplete block image and background image to the local device

1. Find the image location

Open the web page, enter the developer tools, and find the image location

2. Code

import time

import requests

from PIL import Image

from selenium.webdriver.common.by import By

from io import BytesIO


time.sleep(5)# Stay for a few seconds after entering the page and wait for the page to load.

target_link = driver.find_element(By.CLASS_NAME, "yidun_bg-img").get_attribute('src')

template_link = driver.find_element(By.CLASS_NAME, "yidun_jigsaw").get_attribute('src')


target_img = Image.open(BytesIO(requests.get(target_link).content))

template_img = Image.open(BytesIO(requests.get(template_link).content))

target_img.save('target.jpg')

template_img.save('template.png')
Now I have also found a lot of test friends and created a communication group to share technology, sharing a lot of technical documents and video tutorials we collected.
If you don’t want to experience the feeling of not being able to find resources when self-study, having no one to answer your questions, and persisting for a few days before giving up.
You can join us to communicate. And there are many technical experts who have made certain achievements in automation, performance, security, test development, etc.
Share their experience, and also share many live lectures and technical salons
You can learn for free! Focus on it! Open source! ! !
QQ group number: 110685036

03. Compare the similarities between the two pictures and calculate the sliding distance

1. Use matchTemplate to get the moving distance

Because the position of the defective block in the background image is different from the brightness of the original defective image, direct comparison of the similar parts of the two images often does not yield satisfactory results. Here, the two images need to be processed to a certain extent. To avoid this brightness interference, the author first performs grayscale processing on the two pictures, then performs Gaussian processing on the images, and finally performs edge detection.

def handel_img(img):

    imgGray = cv2.cvtColor(img, cv2.COLOR_RGBA2GRAY) # Convert to grayscale image

    imgBlur = cv2.GaussianBlur(imgGray, (5, 5), 1) # Gaussian blur

    imgCanny = cv2.Canny(imgBlur, 60, 60) # Canny operator edge detection

    return imgCanny

Convert JPG image to 4 channels (RGBA)


def add_alpha_channel(img):

    """ Add alpha channel to jpg image """

    r_channel, g_channel, b_channel = cv2.split(img) # Strip jpg image channels

    alpha_channel = np.ones(b_channel.shape, dtype=b_channel.dtype) * 255 # Create Alpha channel

    img_new = cv2.merge((r_channel, g_channel, b_channel, alpha_channel)) # Merge channel

    return img_new

2. Code

import cv2

# read image

def match(img_jpg_path, img_png_path):

    # read image

    img_jpg = cv2.imread(img_jpg_path, cv2.IMREAD_UNCHANGED)

    img_png = cv2.imread(img_png_path, cv2.IMREAD_UNCHANGED)

    # Determine whether the jpg image is already 4 channels

    if img_jpg.shape[2] == 3:

        img_jpg = add_alpha_channel(img_jpg)

    img = handel_img(img_jpg)

    small_img = handel_img(img_png)

    res_TM_CCOEFF_NORMED = cv2.matchTemplate(img, small_img, 3)

    value = cv2.minMaxLoc(res_TM_CCOEFF_NORMED)

    value = value[3][0] # Get the moving distance

    return value

3. Testing effect

In order to verify whether the ideas and methods are appropriate, the slider image and the background image are spliced here to bury a small hole behind.

def merge_img(jpg_img, png_img, y1, y2, x1, x2):

    """ Overlay png transparent images with jpg images

        y1, y2, x1, x2 are the superimposed position coordinate values

    """

    # Determine whether the jpg image is already 4 channels

    if jpg_img.shape[2] == 3:

        jpg_img = add_alpha_channel(jpg_img)

    # Get the alpha value of the image to be overwritten, divide the pixel value by 255, so that the value remains between 0-1

    alpha_png = png_img[yy1:yy2, xx1:xx2, 3] / 255.0

    alpha_jpg = 1 - alpha_png


    # Start overlay

    for c in range(0, 3):

        jpg_img[y1:y2, x1:x2, c] = ((alpha_jpg * jpg_img[y1:y2, x1:x2, c]) + (alpha_png * png_img[yy1:yy2, xx1:xx2, c]))


    return jpg_img

    

img_jpg_path = 'target.jpg' # Readers can modify the file path by themselves

img_png_path = 'template.png' # Readers can modify the file path by themselves

x1 = match(img_jpg_path, img_png_path)

y1 = 0

x2 = x1 + img_png.shape[1]

y2 = y1 + img_png.shape[0]

# Start overlay

res_img = merge_img(img_jpg, img_png, y1, y2, x1, x2)

cv2.imshow("res_img ", res_img)

cv2.waitKey(0)

04, plan the route, move the slider

1. Click the slider to move

Use the distance obtained in Section 3 to click the slider to move it.

from selenium.webdriver.support import expected_conditions as EC

from selenium.webdriver.support.wait import WebDriverWait

from selenium.webdriver import ActionChains


def crack_slider(distance):

wait = WebDriverWait(driver, 20)

    slider = wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'yidun_slider')))

    ActionChains(self.driver).click_and_hold(slider).perform()

    ActionChains(self.driver).move_by_offset(xoffset=distance, yoffset=0).perform()

    time.sleep(2)

    ActionChains(self.driver).release().perform()

    return 0

The magical thing is that when the trap comes, no matching is successful.

2. Reasons for matching failure

There are two reasons for this:

  • The image size has changed and the distance needs to be converted.

  • When the slider slides, the relative position of the slider and the missing block changes.

First solve the problem of image size changes and find the image size on the web page: 345×172.500

Download to local image size: 480×240

So the distance needs to be processed as follows:

distance = distance / 480 * 345

Regarding the second question, I haven’t found a good measuring tool here to measure it. Fortunately, the verification code does not require high position accuracy, so just try the numbers one by one.

distance = distance /480 * 345 + 12

05, Supplement

While studying the Jiexian verification code, some websites have verified the movement trajectory. If the slide is too fast, machine operation will also be recognized. In order to simulate manual operation, excellent programmers wrote a magic movement trajectory.

For example: We can first exceed the target and then move back.

def get_tracks(distance):

     distance + = 20

     v = 0

     t=0.2

     forward_tracks = []

     current = 0

     mid = distance * 3 / 5

     while current < distance:

         if current < mid:

             a = 2

         else:

             a = -3

         s = v * t + 0.5 * a * (t ** 2)

         v = v + a * t

         current + = s

         forward_tracks.append(round(s))


     back_tracks = [-3, -3, -2, -2, -2, -2, -2, -1, -1, -1]

     return {'forward_tracks': forward_tracks, 'back_tracks': back_tracks}



  def crack_slider(tracks):

    wait = WebDriverWait(driver, 20)

      slider = wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'yidun_slider')))

      ActionChains(driver).click_and_hold(slider).perform() # Simulate holding down the left mouse button


      for track in tracks['forward_tracks']:

          ActionChains(driver).move_by_offset(xoffset=track, yoffset=0).perform()


      time.sleep(0.5)

      for back_tracks in tracks['back_tracks']:

          ActionChains(driver).move_by_offset(xoffset=back_tracks, yoffset=0).perform()


      ActionChains(driver).move_by_offset(xoffset=-4, yoffset=0).perform()

      ActionChains(driver).move_by_offset(xoffset=4, yoffset=0).perform()

      time.sleep(0.5)


      ActionChains(driver).release().perform()# Release the left button

      return 0

06, complete code

# coding=utf-8

import re

import requests

import time

from io import BytesIO


import cv2

import numpy as np

from PIL import Image

from selenium import webdriver

from selenium.webdriver import ActionChains

from selenium.webdriver.common.by import By

from selenium.webdriver.support import expected_conditions as EC

from selenium.webdriver.support.wait import WebDriverWait



classCrackSlider():

    # Use browser screenshots to identify the gap position in the verification code, obtain the required sliding distance, and crack the sliding verification code


    def __init__(self):

        super(CrackSlider, self).__init__()

        self.opts = webdriver.ChromeOptions()

        self.opts.add_experimental_option('excludeSwitches', ['enable-logging'])

        # self.driver = webdriver.Chrome(ChromeDriverManager().install(), options=self.opts)

        chrome_path = r"C:\Users\11248\AppData\Local\Google\Chrome\Application\chromedriver.exe"

        self.driver = webdriver.Chrome(chrome_path, options=self.opts)


        self.url = 'https://icas.jnu.edu.cn/cas/login'

        self.wait = WebDriverWait(self.driver, 10)


    def get_pic(self):

        self.driver.get(self.url)

        time.sleep(5)

        target_link = self.driver.find_element(By.CLASS_NAME, "yidun_bg-img").get_attribute('src')

        template_link = self.driver.find_element(By.CLASS_NAME, "yidun_jigsaw").get_attribute('src')


        target_img = Image.open(BytesIO(requests.get(target_link).content))

        template_img = Image.open(BytesIO(requests.get(template_link).content))

        target_img.save('target.jpg')

        template_img.save('template.png')


    def crack_slider(self, distance):

        slider = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'yidun_slider')))

        ActionChains(self.driver).click_and_hold(slider).perform()

        ActionChains(self.driver).move_by_offset(xoffset=distance, yoffset=0).perform()

        time.sleep(2)

        ActionChains(self.driver).release().perform()

        return 0



def add_alpha_channel(img):

    """ Add alpha channel to jpg image """


    r_channel, g_channel, b_channel = cv2.split(img) # Strip jpg image channels

    alpha_channel = np.ones(b_channel.shape, dtype=b_channel.dtype) * 255 # Create Alpha channel


    img_new = cv2.merge((r_channel, g_channel, b_channel, alpha_channel)) # Merge channel

    return img_new



def handel_img(img):

    imgGray = cv2.cvtColor(img, cv2.COLOR_RGBA2GRAY) # Convert to grayscale image

    imgBlur = cv2.GaussianBlur(imgGray, (5, 5), 1) # Gaussian blur

    imgCanny = cv2.Canny(imgBlur, 60, 60) # Canny operator edge detection

    return imgCanny



def match(img_jpg_path, img_png_path):

    # read image

    img_jpg = cv2.imread(img_jpg_path, cv2.IMREAD_UNCHANGED)

    img_png = cv2.imread(img_png_path, cv2.IMREAD_UNCHANGED)

    # Determine whether the jpg image is already 4 channels

    if img_jpg.shape[2] == 3:

        img_jpg = add_alpha_channel(img_jpg)

    img = handel_img(img_jpg)

    small_img = handel_img(img_png)

    res_TM_CCOEFF_NORMED = cv2.matchTemplate(img, small_img, 3)

    value = cv2.minMaxLoc(res_TM_CCOEFF_NORMED)

    value = value[3][0] # Get the moving distance

    return value

    


# 1. Open chromedriver and try to download pictures

cs = CrackSlider()

cs.get_pic()

# 2. Compare pictures and calculate distance

img_jpg_path = 'target.jpg' # Readers can modify the file path by themselves

img_png_path = 'template.png' # Readers can modify the file path by themselves

distance = match(img_jpg_path, img_png_path)

distance = distance /480 * 345 + 12

# 3. Move

cs.crack_slider(distance)

This ends today’s sharing. If the article is helpful to you, remember to like, collect, and follow it. I will share some useful information from time to time…