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

 更新时间:2018年06月04日 11:48:11   作者:Hi!Roy!  
这篇文章主要给大家介绍了关于python验证码识别教程之滑动验证码的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

前言

上篇文章记录了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中关键字nonlocal和global的声明与解析

    Python中关键字nonlocal和global的声明与解析

    这篇文章主要给大家介绍了关于Python中关键字nonlocal和global的声明与解析的相关资料,文中介绍的非常详细,相信对大家具有一定的参考价值,需要的朋友们下面来一起看看吧。
    2017-03-03
  • Scrapy爬虫框架集成selenium及全面详细讲解

    Scrapy爬虫框架集成selenium及全面详细讲解

    这篇文章主要为大家介绍了Scrapy集成selenium,以及scarpy爬虫框架全面讲解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步早日升职加薪
    2022-04-04
  • 在Django中预防CSRF攻击的操作

    在Django中预防CSRF攻击的操作

    这篇文章主要介绍了在Django中预防CSRF攻击的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-03-03
  • Python推导式数据处理方式

    Python推导式数据处理方式

    这篇文章主要介绍了Python推导式数据处理方式,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的朋友可以参考一下
    2022-07-07
  • python如何绘制极坐标轮廓图contourf

    python如何绘制极坐标轮廓图contourf

    这篇文章主要介绍了python如何绘制极坐标轮廓图contourf问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-08-08
  • 基于Python实现火车票抢票软件

    基于Python实现火车票抢票软件

    每年的节假日一到,大家头疼的总时同一个问题:你买到回家的票了吗?尤其是大型的节日:国庆、春节等。本文将利用Python编写一个火车票抢票软件,感兴趣的可以了解一下
    2022-07-07
  • pyinstaller还原python代码过程图解

    pyinstaller还原python代码过程图解

    这篇文章主要介绍了pyinstaller还原python代码过程图解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-01-01
  • python处理xml文件操作详解

    python处理xml文件操作详解

    这篇文章主要介绍了python处理xml文件操作详解,文章围绕主题展开详细内容,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-07-07
  • Python的collections模块真的很好用

    Python的collections模块真的很好用

    collections是实现了特定目标的容器,以提供Python标准内建容器 dict , list , set , 和 tuple 的替代选择,本文详细总结collections的相关知识,感兴趣的朋友跟随看看吧
    2021-03-03
  • 用python编写一个图片拼接工具

    用python编写一个图片拼接工具

    大家好,本篇文章主要讲的是用python编写一个图片拼接工具,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下
    2022-01-01

最新评论