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