I. Introduction:

This content is for technical communication only, please do not make commercial use. This method uses the form of a locally built server to verify the sliding verification code of the algorithm as shown in the figure below:Copy the code

Two. Local test environment construction

The construction of a local test environment is described in detail in the CSDN article. Detailed see/blog address (https://blog.csdn.net/mouday/article/details/83384633)/demo address (https://github.com/mouday/TencentCaptcha)Copy the code

Iii. Introduction of identification ideas

Sliding verification needs to be solved: sliding distance calculation, sliding trajectory simulation, simulation of sliding **Copy the code

1. Calculation of sliding distance

If the verification code is obtained through packet capture, the verification code returns the following two pictures:

2. Unnotched complete background image acquisition:

Complete the background image acquisition in addition to the online article mentioned has been through a lot of gaps in the image segmentation after restructuring tectonic background and sliding finish validation complete screenshots two plans, actually can also directly through the interface to get the full background image, the interests involved in relevant platform, so here to directly by interface for complete method does not make detailed introduction of the background image. But the 10 background images involved will be given:

3. How to find the corresponding unnotched image from the 10 background images after getting the notched image:

Method 1: Directly with pictures of the gap and 10 background image subtraction, statistical difference is greater than the threshold value by the number of pixels, the threshold setting 60, the number of pixels is set to the gap size, about 6000 points, if the difference is more than 60 points number is more than 6000 think pictures not corresponding to the complete background, with 10 background to iterate over, Find the corresponding background graph and return the corresponding target graph path

def get_full_pic(bg_image):
    ' '':param gap_pic: Notched image :return: (STR) Background image path'' '
    Convert the image to grayscale
    img1 = bg_image.convert('L')
    distance = 68     # Since the gap position is at the back of the picture, to reduce the calculation, we can reduce part of the comparison
    threshold = 60
    dir = ""
    for k inRange (1, 11) : dir =".. /background/"+str(k)+".jpg"
        fullbg_image = Image.open(dir)
        img2 = fullbg_image.convert('L')
        diff = 0
        for i in range(distance, img1.size[0]):
            Walk through the ordinate of the pixels
            for j in range(img1.size[1]):
                # If not the same pixel
                img1_pixe = img1.load()[i,j]
                img2_pixe = img2.load()[i,j]
                if abs(img1_pixe - img2_pixe) > threshold:
                    diff = diff + 1
            if diff > 6000:
                break
                # Different pixels above a certain value are considered mismatched.
                # In the later calculation, the initial position data can be returned based on the image verification code.
                # When comparing images, you can remove the data in some areas of the image
            elif i == img1.size[0]-1 and j == img1.size[1]-1:
                print("Find the target")
                return dir
    return dir
Copy the code

Algorithm 2: Because algorithm 1 requires a large amount of calculation, it takes about 1s to find the target during the test. Therefore, only four points on the picture need to be compared, and the selection principle of these four points is as scattered as possible (the pixel values of adjacent points are relatively close).

The code is as follows: select pixels at (50,50) (50,250), (250,50) and (250,250) points on the picture as comparison points, and the improved algorithm saves 1s time compared with algorithm 1

# Find the background target image
def get_full_pic_new(bg_image):
    img1 = bg_image.convert("L")
    dir = ""
    threshold = 60 
    for k inRange (1, 11) : dir =".. /background/"+str(k)+".jpg"   #10 background image corresponding path
        fullbg_image = Image.open(dir)
        img2 = fullbg_image.convert('L')       No need for three channels to compare
        pix11 = img1.load()[50, 50]
        pix12 = img1.load()[50, 250]
        pix13 = img1.load()[250, 50]
        pix14 = img1.load()[250, 250]

        pix21 = img2.load()[50, 50]
        pix22 = img2.load()[50, 250]
        pix23 = img2.load()[250, 50]
        pix24 = img2.load()[250, 250]
        if abs(pix11 - pix21)>threshold or abs(pix12 - pix22)>threshold or abs(pix13 - pix23)>threshold or abs(pix14 - pix24)>threshold:
            continue
        else:
            if abs(pix11 - pix21)<threshold and abs(pix12 - pix22)<threshold and abs(pix13 - pix23)<threshold and abs(pix14 - pix24)<threshold:
                print("Find the target:", dir)
                break
            else:
                print("Not found")
                dir = None
    return dir
Copy the code

After the corresponding background image is found, the distance calculation algorithm is consistent with the polar verification code calculation method, which will not be described in detail here. The complete distance calculation module is as follows:

#! /usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2019/3/22 13:25
# @File : get_distance.py
from PIL import Image
def is_pixel_equal(img1, img2, x, y):
    ""Param image1: image1: param image2: image2: param x: position x: param y: position y: return: pixels are the same""
    # Take two pixels of the image
    pix1 = img1.load()[x, y]
    pix2 = img2.load()[x, y]
    threshold = 68
    if (abs(pix1[0] - pix2[0] < threshold) and abs(pix1[1] - pix2[1] < threshold) and abs(pix1[2] - pix2[2] < threshold )):
        return True
    else:
        return False
def get_gap(img1, img2):
    ""Param img2: notched image :param img2: notched image :param img2: Notched image :return:""
    left = 68
    for i in range(left, img1.size[0]):
        for j in range(img1.size[1]):
            if not is_pixel_equal(img1, img2, i, j):
                left = i
                print(i)
                return left
    return left
def get_full_pic_new(bg_image):
    img1 = bg_image.convert("L")
    dir = ""
    threshold = 60
    for k inRange (1, 11) : dir =".. /background/"+str(k)+".jpg"
        fullbg_image = Image.open(dir)
        img2 = fullbg_image.convert('L')
        pix11 = img1.load()[50, 50]
        pix12 = img1.load()[50, 250]
        pix13 = img1.load()[250, 50]
        pix14 = img1.load()[250, 250]

        pix21 = img2.load()[50, 50]
        pix22 = img2.load()[50, 250]
        pix23 = img2.load()[250, 50]
        pix24 = img2.load()[250, 250]
        if abs(pix11 - pix21)>threshold or abs(pix12 - pix22)>threshold or abs(pix13 - pix23)>threshold or abs(pix14 - pix24)>threshold:
            continue
        else:
            if abs(pix11 - pix21)<threshold and abs(pix12 - pix22)<threshold and abs(pix13 - pix23)<threshold and abs(pix14 - pix24)<threshold:
                print("Find the target:", dir)
                break
            else:
                print("Not found")
                dir = None
    return dir
def get_full_pic(bg_image):
    ' '':param gap_pic: Notched image :return: (STR) Background image path'' '
    Convert the image to grayscale
    img1 = bg_image.convert('L')
    distance = 68
    threshold = 60
    dir = ""
    for k inRange (1, 11) : dir =".. /background/"+str(k)+".jpg"
        fullbg_image = Image.open(dir)
        img2 = fullbg_image.convert('L')
        diff = 0
        for i in range(distance, img1.size[0]):
            Walk through the ordinate of the pixels
            for j in range(img1.size[1]):
                # If not the same pixel
                img1_pixe = img1.load()[i,j]
                img2_pixe = img2.load()[i,j]
                if abs(img1_pixe - img2_pixe) > threshold:
                    diff = diff + 1
            if diff > 6000:
                break
                # Different pixels above a certain value are considered mismatched.
                # In the later calculation, the initial position data can be returned based on the image verification code.
                # When comparing images, you can go to the data in part of the image
            elif i == img1.size[0]-1 and j == img1.size[1]-1:
                print("Find the target")
                return dir
    return dir
def get_distanct(bg_image):
    bg_img = Image.open(bg_image)
    full_dir = get_full_pic_new(bg_img)
    full_img = Image.open(full_dir)
    return get_gap(full_img, bg_img)
if __name__=="__main__":
    import time
    time_start = time.time()
    print("--"* 20 +"run"+"--"*20)
    dir = ".. /gap_pic/8.jpg"
    distanct = get_distanct(dir)
    time_end = time.time()
    print('totally cost', time_end - time_start)
    print(distanct)
Copy the code

Slide to verify the complete demo

#! /usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2019/4/1 11:12
# @File : tx_test.pyimport json from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from  selenium.common.exceptions import TimeoutException from selenium.webdriver.common.action_chains import ActionChains from lxml import etree from get_distanct import get_distanct import time import requests import random import numpy as np from scipy import stats import math class tx_test(object): def __init__(self): self.driver = webdriver.Chrome() self.driver.maximize_window()Set up an intelligent wait
        self.wait = WebDriverWait(self.driver, 5)
        self.url = "http://127.0.0.1:8080/"
    def get_track(self, distance):
        """Param distance: offset :return: move path"""
        # Movement trajectory
        track = []
        # Current displacement
        current = 0
        # Deceleration threshold
        mid = distance * 4 / 5
        # compute intervalT = 0.2# velocityV = 0.1 r = [1.1, 1.2, 1.3, 1.4, 1.5] p = [2, 2.5, 2.8, 3, 3.5, 3.6] q = 5.0 I = 0while current < distance:
            if current < mid:
                The acceleration is plus 2A is equal to 2, and q is equal to q times 0.9else:
                The acceleration is minus 3Q is equal to 1.0, and a is equal to negative 3# initial velocity v0
            v0 = v
            V = v0 + at
            v = v0 + a * t
            X = v0t + 1/2 * a * t^2
            r1 = random.choice(r)
            p1 = random.choice(p)
            move = r1 * v0 * t + 1 / p1 * a * t * t * q
            # Current displacement
            ifi == 2: Currentdis = (distance-current)/random. Choice ([3.5, 4.0, 4.5, 5]) current += currentdis track.append(round(currentdis))elifi == 4: Currentdis = (distance-current)/random. Choice ([4.0, 5.0, 6.0, 7.0]) current += currentdis track.appEnd (round(currentdis))else:
                current += move
                track.append(round(move))
            # Add trajectory
            i = i + 1
        return track
    def get_slider(self, browser):
        """Get slider :return: slider object"""
        slider = None
        while True:
            try:
                slider = self.wait.until(EC.presence_of_element_located((By.XPATH,'//*[@id="tcaptcha_drag_thumb"]')))
                break
            except:
                break
        return slider

    def move_to_gap(self, browser, slider, track):
        """Drag the slider to the slot :param slider: param track: return:"""ActionChains (browser). Click_and_hold (the slider). The perform () time. Sleep (0.5)whiletrack: x = random.choice(track) y = random.choice([-2, -1, 0, 1, 2]) ActionChains(browser).move_by_offset(xoffset=x, Yoffset = y). The perform () track. Remove t = (x). The random choice ([0.002, 0.003, 0.004, 0.005, 0.006]) time. Sleep (t) time. Sleep (1) ActionChains(browser).release(on_element=slider).perform() def login(self):while True:
            self.driver.get(self.url)
            self.driver.delete_all_cookies()
            currhandle = self.driver.current_window_handle
            while True:
                try:
                    self.driver.switch_to_window(currhandle)
                except Exception as e:
                    print(e)
                try:
                    verify_Bt = self.wait.until(EC.element_to_be_clickable((By.XPATH,'//*[@id="TencentCaptcha"]')))   Is the button clickable
                    verify_Bt.click()
                except Exception as e:
                    self.driver.refresh()
                    continue
                try:
                    # if flag is not 0:
                    iframe = self.wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="tcaptcha_iframe"]')))
                    time.sleep(5)
                    self.driver.switch_to.frame(iframe)     Failed to switch to iframe
                    # Check if there is a slide verification code, slide if there is a slide verification code
                    Sliding_Pic = self.wait.until(EC.presence_of_element_located((By.XPATH,'//*[@id="slideBgWrap"]/img')))
                    for i in range(5):
                        page = self.driver.page_source
                        selector = etree.HTML(page)
                        bg_imgSrc = selector.xpath('//*[@id="slideBgWrap"]/img/@src')[0]
                        res = requests.get(bg_imgSrc)
                        with open("./bg_img.jpg"."wb") as fp:
                            fp.write(res.content)
                        # Calculate the slider sliding distance
                        dist = get_distanct("./bg_img.jpg")
                        print("Print sliding distance :",dist)
                        dist = int((dist)/2-34)
                        # Get slide track
                        print(dist)
                        track = self.get_track(dist)
                        print(track)
                        print(sum(track))
                        err = (dist-sum(track))   # Distance correction
                        print(err)
                        # get slider
                        track.append(err)
                        slide = self.get_slider(self.driver)
                        # Slide slider
                        self.move_to_gap(self.driver,slide,track)
                        time.sleep(2)
                        slide = self.get_slider(self.driver)
                        if slide:
                            continue
                        else:
                            print("Sliding verified pass")
                            break
                except Exception as e:
                    print("Slip anomaly")
                    time.sleep(5)
                    break
if __name__=="__main__":
    print("test\n")
    login = tx_test()
    login.login()
Copy the code

Summary and Description

Py, get_distance.py and create background image folder background(which stores 10 background images and names them 1.jpg~10.jpg). Then start the local slide test environment and configure the IP port of the actual server address port. After the sliding is completed, the screenshot is as follows: The trajectory algorithm adds some adjustments on the basis of referring to other polar trajectory simulation algorithms, see the code for details.

In addition to automatic identification of sliding verification codes by Selenium direct simulation sliding, sliding verification codes can also be recognized by directly constructing submission parameters. The specific principle and analysis will be introduced in detail in the next article, and another trajectory simulation algorithm (based on normal distribution curve trajectory simulation algorithm) will be presented in the next article.