ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

太嚣张了!他竟用Python绕过了“验证码”

2019-03-14 18:52:34  阅读:224  来源: 互联网

标签:count code img Python random 验证码 noise location 竟用


在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

 

标签:count,code,img,Python,random,验证码,noise,location,竟用
来源: https://www.cnblogs.com/tynam/p/10532679.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有