前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >基于selenium自动化的滑动验证码破解

基于selenium自动化的滑动验证码破解

作者头像
andrew_a
发布2019-07-30 14:47:47
1.5K0
发布2019-07-30 14:47:47
举报

常见的滑动验证码就是哔哩哔哩了,就以哔哩哔哩作为例子

1、拿到完整图片

2、拿到有缺口的图片

3、计算滑动距离

4、滑动(如何避免被识别出来)

当鼠标放在上面不点击的时候,就会产生完整的图

当点击的时候就会出现有缺口的图片

在图片上右击检查,就会到图片的位置

然后打开图片的URL,你会发现这是一个乱序的图片

如何解决这个问题,

第一种解决办法:

就是将获取到的图片的按照前端的顺序,重新拼接

代码语言:javascript
复制
def get_merge_image(self, filename, location_list):
    """
    合并图像,并还原图像
    :return:
    """
    im = image.open(filename)
    new_im = image.new('RGB', (260, 116))  # width 260px, height 116px
    im_list_upper = []
    im_list_down = []  # 以列表形式储存按照一定的顺序储存图片碎片
    for location in location_list:  # 截取对应位置的图,并添加到列表中
        if location['y'] == -58:
            im_list_upper.append(im.crop((abs(location['x']), 58, abs(location['x'])+10, 166)))
        if location['y'] == 0:
            im_list_down.append(im.crop((abs(location['x']), 0, abs(location['x']) + 10, 58)))

    x_offset = 0
    for im in im_list_upper:
        new_im.paste(im, (x_offset, 0))
        x_offset += im.size[0]
    x_offset = 0
    for im in im_list_down:
        new_im.paste(im, (x_offset, 58))
        x_offset += im.size[0]
    new_im.save(filename)
    time.sleep(1)
    # 将图片碎片组合到复制到新图片上 
    return new_im

第二种:

截图,分别截图,完整的时候截一次图(截图全屏),不用管是否乱序,获取图片的坐标,将截图再次按照坐标截图处理,这样就能获得完整的图和有缺口的图。

代码语言:javascript
复制
def get_image(driver):
    img = driver.find_element_by_class_name('gt_cut_fullbg')
    time.sleep(2)
    location = img.location
    size = img.size
    left = location['x']
    top = location['y']
    right = left + size['width']
    bottom = top + size['height']

    page_snap_obj = get_snap(driver)
    image_obj = page_snap_obj.crop((left, top, right, bottom))
    # image_obj.show()
    return image_obj
代码语言:javascript
复制
def get_snap(driver):
    driver.save_screenshot('full_snap.png')
    page_snap_obj = Image.open('full_snap.png')
    return page_snap_obj

使用PIL裁切图片

使用PIL需要引用Image,使用Image的open(file)方法可以返回打开的图片,使用crop((x0,y0,x1,y1))方法可以对图片做裁切。

区域由一个4元组定义,表示为坐标是 (left, upper, right, lower),Python Imaging Library 使用左上角为 (0, 0)的坐标系统

box(100,100,200,200)就表示在原始图像中以左上角为坐标原点,截取一个100*100(像素为单位)的图像,为方便理解,如下为示意图box(b1,a1,b2,a2)

这样我们就拿到了图片一个是完整的,一个是有缺口的。

第三步就是计算要滑动的距离了

代码语言:javascript
复制
def is_pixel_equal(self, img1, img2, x, y):
    """
    判断两个像素是否相同
    :param img1:
    :param img2:
    :param x: 位置x
    :param y: 位置y
    :return:
    """
    # 取两张图片的像素点
    pix1 = img1.load()[x, y]
    pix2 = img2.load()[x, y]
    threshold = 60
    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
代码语言:javascript
复制
def get_pag(self, img1, img2):
    """
    获取偏移量
    :param img1:不带缺口
    :param img2:带缺口
    :return:
    """
    left = 43
    for i in range(left, img1.size[0]):
        for j in range(img1.size[1]):
            if not self.is_pixel_equal(img1, img2, i, j):
                left = i
                return left
    return left

得到了滑动的距离就是计算如何去滑动了

代码语言:javascript
复制
def get_track(self, distance):
    """
    根据偏移量获取移动轨迹
    :param distance:
    :return:
    """
    distance += 24
    # 移动轨迹
    track = []
    # 当前位移
    current = 0
    # 减速阀值
    mid = distance * 3 / 5
    # 计算阀值
    t = 0.2
    # 计算初速度
    v = 0
    while current < distance:
        if current < mid:
            # 加速度
            a = 2
        else:
            # 加速度为-3
            a = -3
        # 初速度为
        v0 = v
        # 移动距离x = v0t+1/2*a^2
        move = v0*t + 1/2*a*t*t
        # 当前位移
        current += move
        # 加入轨迹
        track.append(round(move))
        # 速度已到达v,该速度作为下次的初速度
        v = v0 + a*t
    # track = [-3, -3, -2, -2, -2, -2, -2, -1, -1, -1]
    return track
代码语言:javascript
复制
def get_track(self, x_offset):

        track = list()
        length = x_offset - 6
        x = random.randint(1,5)
        while length - x >4:
            track.append([x,0,0])
            length=length - x
            x= random.randint(1,15)

        for i in range(length):
            if x_offset>47:
                track.append([1,0,random.randint(10,12)/100.0])
            else:
                track.append([1, 0, random.randint(13, 14)/100.0])
        return track

上面是两种获取移动轨迹的方式,大家可以自己试一下,那个效率更高。

最后就是控制滑块去滑动了

代码语言:javascript
复制
def move_to_gap(self, slider, track):
    """
    拖动滑块到缺口处
    :param slider: 滑块
    :param track: 轨迹
    :return:
    """
    ActionChains(self.browser).click_and_hold(slider).perform()
    while track:
        x = random.choice(track)
        ActionChains(self.browser).move_by_offset(xoffset=x, yoffset=0).perform()
        track.remove(x)
    tracks = [-3, -3, -3, -2, -2, -2, -2, -2, -1, -1, -1, -1]
    time.sleep(0.5)

    for track in tracks:
        ActionChains(self.browser).move_by_offset(xoffset=track, yoffset=0).perform()
    # 小范围震荡一下,进一步迷惑极验后台,这一步可以极大地提高成功率
    ActionChains(self.browser).move_by_offset(xoffset=-1, yoffset=0).perform()
    ActionChains(self.browser).move_by_offset(xoffset=1, yoffset=0).perform()

    time.sleep(0.5)
    ActionChains(self.browser).release().perform()
代码语言:javascript
复制
def simulate_drag(self, track):

        dom_div_slider = self.browser.find_element_by_xpath('//*[@id="gc-box"]/div/div[3]/div[2]')

        ActionChains(self.browser).click_and_hold(on_element=dom_div_slider).perform()

        for x,y,z in track:
            ActionChains(self.browser).move_to_element_with_offset(
                to_element=dom_div_slider,
                xoffset=x+22,
                yoffset=y+22).perform()
            time.sleep(z)

        time.sleep(0.9)
        ActionChains(self.browser).release(on_element=dom_div_slider).perform()
        time.sleep(1)
        dom_div_gt_info = self.browser.find_element_by_class_name('gt_info_type')
        return dom_div_gt_info.text

试试两种不同的滑动方式有什么不同

方法都给大家了,大家可以自己多试试,找出最高效的滑动方式,

如果碰到其他的滑动验证码只需修改元素的定位,思路一样

关于ActionChains,不懂的就去查查

最后源码地址:https://github.com/AndrewAndrea/check_img_code

不要忘了star, 谢谢!

有问题可以留言

抖音剩下的下次的更新,如何破解api,还有appnium 的使用。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-04-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Python爬虫scrapy 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
验证码
腾讯云新一代行为验证码(Captcha),基于十道安全栅栏, 为网页、App、小程序开发者打造立体、全面的人机验证。最大程度保护注册登录、活动秒杀、点赞发帖、数据保护等各大场景下业务安全的同时,提供更精细化的用户体验。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档