滑块验证码(腾讯)——基于selenium,pillow实现

摘要:
与互联网上的其他滑块验证码不同,腾讯的验证码可以直接通过url请求获得。您只需要进一步分析url,提取验证码原始地图的地址,然后下载图像。然而,根据我的观察,url似乎有两种不同类型的地址格式,需要具体分析。在这里,选择其中一个进行实验。源代码在文章末尾。

  与网上的其他滑块验证码不同,腾讯的验证码可以直接通过url请求得到,只需要对url进一步分析,提取出验证码原图的地址,并将图片下载即可。

但据我观察,该url似乎是有两种不同类型的地址格式,需要具体分析。这里,选择其中一种进行实验,源码在文章末尾。

滑块验证码(腾讯)——基于selenium,pillow实现第1张滑块验证码(腾讯)——基于selenium,pillow实现第2张
    def get_img(self):
        """
        获取验证码阴影图和原图
        :return:
        """
        self.driver.switch_to.frame('tcaptcha_iframe')
        time.sleep(3)
        # 获取有阴影的图片
        src = self.driver.find_element_by_id('slideBg').get_attribute('src')
        #  分析图片地址,发现原图地址可以通过阴影图地址改动获取
        src_bg = re.sub('_1_', '_0_', src)
        urlretrieve(src, 'img1.png')
        urlretrieve(src_bg, 'img2.png')
获取图片,保存到本地

  有一个需要注意的问题,下载到本地的图片对原图进行了放大,所以要对图片尺寸进行调整还原,保证后面计算出的偏移值的正确性

滑块验证码(腾讯)——基于selenium,pillow实现第1张滑块验证码(腾讯)——基于selenium,pillow实现第2张
def resize_img(self, img):
        """
        下载的图片把网页中的图片进行了放大,所以将图片还原成原尺寸
        :param img: 图片
        :return: 返回还原后的图片
        """
        a = 2.428  # 通过本地图片与原网页图片的比较,计算出的缩放比例
        (x, y) = img.size
        x_resize = int(x // a)
        y_resize = int(y // a)
        img = img.resize((x_resize, y_resize), Image.ANTIALIAS)
还原图片尺寸

  此时,已经拿到原图和阴影图,只需要进行像素比较即可,网上有其他相关教程,可参考

滑块验证码(腾讯)——基于selenium,pillow实现第1张滑块验证码(腾讯)——基于selenium,pillow实现第2张
    def is_pixel_equal(self, img1, img2, x, y):
        """
        比较两张图片同一点上的像数值,差距大于设置标准返回False
        :param img1: 阴影图
        :param img2: 原图
        :param x: 横坐标
        :param y: 纵坐标
        :return: 是否相等
        """
        pixel1, pixel2 = img1.load()[x, y], img2.load()[x, y]
        sub_index = 100
        if abs(pixel1[0] - pixel2[0]) < sub_index and abs(pixel1[1] - pixel2[1]) < sub_index and abs(
                pixel1[2] - pixel2[2]) < sub_index:
            return True
        else:
            return False

    def get_gap_offset(self, img1, img2):
        '''
            获取缺口的偏移量
        '''
        offset = None
        distance = 70
        for i in range(distance, img1.size[0]):
            for j in range(img1.size[1]):
                # 两张图片对比,(i,j)像素点的RGB差距,过大则该x为偏移值
                if not self.is_pixel_equal(img1, img2, i, j):
                    offset = i
                    return offset
        return offset
计算偏移值

  最后,通过selenuim的动作链,模拟滑块拖动

滑块验证码(腾讯)——基于selenium,pillow实现第1张滑块验证码(腾讯)——基于selenium,pillow实现第2张
    def operate_slider(self, track):
        """
        拖动滑块
        :param track: 运动轨迹
        :return:
        """
        #  定位到拖动按钮
        slider_bt = self.driver.find_element_by_xpath('//div[@class="tc-drag-thumb"]')
        # 点击拖动按钮不放
        ActionChains(self.driver).click_and_hold(slider_bt).perform()
        # 按正向轨迹移动
        for i in track:
            ActionChains(self.driver).move_by_offset(xoffset=i, yoffset=0).perform()
            time.sleep(random.random() / 100)  # 每移动一次随机停顿0-1/100秒之间骗过了极验,通过率很高
        time.sleep(random.random())
        # 按逆向轨迹移动
        back_tracks = [-1, -0.5, -1]
        for i in back_tracks:
            time.sleep(random.random() / 100)
            ActionChains(self.driver).move_by_offset(xoffset=i, yoffset=0).perform()
        # 模拟人手抖动
        self.shake_mouse()
        time.sleep(random.random())
        # 松开滑块按钮
        ActionChains(self.driver).release().perform()
模拟滑块拖动

  下面附上完整的代码,仅供参考,不足之处,欢迎大家指正

滑块验证码(腾讯)——基于selenium,pillow实现第1张滑块验证码(腾讯)——基于selenium,pillow实现第2张
import time
import re
import random
from selenium import webdriver
from urllib.request import urlretrieve
from PIL import Image
from selenium.webdriver.common.action_chains import ActionChains


class Tencent():
    def __init__(self):
        """
        初始化属性,传入url地址,驱动路径,浏览器窗口最大化,伪造ua
        """
        self.url = 'https://qzone.qq.com/'
        driver_path = r'C:UsersxiaodengtangAppDataLocalGoogleChromeApplicationchromedriver.exe'
        self.driver = webdriver.Chrome(executable_path=driver_path)
        self.driver.maximize_window()
        self.headers = {
            'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36'}

    def input_username_password(self, account, password):
        """
        打开浏览器,传入账号、密码,定位到登录窗口,切换登陆方式
        :param account:
        :param password:
        :return:
        """
        self.driver.get(self.url)
        time.sleep(1)
        self.driver.switch_to.frame('login_frame')
        self.driver.find_element_by_id('switcher_plogin').click()
        time.sleep(1)
        self.driver.find_element_by_id('u').send_keys(account)
        time.sleep(0.5)
        self.driver.find_element_by_id('p').send_keys(password)
        time.sleep(0.5)
        self.driver.find_element_by_class_name('login_button').click()

    def get_img(self):
        """
        获取验证码阴影图和原图
        :return:
        """
        self.driver.switch_to.frame('tcaptcha_iframe')
        time.sleep(3)
        # 获取有阴影的图片
        src = self.driver.find_element_by_id('slideBg').get_attribute('src')
        #  分析图片地址,发现原图地址可以通过阴影图地址改动获取
        src_bg = re.sub('_1_', '_0_', src)
        urlretrieve(src, 'img1.png')
        urlretrieve(src_bg, 'img2.png')
        captcha1 = Image.open('img1.png')
        captcha2 = Image.open('img2.png')
        return captcha1, captcha2

    def resize_img(self, img):
        """
        下载的图片把网页中的图片进行了放大,所以将图片还原成原尺寸
        :param img: 图片
        :return: 返回还原后的图片
        """
        a = 2.428  # 通过本地图片与原网页图片的比较,计算出的缩放比例
        (x, y) = img.size
        x_resize = int(x // a)
        y_resize = int(y // a)
        img = img.resize((x_resize, y_resize), Image.ANTIALIAS)
        return img

    def is_pixel_equal(self, img1, img2, x, y):
        """
        比较两张图片同一点上的像数值,差距大于设置标准返回False
        :param img1: 阴影图
        :param img2: 原图
        :param x: 横坐标
        :param y: 纵坐标
        :return: 是否相等
        """
        pixel1, pixel2 = img1.load()[x, y], img2.load()[x, y]
        sub_index = 100
        if abs(pixel1[0] - pixel2[0]) < sub_index and abs(pixel1[1] - pixel2[1]) < sub_index and abs(
                pixel1[2] - pixel2[2]) < sub_index:
            return True
        else:
            return False

    def get_gap_offset(self, img1, img2):
        '''
            获取缺口的偏移量
        '''
        offset = None
        distance = 70
        for i in range(distance, img1.size[0]):
            for j in range(img1.size[1]):
                # 两张图片对比,(i,j)像素点的RGB差距,过大则该x为偏移值
                if not self.is_pixel_equal(img1, img2, i, j):
                    offset = i
                    return offset
        return offset

    def get_track(self, offset):
        '''
        计算滑块的移动轨迹
        '''
        offset -= 30  # 滑块并不是从0开始移动,有一个初始值
        a = offset / 4
        track = [a, a, a, a]
        return track

    def shake_mouse(self):
        """
        模拟人手释放鼠标抖动
        :return: None
        """
        ActionChains(self.driver).move_by_offset(xoffset=-2, yoffset=0).perform()
        ActionChains(self.driver).move_by_offset(xoffset=2, yoffset=0).perform()

    def operate_slider(self, track):
        """
        拖动滑块
        :param track: 运动轨迹
        :return:
        """
        #  定位到拖动按钮
        slider_bt = self.driver.find_element_by_xpath('//div[@class="tc-drag-thumb"]')
        # 点击拖动按钮不放
        ActionChains(self.driver).click_and_hold(slider_bt).perform()
        # 按正向轨迹移动
        for i in track:
            ActionChains(self.driver).move_by_offset(xoffset=i, yoffset=0).perform()
            time.sleep(random.random() / 100)  # 每移动一次随机停顿0-1/100秒之间骗过了极验,通过率很高
        time.sleep(random.random())
        # 按逆向轨迹移动
        back_tracks = [-1, -0.5, -1]
        for i in back_tracks:
            time.sleep(random.random() / 100)
            ActionChains(self.driver).move_by_offset(xoffset=i, yoffset=0).perform()
        # 模拟人手抖动
        self.shake_mouse()
        time.sleep(random.random())
        # 松开滑块按钮
        ActionChains(self.driver).release().perform()

    def login(self, account, password):
        '''
        实现主要的登陆逻辑
        '''
        self.input_username_password(account, password)
        time.sleep(2)
        a, b = self.get_img()
        a = self.resize_img(a)
        b = self.resize_img(b)
        distance = self.get_gap_offset(a, b)
        track = self.get_track(distance)
        self.operate_slider(track)


if __name__ == '__main__':
    qq = Tencent()
    account = '123548658'
    password = 'yanzhengma'
    qq.login(account, password)
完整代码

免责声明:文章转载自《滑块验证码(腾讯)——基于selenium,pillow实现》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇【存储】RAID磁盘阵列选择ffmpeg文档17-视频编码器下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

随便看看

html,js简单保存textarea换行格式

有时我们需要在提交表单时保存html标记,但textarea不保存换行信息,因此我们需要使用js保存HTM标记,例如textarea的换行。˃˃g、 “”);这只是一个允许在js中保留HTML文本区域中的换行符和其他格式的模型。你需要开发它来满足你的需求。希望岑溪网站开发分享的内容对您有所帮助!...

C# winform开发嵌套Chrome内核浏览器(WebKit.net)开发(一)

//Www.cnblogs.com/Maxq/p/6566558.htmlWebKit.net是WebKit的一个net包。使用它,。net程序可以非常方便地集成和使用webkit作为加载网页的容器。EventArgse){WebKit.WebKitBrowser=newWebKitBrowser();this.Controls.Add(浏览器);...

安装gulp教程(整理)

所以安装nodejs。...

记一次Arcgis Server10.2许可过期导致发布图层失败

1.今天,当使用arcmap将地图服务发布到arcgisserver时,发布突然失败。在arcgisserver的管理页面的日志选项中发现错误:未能初始化服务器对象“System/PublicingTools”:0x80004005:错误:(-8003)YourArcGISServerlicense已过期。2.然后在服务器路径中查找文件:...

使用Docker构建redis集群

将六个独立的Redis节点关联到主机上的Redis集群中。Redis部落。rb是Redis官方提供的一个ruby脚本,用于构建Redis集群并修改Redis conf将其移动到上部路径/usr/docker_root/redis_Cluster/。受保护模式norequipassa1s2W3l4%Greunbind无法连接到凹坑以构建Redis基本映像。9....

js 浏览器窗口 刷新、关闭事件

当前页面不会直接关闭,可以点击确定按钮关闭或刷新,也可以取消关闭或刷新。...