### 1.目標
通過程序識別并通過極驗驗證碼的驗證,包括
* 分析識別思路
* 識別缺口位置
* 生成滑動拖動路徑
* 模擬實現滑塊拼合通過驗證
等步驟
### 2.安裝
[selenium安裝](/1kai-fa-huan-jing-pei-zhi/12-qing-qiu-ku-de-an-zhuang/122-seleniumde-an-zhuang.md)
[chromeDriver](/1kai-fa-huan-jing-pei-zhi/12-qing-qiu-ku-de-an-zhuang/123-chromedriverde-an-zhuang.md)
### 3.了解極驗驗證碼
極驗驗證碼官網:[http://www.geetest.com/](http://www.geetest.com/)
它是一個專注于提供驗證安全的系統,主要驗證方式是拖動滑動拼合圖像。若圖像完全拼合,則驗證成功,即表單成功提交,否者重新驗證

### 4.極驗驗證碼特點
* 三角防護之防模擬
* 三角防護之防偽造
* 三角防護之防爆力
* 點擊一下,驗證只需要0.4秒
* 全平臺兼容,適用各種交互情景
* 面向未來,懂科技,更懂人性
### 5.識別思路
極驗官方后臺:[https://account.geetest.com/register](https://account.geetest.com/register)

此按鈕為智能驗證按鈕,即同一個會話,一段時間內第二次點擊會直接通過驗證,如果智能識別不通過,則會彈出滑動驗證窗口,需要拖動滑塊拼合圖形完成二步驗證

驗證成功后,按鈕會變成如下的所示狀態

識別驗證需要完成三步:
* 模擬點擊驗證按鈕
* 識別滑動缺口的位置
* 模擬拖動滑動
第一步:可以直接使用selenium模擬點擊按鈕
第二步:識別缺口的位置,需要用到圖像的相關處理方法,需要用到圖像的相關處理方法
第三步:拖動圖片
### 6.初始化
目標網址:[https://account.geetest.com/login](https://account.geetest.com/login)
初始化配置
```
from selenium.webdriver.support.wait import WebDriverWait
import config
from selenium import webdriver
class CrackGreetest():
def __init__(self):
self.url = "https://account.geetest.com/login"
self.browser = webdriver.Chrome()
self.wait = WebDriverWait(self.browser,20)
self.email = config.EMAIL
self.passwrod = config.PASSWORD
```
### 7.模擬點擊
模擬點擊初始的驗證按鈕
```
def get_geetest_button(self):
'''
獲取初始驗證碼按鈕
:return: 按鈕對象
'''
button = self.wait.until(expected_conditions.element_to_be_clickable((By.CLASS_NAME,'geetest_radar_tip')))
return button
```
### 8.識別缺口
```
def get_position(self,pos):
"""
獲取驗證碼位置
:return: 驗證碼位置元組
"""
img = self.wait.until(expected_conditions.presence_of_element_located((By.CLASS_NAME,pos)))
time.sleep(2)
location = img.location
size = img.size
top,bottom,left,right = location['y'],location['y']+size['height'],location['x'],location['x']+size['width']
return (top,bottom,left,right)
def get_unFull_image(self,name):
"""
獲取未完整驗證碼圖片
:param name:
:return: 圖片對象
"""
top,bottom,left,right = self.get_position(pos="geetest_canvas_img")
print('驗證碼位置',top,bottom,left,right)
screenshot = self.get_screenshot()
unfull_captcha = screenshot.crop((left,top,right,bottom))
unfull_captcha.save(name)
return unfull_captcha
def get_full_image(self,name):
'''
獲取完整驗證碼圖片
:param name:
:return:
'''
# 這里要執行JavaScript腳本才能拿到完整圖片的截圖
show_Full_img1 = "document.getElementsByClassName('geetest_canvas_fullbg')[0].style.display='block'"
self.browser.execute_script(show_Full_img1)
show_Full_img2 = "document.getElementsByClassName('geetest_canvas_fullbg')[0].style.opacity=1"
self.browser.execute_script(show_Full_img2)
# 等待完整圖片加載
time.sleep(2)
top, bottom, left, right = self.get_position(pos="geetest_canvas_fullbg")
print('驗證碼位置', top, bottom, left, right)
screenshot = self.get_screenshot()
full_captcha = screenshot.crop((left, top, right, bottom))
full_captcha.save(name)
return full_captcha
```
比較兩張圖片
```
def get_gap(self,image1,image2):
"""
獲取缺口偏移量
:param image1: 不帶缺口的圖片
:param image2: 帶缺口的圖片
:return: 像素是否相同
"""
# 缺口在滑塊右側,設定遍歷初始橫坐標left為59
left = 60
# 像素對比閾值
threshold = 60
for i in range(left, image2.size[0]):
for j in range(image2.size[1]):
rgb1 = image1.load()[i, j]
rgb2 = image2.load()[i, j]
res1 = abs(rgb2[0] - rgb1[0])
res2 = abs(rgb2[1] - rgb1[1])
res3 = abs(rgb2[2] - rgb1[2])
if not (res1 < threshold and res2 < threshold and res3 < threshold):
return i - 7 # 返回缺口偏移距離,這里需測試幾次
```
### 9.模擬拖動
```
def get_track(self,distanc):
'''
x=v0*t+0.5*a*t*t
v=v0+a*t
根據偏移量獲取移動軌跡
:param distanc: 偏移量
:return: 移動軌跡
'''
# 移動軌跡
track = []
# 當前位移
current = 0
# 減速閾值
mid = distanc * 4 / 5
# 計算間隔
t = random.randint(2,3)/10
# 初速度
v = 0
while current < distanc:
if current < mid:
# 加速度為正2
a = 2
else:
# 加速度為負3
a = -3
v0 = v
# 當前速度v = v0+at
v=v0+a*t
# 移動距離x=v0*t+1/2*a*t*t
move = v0*t+1/2*a*t*t
# 當前位移
current+=move
# 加入軌跡
track.append(round(move))
return track
def move_to_grap(self,slider,track):
'''
拖動滑塊到缺口處
:param slider: 滑塊
:param track: 軌跡
:return:
'''
# 調用ActionChains的click_and_hold()方法按住拖動底部滑塊,遍歷運動軌跡獲取每小段位置距離,調用move_by_offset()方法移動此位移,最后調用release()方法松開鼠標
ActionChains(self.browser).click_and_hold(slider).perform()
for x in track:
ActionChains(self.browser).move_by_offset(xoffset=x,yoffset=0).perform()
time.sleep(0.3)
ActionChains(self.browser).release().perform()
```
### 10.完整代碼
```
import random
from io import BytesIO
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.wait import WebDriverWait
import config,time
from selenium import webdriver
from PIL import Image
class CrackGreetest():
def __init__(self):
self.url = "https://account.geetest.com/login"
self.browser = webdriver.Chrome()
self.wait = WebDriverWait(self.browser,20)
self.email = config.EMAIL
self.password = config.PASSWORD
def open(self):
"""
打開網頁輸入用戶名密碼
:return: None
"""
self.browser.get(self.url)
email = self.wait.until(expected_conditions.presence_of_element_located((By.ID,'email')))
password = self.wait.until(expected_conditions.presence_of_element_located((By.ID,'password')))
email.send_keys(self.email)
password.send_keys(self.password)
def get_geetest_button(self):
'''
獲取初始驗證碼按鈕
:return: 按鈕對象
'''
button = self.wait.until(expected_conditions.element_to_be_clickable((By.CLASS_NAME,'geetest_radar_tip')))
return button
def get_screenshot(self):
"""
獲取網頁截圖
:return: 截圖對象
"""
screenshot = self.browser.get_screenshot_as_png()
screenshot = Image.open(BytesIO(screenshot))
return screenshot
def get_position(self,pos):
"""
獲取驗證碼位置
:return: 驗證碼位置元組
"""
img = self.wait.until(expected_conditions.presence_of_element_located((By.CLASS_NAME,pos)))
time.sleep(2)
location = img.location
size = img.size
top,bottom,left,right = location['y'],location['y']+size['height'],location['x'],location['x']+size['width']
return (top,bottom,left,right)
def get_unFull_image(self,name):
"""
獲取未完整驗證碼圖片
:param name:
:return: 圖片對象
"""
top,bottom,left,right = self.get_position(pos="geetest_canvas_img")
print('驗證碼位置',top,bottom,left,right)
screenshot = self.get_screenshot()
unfull_captcha = screenshot.crop((left,top,right,bottom))
unfull_captcha.save(name)
return unfull_captcha
def get_full_image(self,name):
'''
獲取完整驗證碼圖片
:param name:
:return:
'''
# 這里要執行JavaScript腳本才能拿到完整圖片的截圖
show_Full_img1 = "document.getElementsByClassName('geetest_canvas_fullbg')[0].style.display='block'"
self.browser.execute_script(show_Full_img1)
show_Full_img2 = "document.getElementsByClassName('geetest_canvas_fullbg')[0].style.opacity=1"
self.browser.execute_script(show_Full_img2)
# 等待完整圖片加載
time.sleep(2)
top, bottom, left, right = self.get_position(pos="geetest_canvas_fullbg")
print('驗證碼位置', top, bottom, left, right)
screenshot = self.get_screenshot()
full_captcha = screenshot.crop((left, top, right, bottom))
full_captcha.save(name)
return full_captcha
def get_slider(self):
"""
獲取滑塊
:return: 滑塊對象
"""
slider = self.wait.until(expected_conditions.element_to_be_clickable((By.CLASS_NAME,'geetest_slider_button')))
return slider
# # 判斷兩張圖片同一位置的像素是否相同。比較兩張圖的RGB的絕對值是否均小于定義的閾值threshold
# # 如果絕對值均在閾值值內,則代表像素點相同,繼續遍歷,否者代表不相同的像素點,即缺口的位置
# def is_pixel_equal(self,image1,image2,x,y):
# '''
# 判斷兩個像素是否相同
# :param image1: 圖片1
# :param image2: 圖片2
# :param x: 位置x
# :param y: 位置y
# :return: 像素是否相同
# '''
# # 取兩個圖片的像素點
# pixel1 = image1.load()[x,y]
# pixel2 = image2.load()[x,y]
# # 像素對比閾值
# threshold = 60
# if abs(pixel1[0]-pixel2[0]) < threshold and abs(pixel1[1] - pixel2[1]) < threshold and abs(pixel1[2] - pixel2[2]) < threshold:
# return True
# else:
# return False
def get_gap(self,image1,image2):
"""
獲取缺口偏移量
:param image1: 不帶缺口的圖片
:param image2: 帶缺口的圖片
:return: 像素是否相同
"""
# 缺口在滑塊右側,設定遍歷初始橫坐標left為59
left = 60
# 像素對比閾值
threshold = 60
for i in range(left, image2.size[0]):
for j in range(image2.size[1]):
rgb1 = image1.load()[i, j]
rgb2 = image2.load()[i, j]
res1 = abs(rgb2[0] - rgb1[0])
res2 = abs(rgb2[1] - rgb1[1])
res3 = abs(rgb2[2] - rgb1[2])
if not (res1 < threshold and res2 < threshold and res3 < threshold):
return i - 7 # 返回缺口偏移距離,這里需測試幾次
def get_track(self,distanc):
'''
x=v0*t+0.5*a*t*t
v=v0+a*t
根據偏移量獲取移動軌跡
:param distanc: 偏移量
:return: 移動軌跡
'''
# 移動軌跡
track = []
# 當前位移
current = 0
# 減速閾值
mid = distanc * 4 / 5
# 計算間隔
t = random.randint(2,3)/10
# 初速度
v = 0
while current < distanc:
if current < mid:
# 加速度為正2
a = 2
else:
# 加速度為負3
a = -3
v0 = v
# 當前速度v = v0+at
v=v0+a*t
# 移動距離x=v0*t+1/2*a*t*t
move = v0*t+1/2*a*t*t
# 當前位移
current+=move
# 加入軌跡
track.append(round(move))
return track
def move_to_grap(self,slider,track):
'''
拖動滑塊到缺口處
:param slider: 滑塊
:param track: 軌跡
:return:
'''
# 調用ActionChains的click_and_hold()方法按住拖動底部滑塊,遍歷運動軌跡獲取每小段位置距離,調用move_by_offset()方法移動此位移,最后調用release()方法松開鼠標
ActionChains(self.browser).click_and_hold(slider).perform()
for x in track:
ActionChains(self.browser).move_by_offset(xoffset=x,yoffset=0).perform()
time.sleep(0.3)
ActionChains(self.browser).release().perform()
def login(self):
"""
點擊登陸
:return:
"""
submit = self.wait.until(expected_conditions.element_to_be_clickable((By.CLASS_NAME, 'login-btn')))
submit.click()
time.sleep(10)
print('登錄成功')
def crack(self):
try:
# 輸入用戶名
self.open()
# 模擬點擊按鈕
button = self.get_geetest_button()
button.click()
# 獲取驗證碼圖片
image1 = self.get_unFull_image('unfull_captcha.png')
# 獲取帶缺口的驗證碼圖片
image2 = self.get_full_image('full_captcha.png')
# 對比兩張圖片像素點,獲取缺口位置,得到偏移距離
# 獲取缺口位置
distance = self.get_gap(image1,image2)
print("缺口位置",distance)
# 獲取移動軌跡
track = self.get_track(distance)
print("滑動軌跡",track)
# 模擬人的行為,拖動滑塊,完成驗證
slider = self.get_slider()
# slider.click()
# 拖動滑塊
self.move_to_grap(slider,track)
success = self.wait.until(
expected_conditions.text_to_be_present_in_element((By.CLASS_NAME, 'geetest_success_radar_tip_content'), '驗證成功'))
print(success)
self.login()
except:
self.crack()
if __name__ == "__main__":
crack = CrackGreetest()
crack.crack()
```
- 介紹
- 1.開發環境配置
- 1.1 python3的安裝
- 1.1.1 windows下的安裝
- 1.1.2 Linux下的安裝
- 1.1.3 Mac下的安裝
- 1.2 請求庫的安裝
- 1.2.1 requests的安裝
- 1.2.2 selenium的安裝
- 1.2.3 ChromeDriver的安裝
- 1.2.4 GeckoDriver 的安裝
- 1.2.5 PhantomJS的安裝
- 1.2.6 aiohttp的安裝
- 1.3 解析庫的安裝
- 1.3.1 lxml的安裝
- 1.3.2 Beautiful Soup的安裝
- 1.3.3 pyquery的安裝
- 1.3.4 tesserocr的安裝
- 1.4 數據庫的安裝
- 1.4.1 MySQL的安裝
- 1.4.2 MongoDB的安裝
- 1.4.3 Redis的安裝
- 1.5 存儲庫的安裝
- 1.5.1 PyMySQL的安裝
- 1.5.2 PyMongo的安裝
- 1.5.3 redis-py的安裝
- 1.5.4 RedisDump的安裝
- 1.6 Web庫的安裝
- 1.6.1 Flask的安裝
- 1.6.2 Tornado的安裝
- 1.7 App爬取相關庫的安裝
- 1.7.1 Charles的安裝
- 1.7.2 mitmproxy的安裝
- 1.7.3 Appium的安裝
- 1.8 爬蟲框架的安裝
- 1.8.1 pyspider的安裝
- 1.8.2 Scrapy的安裝
- 1.8.3 Scrapy-Splash的安裝
- 1.8.4 ScrapyRedis的安裝
- 1.9 布署相關庫的安裝
- 1.9.1 Docker的安裝
- 1.9.2 Scrapyd的安裝
- 1.9.3 ScrapydClient的安裝
- 1.9.4 ScrapydAPI的安裝
- 1.9.5 Scrapyrt的安裝
- 1.9.6-Gerapy的安裝
- 2.爬蟲基礎
- 2.1 HTTP 基本原理
- 2.1.1 URI和URL
- 2.1.2 超文本
- 2.1.3 HTTP和HTTPS
- 2.1.4 HTTP請求過程
- 2.1.5 請求
- 2.1.6 響應
- 2.2 網頁基礎
- 2.2.1網頁的組成
- 2.2.2 網頁的結構
- 2.2.3 節點樹及節點間的關系
- 2.2.4 選擇器
- 2.3 爬蟲的基本原理
- 2.3.1 爬蟲概述
- 2.3.2 能抓怎樣的數據
- 2.3.3 javascript渲染的頁面
- 2.4 會話和Cookies
- 2.4.1 靜態網頁和動態網頁
- 2.4.2 無狀態HTTP
- 2.4.3 常見誤區
- 2.5 代理的基本原理
- 2.5.1 基本原理
- 2.5.2 代理的作用
- 2.5.3 爬蟲代理
- 2.5.4 代理分類
- 2.5.5 常見代理設置
- 3.基本庫使用
- 3.1 使用urllib
- 3.1.1 發送請求
- 3.1.2 處理異常
- 3.1.3 解析鏈接
- 3.1.4 分析Robots協議
- 3.2 使用requests
- 3.2.1 基本用法
- 3.2.2 高級用法
- 3.3 正則表達式
- 3.4 抓取貓眼電影排行
- 4.解析庫的使用
- 4.1 使用xpath
- 4.2 使用Beautiful Soup
- 4.3 使用pyquery
- 5.數據存儲
- 5.1 文件存儲
- 5.1.1 TXT 文件存儲
- 5.1.2 JSON文件存儲
- 5.1.3 CSV文件存儲
- 5.2 關系型數據庫存儲
- 5.2.1 MySQL的存儲
- 5.3 非關系數據庫存儲
- 5.3.1 MongoDB存儲
- 5.3.2 Redis存儲
- 6.Ajax數據爬取
- 6.1 什么是Ajax
- 6.2 Ajax分析方法
- 6.3 Ajax結果提取
- 6.4 分析Ajax爬取今日頭條街拍美圖
- 7.動態渲染頁面爬取
- 7.1 Selenium的使用
- 7.2 Splash的使用
- 7.3 Splash負載均衡配置
- 7.4 使用selenium爬取淘寶商品
- 8.驗證碼的識別
- 8.1 圖形驗證碼的識別
- 8.2 極驗滑動驗證碼的識別
- 8.3 點觸驗證碼的識別
- 8.4微博宮格驗證碼的識別
- 9.代理的使用
- 9.1 代理的設置
- 9.2 代理池的維護
- 9.3 付費代理的使用
- 9.4 ADSL撥號代理
- 9.5 使用代理爬取微信公總號文章
- 10.模擬登錄
- 10.1 模擬登陸并爬去GitHub
- 10.2 Cookies池的搭建
- 11.App的爬取
- 11.1 Charles的使用
- 11.2 mitmproxy的使用
- 11.3 mitmdump“得到”App電子書信息
- 11.4 Appium的基本使用
- 11.5 Appnium爬取微信朋友圈
- 11.6 Appium+mitmdump爬取京東商品
- 12.pyspider框架的使用
- 12.1 pyspider框架介紹
- 12.2 pyspider的基本使用
- 12.3 pyspider用法詳解
- 13.Scrapy框架的使用
- 13.1 scrapy框架介紹
- 13.2 入門
- 13.3 selector的用法
- 13.4 spider的用法
- 13.5 Downloader Middleware的用法
- 13.6 Spider Middleware的用法
- 13.7 Item Pipeline的用法
- 13.8 Scrapy對接Selenium
- 13.9 Scrapy對接Splash
- 13.10 Scrapy通用爬蟲
- 13.11 Scrapyrt的使用
- 13.12 Scrapy對接Docker
- 13.13 Scrapy爬取新浪微博
- 14.分布式爬蟲
- 14.1 分布式爬蟲原理
- 14.2 Scrapy-Redis源碼解析
- 14.3 Scrapy分布式實現
- 14.4 Bloom Filter的對接
- 15.分布式爬蟲的部署
- 15.1 Scrapyd分布式部署
- 15.2 Scrapyd-Client的使用
- 15.3 Scrapyd對接Docker
- 15.4 Scrapyd批量部署
- 15.5 Gerapy分布式管理
- 微信公總號文章實戰
- 源碼
- other