拖動式驗證碼
問題點:
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
