因為需求,所以接觸了驗證碼這一塊,原本感覺到會很難,學了之后挺簡單的,但后來又發現自己還是too young。。。
PIL(python Image Library)
目前PIL的官方最新版本為1.1.7,支持的版本為python 2.5, 2.6, 2.7,
PIL官方網站:http://www.pythonware.com/products/pil/
不支持python3,但有高手把它重新編譯生成python3下可安裝的exe了。這一非官方下載地址 http://www.lfd.uci.edu/~gohlke/pythonlibs/#pil ,
,它已經多年未更新了,差不多已經被遺棄了。
pillow
Pillow是PIL的一個派生分支,但如今已經發展成為比PIL本身更具活力的圖像處理庫。pillow可以說已經取代了PIL,將其封裝成python的庫(pip即可安裝),且支持python2和python3,目前最新版本是3.0.0。
Pillow的Github主頁:https://github.com/python-pillow/Pillow
Pillow的文檔(對應版本v3.0.0):
https://pillow.readthedocs.org/en/latest/handbook/index.html
安裝它很簡單 pip install pillow
使用方式:
#python2
import Image
#python3(因為是派生的PIL庫,所以要導入PIL中的Image)from PIL import Image
以python3為例,
- open
from PIL import Image im = Image.open("1.png") im.show()
- format
format屬性定義了圖像的格式,如果圖像不是從文件打開的,那么該屬性值為None;size屬性是一個tuple,表示圖像的寬和高(單位為像素);mode屬性為表示圖像的模式,常用的模式為:L為灰度圖,RGB為真彩色,CMYK為pre-press圖像。如果文件不能打開,則拋出IOError異常。
print(im.format, im.size, im.mode)
- save
im.save("c:\\")
- convert()
convert() 是圖像實例對象的一個方法,接受一個 mode 參數,用以指定一種色彩模式,mode 的取值可以是如下幾種:
· 1 (1-bit pixels, black and white, stored with one pixel per byte)
· L (8-bit pixels, black and white)
· P (8-bit pixels, mapped to any other mode using a colour palette)
· RGB (3x8-bit pixels, true colour)
· RGBA (4x8-bit pixels, true colour with transparency mask)
· CMYK (4x8-bit pixels, colour separation)
· YCbCr (3x8-bit pixels, colour video format)
· I (32-bit signed integer pixels)
· F (32-bit floating point pixels)
im = Image.open('1.png').convert('L')
- Filter
from PIL import Image, ImageFilter
im = Image.open(‘1.png’)
# 高斯模糊
im.filter(ImageFilter.GaussianBlur)
# 普通模糊
im.filter(ImageFilter.BLUR)
# 邊緣增強
im.filter(ImageFilter.EDGE_ENHANCE)
# 找到邊緣
im.filter(ImageFilter.FIND_EDGES)
# 浮雕
im.filter(ImageFilter.EMBOSS)
# 輪廓
im.filter(ImageFilter.CONTOUR)
# 銳化
im.filter(ImageFilter.SHARPEN)
# 平滑
im.filter(ImageFilter.SMOOTH)
# 細節
im.filter(ImageFilter.DETAIL)
-
查看圖像直方圖
im.histogram() -
轉換圖像文件格式
def img2jpg(imgFile): if type(imgFile)==str and imgFile.endswith(('.bmp', '.gif', '.png')): with Image.open(imgFile) as im: im.convert('RGB').save(imgFile[:-3]+'jpg')
img2jpg('1.gif') img2jpg('1.bmp') img2jpg('1.png')
-
屏幕截圖
from PIL import ImageGrab
im = ImageGrab.grab((0,0,800,200)) #截取屏幕指定區域的圖像
im = ImageGrab.grab() #不帶參數表示全屏幕截圖 -
圖像裁剪與粘貼
box = (120, 194, 220, 294) #定義裁剪區域
region = im.crop(box) #裁剪
region = region.transpose(Image.ROTATE_180)
im.paste(region,box) #粘貼 -
圖像縮放
im = im.resize((100,100)) #參數表示圖像的新尺寸,分別表示寬度和高度
-
圖像對比度增強
from PIL import Image
from PIL import ImageEnhance
#原始圖像 image = Image.open('lena.jpg') image.show() #亮度增強 enh_bri = ImageEnhance.Brightness(image) brightness = 1.5 image_brightened = enh_bri.enhance(brightness) image_brightened.show() #色度增強 enh_col = ImageEnhance.Color(image) color = 1.5 image_colored = enh_col.enhance(color) image_colored.show() #對比度增強 enh_con = ImageEnhance.Contrast(image) contrast = 1.5 image_contrasted = enh_con.enhance(contrast) image_contrasted.show() #銳度增強 enh_sha = ImageEnhance.Sharpness(image) sharpness = 3.0 image_sharped = enh_sha.enhance(sharpness) image_sharped.show()
pytesseract
Python-tesseract是一款用於光學字符識別(OCR)的python工具,即從圖片中識別出其中嵌入的文字。Python-tesseract是對Google Tesseract-OCR的一層封裝。它也同時可以單獨作為對tesseract引擎的調用腳本,支持使用PIL庫(Python Imaging Library)讀取的各種圖片文件類型,包括jpeg、png、gif、bmp、tiff和其他格式,。作為腳本使用它將打印出識別出的文字而非寫入到文件。所以安裝pytesseract前要先安裝PIL(也就是現在的pillow)和tesseract-orc這倆依賴庫
tesseract-ocr是谷歌的開源項目,用於圖像文本識別,具體安裝使用情況可以參照圖片文字OCR識別-tesseract-ocr4.00.00安裝使用(4.000版本是實驗版,建議使用正式版的3.X)
pytesseract是調用tesseract的一個庫,所以必須先安裝好tesseract,
如何安裝pytesseract
pip install pytesseract
如何使用pytesseract
from PIL import Image#后面的lang是語言的意思,fra是法語的意思.
import pytesseract
print(pytesseract.image_to_string(Image.open('test.png')))
print(pytesseract.image_to_string(Image.open('test-european.jpg'), lang='fra'))
很簡單,pytesseract只有一個簡單的image_to_string方法。
示例
圖片:
from PIL import Image
from PIL import ImageEnhance
import pytesseract
im=Image.open("1.jpg") im=im.convert('L') im.show() im=ImageEnhance.Contrast(im) im=im.enhance(3) im.show() print(pytesseract.image_to_string(im))
結果:
圖一:
圖二:
打印結果: 
打碼平台
眾所周知,上面的驗證碼識別都是小兒科,也就簡單的上面可以去去噪,換換灰度什么的,要是碰到了神奇的干擾線,或者奇葩的字母組合,那就基本上歇菜了,目前的驗證碼識別依舊存在着巨大的問題,所以打碼平台也就經久不衰了,這么多年過去了,非但沒有就此陌去,反而得到了飛速的發展,其中幾個比較有名,下次有時間再來補充。。。
——來補充了———
這次選擇的是雲打碼平台(非廣告),當然啦,只是本人選擇的是雲打碼,事實上其他的打碼平台都是類似的,
首先要分清楚雲打碼平台的賬戶種類
雲打碼平台分兩種:用戶和開發者
我們只需使用用戶就可以了
注冊完之后可以選擇充值,先充1塊錢,有2000積分,下面是使用積分的說明:

也就是說1塊錢大概可以使用50次以上,這還是可以接受的
接下來就簡單多了
用戶username: ……..
密碼password: ………
賬戶余額balance:………..分
只需修改驗證碼地址和驗證碼種類,填好注冊時的用戶名和密碼,然后運行即可輸出相關信息,目測新浪微博驗證碼識別率95%以上
直接運行下面的源碼即可(記得改好上面的要求)
import http.client, mimetypes, urllib, json, time, requests ###################################################################### #驗證碼地址**(記得修改)** Image="C:\\Users\\Desktop\\ORC\\1.png" #驗證碼種類**(記得修改)** Species=1005 class YDMHttp: apiurl = 'http://api.yundama.com/api.php' username = '' password = '' appid = '' appkey = '' def __init__(self, username, password, appid, appkey): self.username = username self.password = password self.appid = str(appid) self.appkey = appkey def request(self, fields, files=[]): response = self.post_url(self.apiurl, fields, files) response = json.loads(response) return response def balance(self): data = {'method': 'balance', 'username': self.username, 'password': self.password, 'appid': self.appid, 'appkey': self.appkey} response = self.request(data) if (response): if (response['ret'] and response['ret'] < 0): return response['ret'] else: return response['balance'] else: return -9001 def login(self): data = {'method': 'login', 'username': self.username, 'password': self.password, 'appid': self.appid, 'appkey': self.appkey} response = self.request(data) if (response): if (response['ret'] and response['ret'] < 0): return response['ret'] else: return response['uid'] else: return -9001 def upload(self, filename, codetype, timeout): data = {'method': 'upload', 'username': self.username, 'password': self.password, 'appid': self.appid, 'appkey': self.appkey, 'codetype': str(codetype), 'timeout': str(timeout)} file = {'file': filename} response = self.request(data, file) if (response): if (response['ret'] and response['ret'] < 0): return response['ret'] else: return response['cid'] else: return -9001 def result(self, cid): data = {'method': 'result', 'username': self.username, 'password': self.password, 'appid': self.appid, 'appkey': self.appkey, 'cid': str(cid)} response = self.request(data) return response and response['text'] or '' def decode(self, filename, codetype, timeout): cid = self.upload(filename, codetype, timeout) if (cid > 0): for i in range(0, timeout): result = self.result(cid) if (result != ''): return cid, result else: time.sleep(1) return -3003, '' else: return cid, '' def post_url(self, url, fields, files=[]): for key in files: files[key] = open(files[key], 'rb'); res = requests.post(url, files=files, data=fields) return res.text ###################################################################### # 用戶名(填自己的)**(記得修改)** username = '*************' # 密碼(填自己的)**(記得修改)** password = '*******' # 軟件ID,開發者分成必要參數。登錄開發者后台【我的軟件】獲得!(非開發者不用管) appid = 1 # 軟件密鑰,開發者分成必要參數。登錄開發者后台【我的軟件】獲得!(非開發者不用管) appkey = '22cc5376925e9387a23cf797cb9ba745' # 圖片文件 filename = Image # 驗證碼類型,# 例:1004表示4位字母數字,不同類型收費不同。請准確填寫,否則影響識別率。在此查詢所有類型 http://www.yundama.com/price.html codetype = Species # 超時時間,秒 timeout = 60 # 檢查 if (username == 'username'): print('請設置好相關參數再測試') else: # 初始化 yundama = YDMHttp(username, password, appid, appkey) # 登陸雲打碼 uid = yundama.login(); print('uid: %s' % uid) # 查詢余額 balance = yundama.balance(); print('balance: %s' % balance) # 開始識別,圖片路徑,驗證碼類型ID,超時時間(秒),識別結果 cid, result = yundama.decode(filename, codetype, timeout); print('cid: %s, result: %s' % (cid, result)) ######################################################################
附贈幾張新浪微博的驗證碼: 



小結
驗證碼是一個神奇的產物,它充分的遏制住了一大批計算機上網的沖動,就是這么一個小小的驗證碼阻擋住了千軍萬馬,但是我相信未來的算法一定會將這個產物解決掉的-。-。-。-。-。-。-。
