zoukankan      html  css  js  c++  java
  • 拖动式验证码

    拖动式验证码

    问题点:

    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

  • 相关阅读:
    验证码图片识别
    DataSnap下的分包获取
    uniGUI试用笔记(十)
    EControl的安装
    Cesium应用篇:3控件(6) FullScreen/ VR / Home
    Cesium应用篇:3控件(5)CesiumInspector
    Cesium应用篇:3控件(4)Geocoder
    Cesium应用篇:3控件(3)SelectionIndicator& InfoBox
    Cesium应用篇:3控件(2)BaseLayerPicker
    Cesium应用篇:3控件(1)Clock
  • 原文地址:https://www.cnblogs.com/shangpolu/p/7976362.html
Copyright © 2011-2022 走看看