声明:滑块验证码更迭速度超快的,很多更替都体现在细节上,只有破解的过程中才能体会到真正的破解痛点,而本人是在18年中旬做的滑块验证码破解,所以最新版滑块验证码肯定是更新过好多次了的,因此本文主要提供一种破解思路,如果源码能给你带来直接借鉴作用那是最好。

废话不多说,直接上源码!

#--PANDA Edit--

from PIL import Image
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
import time,requests,random

class Verification_Code:

    #匹配原图
    def match_source(self,image):
        imagea=Image.open('d://source1.png')
        imageb=Image.open('d://source2.png')
        imagec=Image.open('d://source3.png')
        imaged=Image.open('d://source4.png')
        list=[imagea,imageb,imagec,imaged]
        #通过像素差遍历匹配本地原图
        for i in list:
            pixel1 = image.getpixel((868, 340))
            pixel2 = i.getpixel((868, 428))
            if abs(pixel1[0]-pixel2[0])<5:
                return i
        return image

    #对比RGB值得到缺口位置
    def is_similar(self,image1,image2,x,y):
        pixel1 = image1.getpixel((x, y + 88))
        pixel2 = image2.getpixel((x, y))
        if abs(pixel1[0] - pixel2[0]) >= 50 and abs(pixel1[1] - pixel2[1]) >= 50 and abs(pixel1[2] - pixel2[2]) >= 50:
            return False
        return True

    #计算滑块位移距离
    def get_diff_location(self,image1,image2):
        for i in range(825, 1082):
            for j in range(335, 463):
                if self.is_similar(image1,image2,i,j)==False:
                    return i
        return -1

    #滑块移动轨迹
    def get_track(self,distance):
        track=[]
        current=0
        mid=distance*7/8
        t=random.randint(2,3)/10
        v=0
        while current<distance:
            if current<mid:
                a=2
            else:
                a=-3
            v0=v
            v=v0+a*t
            move=v0*t+1/2*a*t*t
            current+=move
            track.append(round(move))
        return track

    #判断验证是否成功
    def check_success(self,image1,image2,driver,run):
        pixel1=image1.getpixel((1032,480))
        pixel2=image2.getpixel((1032,568))
        if abs(pixel1[0] - pixel2[0]) <10 and abs(pixel1[1] - pixel2[1])<10 and abs(pixel1[2] - pixel2[2])<10:
            return True
        else:
            if run<3:
                refresh=driver.find_element_by_class_name('geetest_refresh_1')
                refresh.click()
            return False

    #主程序
    def run(self,URL,token,phoneNumber):
        driver = webdriver.Chrome()
        # 打开页面
        driver.get('https://account.ch.com/NonRegistrations-Regist')
        driver.maximize_window()
        input1 = driver.find_element_by_name('phoneNumberInput')
        # 输入注册号码
        input1.send_keys(phoneNumber)
        time.sleep(0.2)
        getcheck=driver.find_element_by_id('getDynamicPwd')
        getcheck.click()
        flag0=1
        flag1=1
        run=1
        #循环验证
        while flag1==1:
                time.sleep(1)
                # 获取拖拽元素
                try:
                    slideblock = driver.find_element_by_class_name('geetest_slider_button')
                except:
                    print('网络延迟')
                    self.cancelRecv(URL, token, phoneNumber)
                    flag0=0
                    break
                ActionChains(driver).click_and_hold(slideblock).perform()
                ActionChains(driver).move_by_offset(xoffset=250, yoffset=0).perform()
                time.sleep(0.4)
                # 获取包含滑块及缺口截屏图片
                driver.save_screenshot('D:\quekou.png')
                # 放开拖拽元素
                ActionChains(driver).release(slideblock).perform()
                quekouimg=Image.open('d://quekou.png')
                # 匹配本地对应原图
                sourceimg=self.match_source(quekouimg)
                # 获取缺口位置
                visualstack=self.get_diff_location(sourceimg,quekouimg)
                # 获取移动距离loc
                loc=visualstack-827
                # 生成拖拽移动轨迹
                track_list=self.get_track(loc+3)
                time.sleep(2)
                ActionChains(driver).click_and_hold(slideblock).perform()
                time.sleep(0.2)
                # 根据轨迹拖拽滑块
                for track in track_list:
                    ActionChains(driver).move_by_offset(xoffset=track,yoffset=0).perform()
                # 模拟人工滑动超过缺口位置返回至缺口的情形,增加移动轨迹真实性
                imitate=ActionChains(driver).move_by_offset(xoffset=-1, yoffset=0)
                time.sleep(0.015)
                imitate.perform()
                time.sleep(random.randint(6,10)/10)
                imitate.perform()
                time.sleep(0.04)
                imitate.perform()
                time.sleep(0.012)
                imitate.perform()
                time.sleep(0.019)
                imitate.perform()
                time.sleep(0.033)
                ActionChains(driver).move_by_offset(xoffset=1, yoffset=0).perform()
                # 放开拖拽元素
                ActionChains(driver).pause(random.randint(7,14)/10).release(slideblock).perform()
                time.sleep(1)
                driver.save_screenshot('d:\checkpicture.png')
                checkimg=Image.open('d:\checkpicture.png')
                #判断是否验证成功
                if self.check_success(checkimg,sourceimg,driver,run):
                    time.sleep(3.5)
                    flag1 = 0
                    # 检查手机号码获取验证码次数是否已达上限
                    try:
                        driver.find_element_by_tag_name('button').click()
                        flag0 = 0
                        self.addBlacklist(URL, token, phoneNumber)
                        print('本号码注册获取验证码次数已达上限')
                    except:
                        print()
                run+=1
                if run>3 and flag1==1:  #判断多次循环后滑块验证码是否通过
                    self.cancelRecv(URL, token, phoneNumber)
                    flag0=0
                    break
        #填入验证码进行注册
        if flag0==1:
            count = 1
            while True:
                messageContent = requests.get(URL,"action=getMessage&sid=987&phone=" + phoneNumber + "&token=" + token).text
                # 截取头信息
                header = messageContent[0:messageContent.index("|")]
                #判断是否接收到验证码
                if header == '0':
                    time.sleep(3.5)
                    if count > 5:
                        self.addBlacklist(URL, token, phoneNumber)
                        break
                if header == '1':
                    messageInfo = messageContent[messageContent.index("|") + 1:len(messageContent)]
                    verificationCode = messageInfo[messageInfo.index("验证码:") + len("验证码:"):messageInfo.index(",",messageInfo.index("验证码:"))]
                    #填入验证码
                    driver.find_element_by_name('ValidateCode').send_keys(verificationCode)
                    #填入密码
                    driver.find_element_by_name('phonePassword').send_keys('wsk190120')
                    #确认密码
                    driver.find_element_by_name('phonePasswordConfirm').send_keys('wsk190120')
                    #点击注册
                    driver.find_element_by_id('dynamicRegist').click()
                    time.sleep(2)
                    #利用是否跳转页面判断是否成功注册
                    try:
                        driver.find_element_by_class_name('u-dialog-btn').click()
                        self.addBlacklist(URL, token, phoneNumber)
                    except:
                        print('注册成功')
                        f=open('d://output.txt','a+')
                        f.write('INSERT INTO map_chuser VALUES(null,'+'\''+phoneNumber+'\''+',\''+'wsk190120'+'\''+',0,0,1);'+'\n')
                        f.close()
                    break
                count+=1
        time.sleep(0.5)
        driver.close()

    #获取手机号码
    def getPhone(self,URL,loginInfo,token):
        phoneInfo = requests.get(URL, "action=getPhone&sid=987&token=" + token).text
        return phoneInfo[loginInfo.index("|") + 1:len(loginInfo)]

    #手机号码加黑
    def addBlacklist(self,URL,token,phoneNumber):
        requests.get(URL, "action=addBlacklist&sid=987&phone=" + phoneNumber + "&token=" + token)

    #手机号码释放
    def cancelRecv(self,URL,token,phoneNumber):
        requests.get(URL,'action=cancelRecv&sid=987&phone='+phoneNumber+'&token='+token)

    #生成随机密码
    '''def random_str(self,randomlength):
        str = ''
        chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789'
        length = len(chars) - 1
        for i in range(randomlength):
            str += chars[random.randint(0, length)]
        return str'''

if __name__=='__main__':
    auto_logon = Verification_Code()
    URL = "http://www.ximahuang.com/alz/api"
    for i in range(5):
        try:
            print(i)
            #开发者登录吸码皇
            loginInfo = requests.get(URL,b'action=loginIn&name=xtpa001&password=190120&developer=developer=df64aff97eb04560af80ba7834f4e6c9').text
            #截取登录令牌
            token = loginInfo[loginInfo.index("|") + 1:len(loginInfo)]
            #获取用户信息
            userInfo = requests.get(URL, "action=getSummary&token=" + token)
            #获取手机号码
            phoneNumber = auto_logon.getPhone(URL,loginInfo, token)
            #获取验证码进行验证注册
            auto_logon.run(URL,token,phoneNumber)
        except:
            print('注册提前结束!')
    print('程序结束!')