拖动式验证码

拖动式验证码

问题点:

1、无法直接通过发送url请求来实现鼠标拖动的动作;

2、实际的背景图片是乱的,并不是我们实际肉眼看到的图像!

3、“开创行为判别算法,利用数据挖掘和机器学习,提取超过200多个行为判别特征,建立坚若磐石的多维验证防御体系。”这是官网的描述,听上去就已经很高大上,查了些资料也都说拖动轨迹的识别是geetest的核心内容而无过多的表述,那么这也应该是主要的难点了

提供的是一种思路:

1、获取图片,调整拼接

2、计算图片缺口(这个实例的计算不太理想)

3、生成移动轨迹(模拟)

4、滑动

安装geetest实例

首先自己安装配置一份geetest的样例。虽然geetest官网上有样例,但有时候反应比较慢,而且后面研究拖动轨迹的时候还需要对样例做一定的改动。编程语言我使用的是python2.7,所以这里选择的也是python版本的。

安装git:

[root@mysql-test1 ~]# yum install git

 在github中clone出最新Demo项目:

[root@mysql-test1 ~]# git clone https://github.com/GeeTeam/gt-python-sdk.git

 安装GeetestSDK:

[root@mysql-test1 ~]# cd gt-python-sdk/
[root@mysql-test1 gt-python-sdk]# python setup.py install

 安装Django,要注意的是最新的Django-1.10.1和当前的GeetestSDK是有兼容性问题的,要用Django-1.8.14:

[root@mysql-test1 ~]# wget --no-check-certificate  https://www.djangoproject.com/download/1.8.14/tarball/
[root@mysql-test1 ~]# tar zxvf Django-1.8.14.tar.gz
[root@mysql-test1 ~]# cd Django-1.8.14
[root@mysql-test1 Django-1.8.14]# python setup.py install

 后面就可以直接运行了:

[root@mysql-test1 ~]# cd gt-python-sdk/demo/django_demo/
[root@mysql-test1 django_demo]# python manage.py runserver 0.0.0.0:8000

 解析过程:

#!/usr/local/bin/python
# -*- coding: utf8 -*-

from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.action_chains import ActionChains
import PIL.Image as image
# from PIL import Image
import time, re, cStringIO, urllib2, random


def get_merge_image(filename,location_list):
    '''
    根据位置对图片进行合并还原
    :filename:图片
    :location_list:图片位置
    '''
    pass

    im = image.open(filename)

    new_im = image.new('RGB', (260, 116))

    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)))

    new_im = image.new('RGB', (260,116))

    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]

    return new_im


def get_image(driver,div):
    '''
    下载并还原图片
    :driver:webdriver
    :div:图片的div
    '''
    pass

    # 找到图片所在的div
    background_images = driver.find_elements_by_xpath(div)

    location_list = []

    imageurl = ''

    for background_image in background_images:
        location={}

        # 在html里面解析出小图片的url地址,还有长高的数值
        location['x']=int(re.findall("background-image: url("(.*)"); background-position: (.*)px (.*)px;",background_image.get_attribute('style'))[0][1])
        location['y']=int(re.findall("background-image: url("(.*)"); background-position: (.*)px (.*)px;",background_image.get_attribute('style'))[0][2])
        imageurl = re.findall("background-image: url("(.*)"); background-position: (.*)px (.*)px;",background_image.get_attribute('style'))[0][0]

        location_list.append(location)

    imageurl = imageurl.replace("webp", "jpg")

    proxy_support = urllib2.ProxyHandler({"http": "172.17.18.80:8080"})
    opener = urllib2.build_opener(proxy_support)
    urllib2.install_opener(opener)
    jpgfile = cStringIO.StringIO(urllib2.urlopen(imageurl).read())

    # 重新合并图片
    image = get_merge_image(jpgfile, location_list)

    return image


def is_similar(image1, image2, x, y):
    '''
    对比RGB值
    '''
    pass

    pixel1=image1.getpixel((x, y))
    pixel2=image2.getpixel((x, y))

    for i in range(0,3):
        if abs(pixel1[i]-pixel2[i]) >= 50:
            return False

    return True


def get_diff_location(image1, image2):
    '''
    计算缺口的位置
    '''

    i = 0

    for i in range(0, 260):
        for j in range(0, 116):
            if is_similar(image1, image2, i, j) == False:
                return i


def get_track(length):
    '''
    根据缺口的位置模拟x轴移动的轨迹
    '''
    pass

    list=[]

    # 间隔通过随机范围函数来获得
    x = random.randint(1, 3)

    while length-x >= 5:
        list.append(x)

        length = length-x
        x = random.randint(1, 3)

    for i in xrange(length):
        list.append(1)

    return list

def main():

#     这里的文件路径是webdriver的文件路径
#     driver = webdriver.Chrome(executable_path=r"C:Program Files (x86)GoogleChromeApplicationchromedriver.exe")
    driver = webdriver.Firefox()

#     打开网页
    driver.get("http://127.0.0.1:5000/")

#     等待页面的上元素刷新出来
    WebDriverWait(driver, 30).until(lambda the_driver: the_driver.find_element_by_xpath("//div[@class='gt_slider_knob gt_show']").is_displayed())
    # WebDriverWait(driver, 30).until(lambda the_driver: the_driver.find_element_by_xpath("//div[@class='gt_cut_bg gt_show']").is_displayed())
    # WebDriverWait(driver, 30).until(lambda the_driver: the_driver.find_element_by_xpath("//div[@class='gt_cut_fullbg gt_show']").is_displayed())

#     下载图片
    image1=get_image(driver, "//div[@class='gt_cut_bg gt_show']/div")
    image2=get_image(driver, "//div[@class='gt_cut_fullbg gt_show']/div")
    image1.save("image1.jpg", "JPEG")
    image2.save("image2.jpg", "JPEG")

    # 计算缺口位置
    loc = get_diff_location(image1, image2)

    # 生成x的移动轨迹点
    track_list = get_track(loc)

    # 找到滑动的圆球
    element = driver.find_element_by_xpath("//div[@class='gt_slider_knob gt_show']")
    location = element.location
    # 获得滑动圆球的高度
    y = location['y']

    # 鼠标点击元素并按住不放
    print "第一步,点击元素"
    ActionChains(driver).click_and_hold(on_element=element).perform()
    time.sleep(0.15)

    print "第二步,拖动元素"
    print track_list
    track_string = ""
    for track in track_list:        
        track_string = track_string + "{%d,%d}," % (track, y - 521)
        # xoffset=track+22:这里的移动位置的值是相对于滑动圆球左上角的相对值,而轨迹变量里的是圆球的中心点,所以要加上圆球长度的一半。
        # yoffset=y-521:这里也是一样的。不过要注意的是不同的浏览器渲染出来的结果是不一样的,要保证最终的计算后的值是22,也就是圆球高度的一半
        ActionChains(driver).move_to_element_with_offset(to_element=element, xoffset=track+22, yoffset=y-521).perform()
        # 间隔时间也通过随机函数来获得
        time.sleep(random.randint(10, 50)/100)
    print track_string
    # xoffset=21,本质就是向后退一格。这里退了5格是因为圆球的位置和滑动条的左边缘有5格的距离
    ActionChains(driver).move_to_element_with_offset(to_element=element, xoffset=21, yoffset=y-521).perform()
    time.sleep(0.1)
    ActionChains(driver).move_to_element_with_offset(to_element=element, xoffset=21, yoffset=y-521).perform()
    time.sleep(0.1)
    ActionChains(driver).move_to_element_with_offset(to_element=element, xoffset=21, yoffset=y-521).perform()
    time.sleep(0.1)
    ActionChains(driver).move_to_element_with_offset(to_element=element, xoffset=21, yoffset=y-521).perform()
    time.sleep(0.1)
    ActionChains(driver).move_to_element_with_offset(to_element=element, xoffset=21, yoffset=y-521).perform()

    time.sleep(2)
    print "第三步,释放鼠标"
    # 释放鼠标
    ActionChains(driver).release(on_element=element).perform()
    time.sleep(5)
    # 点击验证
    driver.find_element_by_xpath("//input[@id='embed-submit']").click()
    # ActionChains(driver).click(on_element=submit).perform()

    time.sleep(10)

    driver.quit()

if __name__ == '__main__':
    pass

    main()

参考:http://blog.csdn.net/paololiu/article/details/52514504

原文地址:https://www.cnblogs.com/shangpolu/p/7976362.html