第二十五节:scrapy爬虫识别验证码(四)手绘验证码识别
一、介绍
今天主要介绍的是微博客户端在登录时出现的四宫格手绘验证码,不多说直接看看验证码长成什么样。

二、思路
1、由于微博上的手绘验证码只有四个宫格,且每个宫格之间都有有向线段连接,所以我们可以判断四个宫格不同方向的验证码一共有24种,
我们将四个宫格进行标号,得到的结果如下:

则我们可以排列出24种不同的手绘方向的验证码,分别为一下24种
| 1234 | 2134 | 3124 | 4321 |
| 1243 | 2143 | 3142 | 4312 |
| 1342 | 2314 | 3214 | 4123 |
| 1324 | 2341 | 3241 | 4132 |
| 1423 | 2413 | 3412 | 4213 |
| 1432 | 2431 | 3421 | 4231 |
2、我们通过获取到微博客户端的24种手绘验证码后需要进行模板匹配,这样通过全图匹配的方式进行滑动。
三、代码实现
1、首先是要通过微博移动端(https://passport.weibo.cn/signin/login)批量获取手绘验证码,但是这个验证码不一定出现,
只有在账号存在风险或者频繁登录的时候才会出现。获取手绘验证码的代码如下:
注意:需要将模拟浏览器所以元素(用户名框,密码框)加载完了才能发送用户名和密码,否则报错
1 # -*- coding:utf-8 -*-
2 import time
3 from io import BytesIO
4 from PIL import Image
5 from selenium import webdriver
6 from selenium.webdriver.common.by import By
7 from selenium.common.exceptions import TimeoutException
8 from selenium.webdriver.support.ui import WebDriverWait
9 from selenium.webdriver.support import expected_conditions as EC
10
11
12 class CrackWeiboSlide():
13 def __init__(self):
14 self.url = "https://passport.weibo.cn/signin/login?entry=mweibo&r=https://m.weibo.cn/"
15 self.browser = webdriver.Chrome(r"D:\chromedriver.exe")
16 self.browser.maximize_window()
17 self.wait = WebDriverWait(self.browser,5)
18
19
20 def __del__(self):
21 self.browser.close()
22
23 def open(self):
24 # 打开模拟浏览器
25 self.browser.get(self.url)
26 # 获取用户名元素
27 username = self.wait.until(EC.presence_of_element_located((By.XPATH,'//*[@id="loginName"]')))
28 # 获取密码框元素
29 password = self.wait.until(EC.presence_of_element_located((By.XPATH,'//*[@id="loginPassword"]')))
30 # 获取登录按钮元素
31 submit = self.wait.until(EC.element_to_be_clickable((By.XPATH,'//*[@id="loginAction"]')))
32 # 提交数据并登录
33 username.send_keys("15612345678")
34 password.send_keys("xxxxxxxxxxxx")
35 submit.click()
36
37
38 def get_image(self,name = "captcha.png"):
39 try:
40 # 获取验证码图片元素
41 img = self.wait.until(EC.presence_of_element_located((By.CLASS_NAME,"patt-shadow")))
42 time.sleep(1)
43 # 获取验证码图片所在的位置
44 location = img.location
45 # 获取验证码图片的大小
46 size = img.size
47 top = location["y"] # 上
48 bottom = location["y"] + size["height"] # 下
49 left = location["x"] # 左
50 right = location["x"] + size["width"] # 右
51 print("验证码的位置:", left, top, right, bottom)
52 # 将当前窗口进行截屏
53 screenshot = self.browser.get_screenshot_as_png()
54 # 读取截图
55 screenshot = Image.open(BytesIO(screenshot))
56 # 剪切九宫格图片验证码
57 captcha = screenshot.crop((left, top, right, bottom))
58 # 将剪切的九宫格验证码保存到指定位置
59 captcha.save(name)
60 print("微博登录验证码保存完成!!!")
61 return captcha
62 except TimeoutException:
63 print("没有出现验证码!!")
64 # 回调打开模拟浏览器函数
65 self.open()
66
67
68 def main(self):
69 count = 1
70 while True:
71 # 调用打开模拟浏览器函数
72 self.open()
73 # 调用获取验证码图片函数
74 self.get_image(str(count) + ".png")
75 count += 1
76
77
78 if __name__ == '__main__':
79 crack = CrackWeiboSlide()
80 crack.main()
批量获取手绘验证码
得到的24种手绘验证码,同时需要对这些手绘验证码根据上边的编号进行命名


上图就是我们需要的模板,接下来我们进行遍历模板匹配即可
2、模板匹配
通过遍历手绘验证码模板进行匹配
1 import os
2 import time
3 from io import BytesIO
4 from PIL import Image
5 from selenium import webdriver
6 from selenium.webdriver import ActionChains
7 from selenium.webdriver.common.by import By
8 from selenium.common.exceptions import TimeoutException
9 from selenium.webdriver.support.ui import WebDriverWait
10 from selenium.webdriver.support import expected_conditions as EC
11
12 class CrackWeiboSlide():
13 def __init__(self):
14 self.url = "https://passport.weibo.cn/signin/login?entry=mweibo&r=https://m.weibo.cn/"
15 self.browser = webdriver.Chrome(r"D:\chromedriver.exe")
16 self.browser.maximize_window()
17 self.wait = WebDriverWait(self.browser,5)
18
19
20 def __del__(self):
21 self.browser.close()
22
23 def open(self):
24 # 打开模拟浏览器
25 self.browser.get(self.url)
26 # 获取用户名元素
27 username = self.wait.until(EC.presence_of_element_located((By.XPATH,'//*[@id="loginName"]')))
28 # 获取密码框元素
29 password = self.wait.until(EC.presence_of_element_located((By.XPATH,'//*[@id="loginPassword"]')))
30 # 获取登录按钮元素
31 submit = self.wait.until(EC.element_to_be_clickable((By.XPATH,'//*[@id="loginAction"]')))
32 # 提交数据并登录
33 username.send_keys("15612345678")
34 password.send_keys("xxxxxxxxxxxx")
35 submit.click()
36
37
38 def get_image(self,name = "captcha.png"):
39 try:
40 # 获取验证码图片元素
41 img = self.wait.until(EC.presence_of_element_located((By.CLASS_NAME,"patt-shadow")))
42 time.sleep(1)
43
44 # 获取验证码图片所在的位置
45 location = img.location
46
47 # 获取验证码图片的大小
48 size = img.size
49 top = location["y"] # 上
50 bottom = location["y"] + size["height"] # 下
51 left = location["x"] # 左
52 right = location["x"] + size["width"] # 右
53 print("验证码的位置:", left, top, right, bottom)
54
55 # 将当前窗口进行截屏
56 screenshot = self.browser.get_screenshot_as_png()
57
58 # 读取截图
59 screenshot = Image.open(BytesIO(screenshot))
60
61 # 剪切九宫格图片验证码
62 captcha = screenshot.crop((left, top, right, bottom))
63
64 # 将剪切的九宫格验证码保存到指定位置
65 captcha.save(name)
66 print("微博登录验证码保存完成!!!")
67
68 # 返回微博移动端的验证码图片
69 return captcha
70 except TimeoutException:
71 print("没有出现验证码!!")
72
73 # 回调打开模拟浏览器函数
74 self.open()
75
76 def is_pixel_equal(self,image,template,i,j):
77
78 # 取出两张图片的像素点
79 pixel1 = image.load()[i,j] # 移动客户端获取的验证码
80 pixel2 = template.load()[i,j] # 模板文件里的验证码
81 threshold = 20 # 阈值
82 pix_r = abs(pixel1[0] - pixel2[0]) # R
83 pix_g = abs(pixel1[1] - pixel2[1]) # G
84 pix_b = abs(pixel1[2] - pixel2[2]) # B
85 if (pix_r< threshold) and (pix_g< threshold ) and (pix_b< threshold) :
86 return True
87 else:
88 return False
89
90 def same_image(self,image,template):
91 """
92 :param image: 微博移动端获取的验证码图片
93 :param template: 通过模板文件获取的验证码图片
94 """
95 threshold = 0.99 # 相似度阈值
96 count = 0
97 # 遍历微博移动端获取的验证码图片的宽度和高度
98 for i in range(image.width):
99 for j in range(image.height):
100
101 # 判断两张图片的像素是否相等
102 if self.is_pixel_equal(image,template,i,j):
103 count += 1
104 result = float(count)/(image.width*image.height)
105 if result >threshold:
106 print("匹配成功!!!")
107 return True
108 else:
109 return False
110
111
112 def detect_image(self,image):
113 # 遍历手绘验证码模板文件内的所有验证码图片
114 for template_name in os.listdir(r"D:\photo\templates"):
115 print("正在匹配",template_name)
116
117 # 打开验证码图片
118 template = Image.open(r"D:\photo\templates\{}".format(template_name))
119
120 if self.same_image(image,template):
121 # 返回这张图片的顺序,如4—>3—>1—>2
122 numbers = [int(number) for number in list(template_name.split(".")[0])]
123 print("按照顺序进行拖动",numbers)
124 return numbers
125
126 def move(self,numbers):
127 # 获得四个按点
128 circles = self.browser.find_element_by_css_selector('.patt-wrap .patt-circ')
129 dx = dy = 0
130 # 由于是四个宫格,所以需要循环四次
131 for index in range(4):
132 circle = circles[numbers[index] - 1]
133 # 如果是第一次循环
134 if index == 0:
135 # 点击第一个点
136 action = ActionChains(self.browser).move_to_element_with_offset(circle,circle.size["width"]/2,circle.size['height']/2)
137 action.click_and_hold().perform()
138 else:
139 # 小幅度移动次数
140 times = 30
141 # 拖动
142 for i in range(times):
143 ActionChains(self.browser).move_by_offset(dx/times,dy/times).perform()
144 time.sleep(1/times)
145
146 # 如果是最后一次循环
147 if index == 3:
148 # 松开鼠标
149 ActionChains(self.browser).release().perform()
150 else:
151 # 计算下一次偏移
152 dx = circles[numbers[index + 1] - 1].location['x'] - circle.location['x']
153 dy = circles[numbers[index + 1] - 1].location['y'] - circle.location['y']
154
155
156 def main(self):
157 # 调用打开模拟浏览器函数
158 self.open()
159 image = self.get_image("captcha.png") # 微博移动端的验证码图片
160 numbers = self.detect_image(image)
161 self.move(numbers)
162 time.sleep(10)
163 print('识别结束')
164
165
166 if __name__ == '__main__':
167 crack = CrackWeiboSlide()
168 crack.main()
匹配验证识别
四、识别结果
通过循环四次后绘出四条方向,最终得到效果图

第二十五节:scrapy爬虫识别验证码(四)手绘验证码识别的更多相关文章
- centos lamp/lnmp阶段复习 以后搬迁discuz论坛不需要重新安装,只需修改配置文件即可 安装wordpress 安装phpmyadmin 定时备份mysql两种方法 第二十五节课
centos lamp/lnmp阶段复习 以后搬迁discuz论坛不需要重新安装,只需修改配置文件即可 安装wordpress 安装phpmyadmin 定时备份mysql两种方法 第二十五节 ...
- 风炫安全WEB安全学习第二十五节课 利用XSS键盘记录
风炫安全WEB安全学习第二十五节课 利用XSS键盘记录 XSS键盘记录 同源策略是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源.所以xyz.com下的js脚本采用a ...
- 第二十三节:scrapy爬虫识别验证码(二)图片验证码识别
图片验证码基本上是有数字和字母或者数字或者字母组成的字符串,然后通过一些干扰线的绘制而形成图片验证码. 例如:知网的注册就有图片验证码 首先我们需要获取验证码图片,通过开发者工具我们可以得到验证码ur ...
- python自动化开发-[第二十五天]-scrapy进阶与flask使用
今日内容概要 1.cookie操作 2.pipeline 3.中间件 4.扩展 5.自定义命令 6.scrapy-redis 7.flask使用 - 路由系统 - 视图 - 模版 - message( ...
- 【php增删改查实例】第二十五节 - 在main.php中显示头像
在用户成功上传头像以后,用户登录系统,应该能够看到自己的头像,本节演示如何在这个地方: 添加用户头像. 1.用DIV做: border-radius:50% background:url(xxx.jp ...
- [ExtJS5学习笔记]第二十五节 利用window.open()函数实现ExtJS5的登陆页面跳转
本文地址:http://blog.csdn.net/sushengmiyan/article/details/40427543 mvvm方式实现登陆的博客:http://blog.csdn.net/s ...
- 第二十五节:Java语言基础-面向对象基础
面向对象 面向过程的代表主要是C语言,面向对象是相对面向过程而言,Java是面向对象的编程语言,面向过程是通过函数体现,面向过程主要是功能行为. 而对于面向对象而言,将功能封装到对象,所以面向对象是基 ...
- php第二十五节课
详情删除 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3 ...
- 第十五节、OpenCV学习(四)图像平滑与滤波
图像的平滑与滤波 平滑滤波是低频增强的空间域滤波技术,是图像模糊.消除噪声. 一.2D滤波器cv2.filter2D() 对于2D图像可以进行低通或者高通滤波操作,低通滤波(LPF)有利于去噪声,模糊 ...
- 第三百三十五节,web爬虫讲解2—Scrapy框架爬虫—豆瓣登录与利用打码接口实现自动识别验证码
第三百三十五节,web爬虫讲解2—Scrapy框架爬虫—豆瓣登录与利用打码接口实现自动识别验证码 打码接口文件 # -*- coding: cp936 -*- import sys import os ...
随机推荐
- MasaFramework的MinimalAPI设计
在以前的MVC引用程序中,控制器负责接收输入信息.执行.编排操作并返回响应,它是一个功能齐全的框架,它提供了过滤器.内置了模型绑定与验证,并提供了很多可扩展的管道,但它偏重,不像其它语言是通过更加简洁 ...
- 阿里云下配置keepalive,利用HAVIP实现HA
注:这篇文章参考网络,有些称呼都变了,比如阿里云上的现在是弹性ip 包括阿里云在内的很多云环境,因为不支持浮动IP广受诟病.目前阿里云在VPC网络下发布了HAVIP,能够实现arp宣告IP.这样也就让 ...
- EFK-5: ES集群开启用户认证
转载自:https://mp.weixin.qq.com/s?__biz=MzUyNzk0NTI4MQ==&mid=2247483826&idx=1&sn=583e9a5260 ...
- 企业MES系统与ERP信息集成要素有哪些?
关于要讲明企业MES系统与ERP信息集成要素有哪些,得先弄清楚他们之间的关系:从工厂的管理来说,ERP在上MES在下,ERP统领企业全局包括MES,为管理层服务,重心在于企业决策,ERP对企业宏观管理 ...
- Codeforces Round #823 (Div. 2) A-D
比赛链接 A 题解 知识点:贪心. 对于一个轨道,要么一次性清理,要么一个一个清理.显然,如果行星个数大于直接清理的花费,那么选择直接清理,否则一个一个清理.即 \(\sum \min (c,cnt[ ...
- Java19虚拟线程都来了,我正在写的线程代码会被淘汰掉吗?
Java19中引入了虚拟线程,虽然默认是关闭的,但是可以以Preview模式启用,这绝对是一个重大的更新,今天Java架构杂谈带大家开箱验货,看看这家伙实现了什么了不起的功能. 1 为什么需要虚拟线程 ...
- 这些不知道,别说你熟悉 Spring
大家好,这篇文章跟大家来聊下 Spring 中提供的常用扩展点.Spring SPI 机制.以及 SpringBoot 自动装配原理,重点介绍下 Spring 基于这些扩展点怎么跟配置中心(Apoll ...
- springboot+vue 实现校园二手商城(毕业设计一)
1.功能划分 2.实现的效果 2.1 登录页面 2.2 注册页面 2.3 商城首页 2.4 商品详情 2.5 购物车 2.6 订单 2.7 在线交流 2.8 公告信息 2.9 个人信息 3.后台管理界 ...
- 复杂场景数据处理的 OLTP 与 OLAP 融合实践
本文首发于 NebulaGraph 公众号 Dag Controller 介绍 Dag Controller 是 NebulaGraph 企业版的系统,经过反复测试无误后进行了发布,它主要解决的是 O ...
- git 多个commit 如何合并
git 多个commit 如何合并 本篇主要介绍一下 git 中多个commit 如何合并, 因为commit 太多 会导致提交记录混乱, 所以有时候会把多个commit 合并成一个 保持提交记录干净 ...