zoukankan      html  css  js  c++  java
  • 太嚣张了!他竟用Python绕过了“验证码”

    在web页面中,经常会遇到验证码,这对于我这么一个热爱web自动化测试人员,就变成了一件头疼的事。于是千方百计找各种资源得到破解简单的验证码方法。

    识别验证码

      大致分如下几个步骤:

        1.获取验证码图片

        2.灰度处理

        3.增加对比度

        4.降噪

        5.识别

    >>>>获取验证码

      通过各种方法,将含有验证码的图片获取并存贮在本地。

      本次的方法是:截取当前web页面,然后获取验证码在web页面中的位置,通过位置定位验证码图片再次截取。

      以163邮箱注册页面为例

      用到的库:selenium、PIL

      如果是python2.x,pip install PIL;在python3.x中PIL被移植到pillow 中,所以导入时需要导入pillow,pip install pillow  

     1 from PIL import Image
     2 
     3 import time
     4 from selenium import webdriver
     5 
     6 
     7 
     8 def get_code_img(driver):
     9 
    10    time.sleep(1)
    11 
    12    # 截取整个浏览器图
    13    driver.save_screenshot('webImg.png')
    14 
    15    # 获取code元素坐标
    16    code_element = driver.find_element_by_id('vcodeImg')
    17 
    18    # 获取code图片坐标值
    19    left_location = code_element.location['x']
    20    top_location = code_element.location['y']
    21 
    22    right_location = code_element.size['width'] + left_location
    23    below_location = code_element.size['height'] + top_location
    24 
    25    # 通过坐标值得到code image图
    26    web_img = Image.open("webImg.png")
    27    code_img = web_img.crop((left_location,top_location,right_location,below_location))
    28    code_img.save("codeImg.png")

      save_screenshot:webdriver中提供的一个方法,截取整个web页面

      code_element.location:获取某个的位置

      例如:print(code_element.location)的结果为:{'x': 632, 'y': 511}

      他是以图片的左上角为基准点,向右为x,向下为y

      code_element.size:获取图片的尺寸

      crop:是通过四个坐标点获取位置截图并且生成一张新图,他是Image 中的一个方法。

    运行代码

    1 if __name__ == '__main__':
    2 
    3    base_url = 'http://reg.email.163.com/unireg/call.do?cmd=register.entrance&from=126mail'
    4 
    5    driver = webdriver.Chrome()
    6    driver.maximize_window()
    7    driver.get(base_url)
    8    get_code_img(driver)
    9    driver.close()

    运行后获得两张图片webImg.png和codeImg.png。codeImg如下:

     

    >>>>灰度处理/增加对比色

       将图片的颜色变成灰色并且增加对比色,识别时减少不必要的干扰。 

     1 def gray_img(img):
     2    code_img = Image.open(img)
     3    # 转换为灰度
     4    gray_img = code_img.convert('L')
     5    # 增强亮度
     6    enhance_img = ImageEnhance.Contrast(gray_img)
     7    enhance_img = enhance_img.enhance(3)
     8    return enhance_img
     9 
    10 
    11 
    12 if __name__ == '__main__':
    13 
    14      gray_img('codeImg.png').show()

      运行后结果

    >>>>降噪

      根据一个点A的RGB值,与周围的4个点的RGB值进行比较,最初设定一个值N即判断数量(0<N<4),当A的RGB值与周围4个点的RGB相等数小于N时会被视为燥点,被消除。

     1 def clear_noise(img):
     2 
     3 noise_img = img.load()
     4 # 获取图片的尺寸
     5 w,h = img.size
     6 
     7 for y in range(1,h-1):
     8  for x in range(1,w-1):
     9   count = 0
    10   if noise_img[x,y-1] > 245:
    11    count = count + 1
    12   if noise_img[x,y+1] > 245:
    13    count = count + 1
    14   if noise_img[x-1,y] > 245:
    15    count = count + 1
    16   if noise_img[x+1,y] > 245:
    17    count = count + 1
    18   if noise_img[x-1,y-1] > 245:
    19    count = count + 1
    20   if noise_img[x-1,y+1] > 245:
    21    count = count + 1
    22   if noise_img[x+1,y-1] > 245:
    23    count = count + 1
    24   if noise_img[x+1,y+1] > 245:
    25    count = count + 1
    26   if count > 4:
    27       noise_img[x,y] = 255
    28 return img
    29 
    30 if __name__ == '__main__':
    31    img = gray_img('codeImg.png')
    32    clear_noise(img).show()

    运行后结果

    >>>>识别

      识别使用的是pytesseract包。

      Pytesseract包依赖于tesseract,安装的时候两个都需安装

      详情参考

        tesseract: https://github.com/sirfz/tesserocr

        pytesseract:https://github.com/madmaze/pytesseract

    1 text = pytesseract.image_to_string(img)
    2 print(text)

      很遗憾,上面的图没有识别出来。

    完整代码运行识别

    以下图验证码为例

     

     1 from PIL import Image, ImageEnhance
     2 import time
     3 import pytesseract
     4 from selenium import webdriver
     5 
     6 
     7 def clear_noise(img):
     8 noise_img = img.load()
     9 # 获取图片的尺寸
    10 w,h = img.size
    11 
    12 for y in range(1,h-1):
    13  for x in range(1,w-1):
    14   count = 0
    15   if noise_img[x,y-1] > 245:
    16    count = count + 1
    17   if noise_img[x,y+1] > 245:
    18    count = count + 1
    19   if noise_img[x-1,y] > 245:
    20    count = count + 1
    21   if noise_img[x+1,y] > 245:
    22    count = count + 1
    23   if noise_img[x-1,y-1] > 245:
    24    count = count + 1
    25   if noise_img[x-1,y+1] > 245:
    26    count = count + 1
    27   if noise_img[x+1,y-1] > 245:
    28    count = count + 1
    29   if noise_img[x+1,y+1] > 245:
    30    count = count + 1
    31   if count > 4:
    32       noise_img[x,y] = 255
    33 return img
    34 
    35 
    36 def get_code_img(driver):
    37 
    38    time.sleep(1)
    39 
    40    # 截取整个浏览器图
    41    driver.save_screenshot('webImg.png')
    42 
    43    # 获取code元素坐标
    44    code_element = driver.find_element_by_id('vcodeImg')
    45 
    46    # 获取code图片坐标值
    47    left_location = code_element.location['x']
    48    top_location = code_element.location['y']
    49 
    50    right_location = code_element.size['width'] + left_location
    51    below_location = code_element.size['height'] + top_location
    52 
    53    # 通过坐标值得到code image图
    54    web_img = Image.open("webImg.png")
    55    code_img = web_img.crop((left_location,top_location,right_location,below_location))
    56    code_img.save("codeImg.png")
    57 
    58 
    59 def gray_img(img):
    60    code_img = Image.open(img)
    61    # 转换为灰度
    62    gray_img = code_img.convert('L')
    63    # 增强亮度
    64    enhance_img = ImageEnhance.Contrast(gray_img)
    65    enhance_img = enhance_img.enhance(3)
    66    return enhance_img
    67 
    68 
    69 if __name__ == '__main__':
    70 
    71    # base_url = 'http://reg.email.163.com/unireg/call.do?cmd=register.entrance&from=126mail'
    72    #
    73    # driver = webdriver.Chrome()
    74    # driver.maximize_window()
    75    # driver.get(base_url)
    76    # get_code_img(driver)
    77    # driver.close()
    78    img = gray_img('d.png')
    79    img = clear_noise(img)
    80    img.show()
    81    text = pytesseract.image_to_string(img)
    82    print(text)

      运行结果

     

      虽然还是失败的。但至少已经接近了...

      此次只是对验证码的识别做简单的尝试。虽然此方法识别率不是很高。当然网上有很多收费的识别平台,通过大量联系识别率是很高的,有兴趣的可以去了解下。

      在认识验证码后我又来兴趣了,想去探个究竟验证码是怎样生成的...下次分享(皮一下)

    python之验证码的生成

      在识别验证码的玩虐后,决定去看看他是怎么生成的。

     大致步骤:

        1.创建图片

        2.对背景像素处理

        3.写入识别码

        4.增加干扰线

        5.滤镜处理

    用到的库

    1 import random
    2 
    3 from PIL import Image, ImageFont, ImageDraw,ImageFilter

      在开始之前,了解下Image下图片的基本属性

      print(Image.open('img.jpeg'))

      结果:<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=500x291 at 0x103BA3FD0>

        打印的是:图片格式、mode:彩色值、size:尺寸

      也可以直接获取该图片的相关属性

      img = Image.open('img.jpeg')

      print(img.size, img.format, img.mode)

        结果: (500, 291) JPEG RGB

    现在开始生成验证码 

    >>>>创建图片

    1 from PIL import Image
    2 
    3 width = 240
    4 height = 60
    5 
    6 # 图像生成
    7 image = Image.new('RGB', (width,height), color='red')
    8 image.show()

      new()是创建一个图片,第一个参数为图片mode也就是色彩值;

      第二个参数为图片的大小;

      第三个参数是图片颜色。

      show()方法是展示图片

      运行后结果

    >>>>对背景像素处理

    1 # 填充每个像素点
    2 for i in range(width):
    3    for j in range(height
    4 
    5 ):
    6        draw.point((i,j), fill=random_bgcolor())

      random_bgcolor():也是自定义的方法,随机产生颜色。

    def random_bgcolor():
       return (random.randint(60,200)random.randint(60,200),random.randint(60,200))

      返回一个RGB色彩值,其中的颜色取值根据需要设置吧。

    打印结果

    >>>>写入识别码

    1 draw = ImageDraw.Draw(image)
    2 # 写入信息
    3 for i in range(4):
    4    draw.text((60*i+10, 10), get_random(1,4), font=font, fill=random_color())

      ImageDraw.Draw(image)是在图片image上创建一个画笔

      For循环:循环产生4个数字或字母

      draw.text()方法是写入的内容,

        第一个参数是坐标,坐标自己通过图片尺寸稍为计算下,合理布局;

        第二个参数是写入的内容值,这里传入的是让系统随机产生一个数,方法可以自己定义;

        第三个font为字体,设置的字体必须存在

        第四个是对写入的内容附上颜色,这里传入的是让系统随机产生一个颜色,方法可以自己定义;

    第二个参数的方法如下:

     1 def get_random(num,many):
     2        for i in range(many):
     3            s = ""
     4            for j in range(num):
     5                n = random.randint(1,2) # n==1生成数字,n=2生成字母
     6                if n == 1:
     7                    num1 = random.randint(0, 9)
     8                    s +=str(num1)
     9                else:
    10                    s +=str(random.choice(string.ascii_letters))
    11 
    12    return s

    第三个参数字体:

    font = ImageFont.truetype('Arial.ttf',36)

    第四个参数的方法如下:

      直接返回RGB颜色值

    1 def random_color():
    2    return (random.randint(64,255), random.randint(64,255), random.randint(64,255))

      运行上面代码结果:

     

    >>>>增加干扰线

       在生成的验证码图片上添加一条干扰线

    1 for i in range(2):
    2    x1 = random.randint(0, width)
    3    y1 = random.randint(0, height)
    4    x2 = random.randint(0, width)
    5    y2 = random.randint(0, height)
    6    draw.line((x1, y1, x2, y2), fill=random_bgcolor(),width=3)

      draw.line()是画线方法

          第一个参数:线条坐标,即位置。如上是在图片范围内位置随机

          第二个参数:线条的颜色,还是让随机产生

          第三个参数:线条的宽度,不设置的话默认为0

      运行结果

     

    >>>>滤镜处理

       增加滤镜,可以增加颜色的不同

      很简单,一行代码搞定

    1 image = image.filter(ImageFilter.BLUR)

    结果如下:

     

      非常抱歉,我设置产生的随机色颜色值没有调对,导致背景色和字体色颜色太接近,效果看起来不是很好。

      但是滤镜不是必须项,可以不设置。

    完整代码如下

     1 import string
     2 
     3 import random
     4 from PIL import Image, ImageFont, ImageDraw,ImageFilter
     5 
     6 # 生成随机大小数字
     7 def get_random(num,many):
     8        for i in range(many):
     9            s = ""
    10            for j in range(num):
    11                n = random.randint(1,2) # n==1生成数字,n=2生成字母
    12                if n == 1:
    13                    num1 = random.randint(0, 9)
    14                    s +=str(num1)
    15                else:
    16                    s +=str(random.choice(string.ascii_letters))
    17            return s
    18 
    19 # 随机颜色RGB
    20 def random_color():
    21    return (random.randint(64,255), random.randint(64,255), random.randint(64,255))
    22 
    23 # 随机颜色RGB
    24 def random_bgcolor():
    25    return (random.randint(60,200), random.randint(60,200), random.randint(60,200))
    26 
    27 # 字体,字体大小
    28 font = ImageFont.truetype('Arial.ttf',36)
    29 
    30 # 图片尺寸
    31 width = 240
    32 height = 60
    33 
    34 # 图像生成
    35 image = Image.new('RGB', (width,height), color='red')
    36 
    37 # 创建绘图对象
    38 draw = ImageDraw.Draw(image)
    39 
    40 # 填充背景色
    41 for i in range(width):
    42    for j in range(height):
    43        draw.point((i,j), fill=random_bgcolor())
    44 
    45 # 写入信息
    46 for i in range(4):
    47     draw.text((60*i+10, 10), get_random(1,4), font=font, fill=random_color())
    48 
    49 # 插入干扰线
    50 for i in range(2):
    51    x1 = random.randint(0, width)
    52    y1 = random.randint(0, height)
    53    x2 = random.randint(0, width)
    54    y2 = random.randint(0, height)
    55    draw.line((x1, y1, x2, y2), fill=random_bgcolor(),width=3)
    56 
    57 # 添加滤镜
    58 image = image.filter(ImageFilter.BLUR)
    59 
    60 # 展示图片
    61 image.show()
    62 
    63 # 保存
    64 image.save('code.png')

    原文发布在 自动化软件测试 微信公众号,欢迎关注

    原文地址:https://mp.weixin.qq.com/s/x3QT8njMX2wKPXKxqDPRyg

  • 相关阅读:
    填空练习(指向指针的指针)
    练习指针函数:编写一个函数,输入n为偶数时,调用fa函数,当输入n为奇数时,调用fb函数(利用指针函数)。
    输入一个整数,并将其反转后输出。
    有n个人围成一圈,顺序排号。从第一个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来第几号的那位。
    案例练习
    操作don树
    Node对象
    element对象二
    element对象
    在末尾添加节点
  • 原文地址:https://www.cnblogs.com/tynam/p/10532679.html
Copyright © 2011-2022 走看看