拖动式验证码
拖动式验证码
问题点:
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)\Google\Chrome\Application\chromedriver.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