### 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/)
它是一个专注于提供验证安全的系统,主要验证方式是拖动滑动拼合图像。若图像完全拼合,则验证成功,即表单成功提交,否者重新验证
![](/assets/8.2.1.png)
### 4.极验验证码特点
* 三角防护之防模拟
* 三角防护之防伪造
* 三角防护之防爆力
* 点击一下,验证只需要0.4秒
* 全平台兼容,适用各种交互情景
* 面向未来,懂科技,更懂人性
### 5.识别思路
极验官方后台:[https://account.geetest.com/register](https://account.geetest.com/register)
![](/assets/8.2.2.png)
此按钮为智能验证按钮,即同一个会话,一段时间内第二次点击会直接通过验证,如果智能识别不通过,则会弹出滑动验证窗口,需要拖动滑块拼合图形完成二步验证
![](/assets/8.-2.3.png)
验证成功后,按钮会变成如下的所示状态
![](/assets/8.2.4.png)
识别验证需要完成三步:
* 模拟点击验证按钮
* 识别滑动缺口的位置
* 模拟拖动滑动
第一步:可以直接使用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