python验证码识别教程之滑动验证码


Posted in Python onJune 04, 2018

前言

上篇文章记录了2种分割验证码的方法,此外还有一种叫做”滴水算法”(Drop Fall Algorithm)的方法,但本人智商原因看这个算法看的云里雾里的,所以今天记录滑动验证码的处理吧。网上据说有大神已经破解了滑动验证码的算法,可以不使用selenium来破解,但本人能力不足还是使用笨方法吧。

基础原理很简单,首先点击验证码按钮后的图片是滑动后的完整结果,点击一下滑块后会出现拼图,对这2个分别截图后比较像素值来找出滑动距离,并结合selenium来实现拖拽效果。

至于selenium怎么安装就不说了,滑动验证码的一个难点就是要模拟人的拖拽行为,移动快了不行,慢了也不行。

这里以国家企业公示网站为例:

# -*- coding: utf-8 -*-
import time
import random
from io import BytesIO
from PIL import Image
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver import ActionChains
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC


class Slide(object):
 """滑动验证码破解"""

 def __init__(self, target):
 self.target = target # 要搜索的公司名称
 self.driver = webdriver.Chrome()
 self.wait = WebDriverWait(self.driver, 10)

 def crop(self, left, top, right, bottom, pic_name):
 """截屏并裁剪"""
 ss = Image.open(BytesIO(self.driver.get_screenshot_as_png()))
 cp = ss.crop((left, top, right, bottom)) # 注意这里顺序
 cp.save(pic_name)
 return cp

 def calc_move(self, pic1, pic2):
 """根据阈值计算移动距离"""
 pix1 = pic1.load()
 pix2 = pic2.load()
 threshold = 200
 move = 0
 # 因为滑块都从左向右滑动,而碎片本身宽度为60所以从60开始遍历
 for i in range(60, pic1.size[0]):
  flag = False
  for j in range(pic1.size[1]):
  r = abs(pix1[i, j][0] - pix2[i, j][0])
  g = abs(pix1[i, j][1] - pix2[i, j][1])
  b = abs(pix1[i, j][2] - pix2[i, j][2])
  # if r > threshold and g > threshold and b > threshold:
  # 方法1:分别判断rgb大于阈值
  # flag = True
  # break
  if r + g + b > threshold:
   # 方法2:判断rgb总和跟阈值比较,效果比1好 为什么呢??
   flag = True
   break
  if flag:
  move = i
  break
 return move

 def path1(self, distance):
 """绘制移动路径方法1,构造一个等比数列"""
 q = 0.4 # 测试后发现0.4效果最佳
 n = 10 # 最多移动几次
 a1 = ((1 - q) * distance) / (1 - q**n)
 result = []
 for o in range(1, n + 1):
  an = a1 * q**(o - 1)
  if an < 0.1: # 小于移动阈值的就不要了
  break
  t = random.uniform(0, 0.5) # 测试后0.5秒的间隔成功率最高
  result.append([an, 0, t])
 return result

 def path2(self, distance):
 """绘制移动路径方法2,模拟物理加速、减速运动,效果比1好"""
 result = []
 current = 0
 # 减速阈值
 mid = distance * 4 / 5
 # 计算间隔
 t = 0.2
 # 初速度
 v = 0
 while current < (distance - 10):
  if current < mid:
  # 加速度为正2
  a = 2
  else:
  # 加速度为负3
  a = -3
  # 初速度v0
  v0 = v
  # 当前速度v = v0 + at
  v = v0 + a * t
  # 移动距离x = v0t + 1/2 * a * t^2
  move = v0 * t + 0.5 * a * t * t
  # 当前位移
  current += move
  # 加入轨迹
  result.append([round(move), 0, random.uniform(0, 0.5)])
 return result

 def run(self):
 self.driver.get("http://www.gsxt.gov.cn/index")
 input_box = self.driver.find_element_by_id('keyword')
 input_box.send_keys(self.target)
 search_btn = self.driver.find_element_by_id('btn_query')
 time.sleep(3) # 注意这里等一下再点,否则会出现卡死现象
 search_btn.click()
 # 等待验证码弹出
 bg_pic = self.wait.until(EC.presence_of_element_located((By.CLASS_NAME,
         "gt_cut_fullbg")))
 # html中坐标原点是左上角,右为x轴正方向,下为y轴正方向
 # 输出的x为正就是此元素距离屏幕左侧距离
 # 输出的y为正就是此元素距离屏幕上侧距离
 # 所以我们需要截图的四个距离如下:
 top, bottom, left, right = (
  bg_pic.location['y'], bg_pic.location['y'] + bg_pic.size['height'],
  bg_pic.location['x'], bg_pic.location['x'] + bg_pic.size['width'])
 time.sleep(1)
 cp1 = self.crop(left, top, right, bottom, '1.png')

 # 获取滑块按钮并点击一下
 slide = self.wait.until(EC.presence_of_element_located((By.CLASS_NAME,
        "gt_slider_knob")))
 slide.click()
 time.sleep(3) # 等3秒报错信息消失 TODO 这里应该可以改进
 cp2 = self.crop(left, top, right, bottom, '2.png')
 move = self.calc_move(cp1, cp2)

 result = self.path1(move)
 # result = self.path2(move)

 # 拖动滑块
 ActionChains(self.driver).click_and_hold(slide).perform()
 for x in result:
  ActionChains(self.driver).move_by_offset(xoffset=x[0],yoffset=x[1]).perform()
  # ActionChains(driver).move_to_element_with_offset(to_element=slide,xoffset=x[0],yoffset=x[1]).perform()
  time.sleep(x[-1]) # 如果使用方法1则需要sleep
 time.sleep(0.5)
 ActionChains(self.driver).release(slide).perform() # 释放按钮

 time.sleep(0.8)
 element = self.wait.until(EC.presence_of_element_located((By.CLASS_NAME, "gt_info_text")))
 ans = element.text
 if u"通过" in ans:
  # 这里也需要等一下才能获取到具体的链接
  element = self.wait.until(EC.presence_of_all_elements_located((By.CLASS_NAME, "search_list_item")))
  for o in self.driver.find_elements_by_xpath(u"//a[@target='_blank']"):
  print(o.get_attribute("href"))
  self.driver.quit()
 else:
  print("识别失败")
  self.driver.quit()


if __name__ == '__main__':
 s = Slide('中国平安')
 s.run()

代码中注释很详细就不多说了,如果运行时候提示

selenium.common.exceptions.WebDriverException: Message: 'chromedriver' executable needs to be in PATH. Please see https://sites.google.com/a/chromium.org/chromedriver/home

则需要到 https://sites.google.com/a/chromium.org/chromedriver/home 下载驱动后解压到/usr/local/bin目录即可。
使用服务器运行时使用phantomjs替换chrome,另外失败的时候可以进行判断自动重试,有兴趣的小伙伴可以自己补充完善。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Python 相关文章推荐
python新手经常遇到的17个错误分析
Jul 30 Python
举例讲解Python中的迭代器、生成器与列表解析用法
Mar 20 Python
python3.5 email实现发送邮件功能
May 22 Python
使用PyInstaller将python转成可执行文件exe笔记
May 26 Python
Django使用Mysql数据库已经存在的数据表方法
May 27 Python
Python基于sklearn库的分类算法简单应用示例
Jul 09 Python
python使用ddt过程中遇到的问题及解决方案【推荐】
Oct 29 Python
详解用python自制微信机器人,定时发送天气预报
Mar 25 Python
python处理excel绘制雷达图
Oct 18 Python
python计算Content-MD5并获取文件的Content-MD5值方式
Apr 03 Python
解决pycharm debug时界面下方不出现step等按钮及变量值的问题
Jun 09 Python
Python爬虫自动化爬取b站实时弹幕实例方法
Jan 26 Python
python验证码识别教程之利用投影法、连通域法分割图片
Jun 04 #Python
python验证码识别教程之灰度处理、二值化、降噪与tesserocr识别
Jun 04 #Python
实用自动化运维Python脚本分享
Jun 04 #Python
python中验证码连通域分割的方法详解
Jun 04 #Python
python 匹配url中是否存在IP地址的方法
Jun 04 #Python
Python实现ping指定IP的示例
Jun 04 #Python
用Python3创建httpServer的简单方法
Jun 04 #Python
You might like
php中看实例学正则表达式
2006/12/25 PHP
php递归创建目录的方法
2015/02/02 PHP
PHP实现的多文件上传类及用法示例
2016/05/06 PHP
Yii2学习笔记之汉化yii设置表单的描述(属性标签attributeLabels)
2017/02/07 PHP
PHP实现使用DOM将XML数据存入数组的方法示例
2017/09/27 PHP
什么是PHP7中的孤儿进程与僵尸进程
2019/04/14 PHP
不用写JS也能使用EXTJS视频演示
2008/12/29 Javascript
JavaScript高级程序设计(第3版)学习笔记13 ECMAScript5新特性
2012/10/11 Javascript
简单实用jquery版三级联动select示例
2013/07/04 Javascript
实用框架(iframe)操作代码
2014/10/23 Javascript
javaScript的函数对象的声明详解
2015/02/06 Javascript
jquery代码实现多选、不同分享功能
2015/07/31 Javascript
Web前端开发工具——bower依赖包管理工具
2016/03/29 Javascript
利用原生JS自动生成文章标题树的实例
2016/08/22 Javascript
JS实现表单多文件上传样式美化支持选中文件后删除相关项
2016/09/30 Javascript
Jquery AJAX POST与GET之间的区别详细介绍
2016/10/17 Javascript
vue将时间戳转换成自定义时间格式的方法
2018/03/02 Javascript
WebSocket的通信过程与实现方法详解
2018/04/29 Javascript
vue解决一个方法同时发送多个请求的问题
2018/09/25 Javascript
详解Vue之父子组件传值
2019/04/01 Javascript
javascript json对象小技巧之键名作为变量用法分析
2019/11/11 Javascript
node.js使用yargs处理命令行参数操作示例
2020/02/11 Javascript
python 字典(dict)遍历的四种方法性能测试报告
2014/06/25 Python
Python编程中实现迭代器的一些技巧小结
2016/06/21 Python
python学习基础之循环import及import过程
2018/04/22 Python
Python logging模块用法示例
2018/08/28 Python
美国珠宝精品店:Opulent Jewelers
2019/08/20 全球购物
美国购买舞会礼服网站:Couture Candy
2019/12/29 全球购物
大学生党课思想汇报
2013/12/29 职场文书
小学生手册家长评语
2014/04/16 职场文书
学生会竞选演讲稿
2014/04/24 职场文书
科学发展观演讲稿
2014/09/11 职场文书
假期安全教育广播稿
2014/10/04 职场文书
2014年业务工作总结
2014/11/17 职场文书
导游词怎么写
2015/02/04 职场文书
妈妈再爱我一次观后感
2015/06/08 职场文书