[Python][爬蟲]使用 pytesseract 與 Image 套件解析驗證碼
當爬網站碰到需要讀取驗證碼的網站時可以使用 pytesseract 與 Image 套件來讀取圖片上的數字與英文。
基本流程:
- 找到圖片的來源網址
- 下載圖片
- 調整圖片、解析圖片,獲得圖片上的數字與英文
- 帶入參數
以 經濟部公司及分公司基本資料查詢系統 為例,從檢查元素中可以發現,在載入這個頁面時會有一個產生圖片的 網址 同時被載入。而這個頁面正是送出 requests 時會產生的驗證碼圖片。
所以只要能下載這個圖片並解析它,就能將解析出來的結果帶進 post 的參數裡,就能完成一個 post requests 。
解析驗證碼完整程式碼
s = requests.Session()
# 1. 找到圖片的來源網址
img_url = "https://serv.gcis.nat.gov.tw/pub/kaptcha.jpg"
res = s.get(img_url, stream = True, verify = True, timeout = 30)
# 2. 下載圖片
with open('pic.jpg','wb') as f:
f.write(res.content)
# 3. 調整圖片、解析圖片,獲得圖片上的數字與英文
image = Image.open('pic.jpg')
# adjust pitcure size, it would read more correctly
image.resize((150, 50),Image.ANTIALIAS).save("pic.jpg")
image = Image.open("pic.jpg")
captcha = pytesseract.image_to_string(image).replace(" ", "").replace("-", "").replace("$", "")
程式碼步驟解析
session()
這裡使是 session 是因為要記錄載入頁面的 cookies,以確保讓網站覺得和等下要送出 requests 時事同時載入的。
s = requests.Session()
找到圖片的來源網址與存檔
img_url = "https://serv.gcis.nat.gov.tw/pub/kaptcha.jpg"
res = s.get(img_url, stream = True, verify = True, timeout = 30)
with open('pic.jpg','wb') as f:
f.write(res.content)
這前面兩行很簡單,就是送出驗證碼來源網址的 requests,接著下載該圖檔,會發現這時候產生了一個 pic.jpg 的檔案。
調整圖片、解析圖片,獲得圖片上的數字與英文
image = Image.open('pic.jpg')
print image
# adjust pitcure size, it would read more correctly
image.resize((150, 50),Image.ANTIALIAS).save("pic.jpg")
image = Image.open("pic.jpg")
print image
captcha = pytesseract.image_to_string(image).replace(" ", "").replace("-", "").replace("$", "")
print captcha
有時候將下載下來的圖片直接丟進 pytesseract.image_to_string() 解析結果正確率會很低,但如果調整一下圖片的 size 反而會有較正確的結果。所以前面我先使用 resize 調整圖片的大小,並重新存檔。最後再使用 pytesseract.image_to_string() 解析圖片。
可以根據 pytesseract.image_to_string() 解析出來的結果做些調整以提高正確率。因為發現這個圖片解析出來後常會有些多餘的符號,所以使用 replace 修正。
圖片的 mode 必須要為 RGB
另外,可以使用print image
看 open() 後的圖片的資訊。
像是被調整過後的圖片變成
<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=150x50 at 0x109355D90>
圖片的尺寸(size)變成 150x50,mode 為 RGB。這點很重要,因為如果 mode 不是 RGB 就會無法 使用 pytesseract.image_to_string()
解析圖片。
會碰到錯誤訊息
/usr/local/lib/python2.7/site-packages/PIL/Image.py:971: UserWarning: Couldn't allocate palette entry for transparency
"for transparency")
---省略--
TypeError: int() argument must be a string or a number, not 'tuple'
譬如我曾經抓到一個圖片,print 出來的圖片資訊是
<PIL.GifImagePlugin.GifImageFile image mode=P size=60x20 at 0x10F1DCD10>
這時候必須要把 mode 由 P 轉為 RGB,只要在 open() 後加上一行,
image = Image.open('pic.gif')
image = image.convert('RGB')
# print image
這是後print image
會發現 mode 已被改為 RGB,且可以正確執行了。
基本上,根據上面的概念就可以破解驗證碼,只要再根據個別網站的狀況做調整就好。