[Python][爬蟲]使用 pytesseract 與 Image 套件解析驗證碼

當爬網站碰到需要讀取驗證碼的網站時可以使用 pytesseractImage 套件來讀取圖片上的數字與英文。

基本流程:

  1. 找到圖片的來源網址
  2. 下載圖片
  3. 調整圖片、解析圖片,獲得圖片上的數字與英文
  4. 帶入參數

經濟部公司及分公司基本資料查詢系統 為例,從檢查元素中可以發現,在載入這個頁面時會有一個產生圖片的 網址 同時被載入。而這個頁面正是送出 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,且可以正確執行了。


基本上,根據上面的概念就可以破解驗證碼,只要再根據個別網站的狀況做調整就好。

經濟部公司及分公司基本資料查詢系統爬蟲網站 完整程式碼 。或是,另外比較複雜的驗證碼可以參考我的 github