小豬的Python學習之旅 —— 13.文字識別庫pytesseract初體驗

coder-pig發表於2018-03-01

引言

度過了短暫的春節假期,又要開始繼續搬磚了,因為還處於節後 綜合徵,各種散漫,不想看任何程式碼相關的東西,根本擠不出學習熱情... 恰逢前幾天,公司的UI妹子安利了一個賣萌的新番:小木乃伊到我家

小豬的Python學習之旅 —— 13.文字識別庫pytesseract初體驗

就是圖中的這四隻小東西,敲可愛的說,分別叫:

小伊(木乃伊),可尼(小鬼,牛),啊勇(龍),胖嘟嘟

UI妹子尤其喜歡可尼,是挺萌的,突然想找些相關的手機或者電腦桌布, 桌布沒找到,卻在 小木乃伊到我家吧 裡找到了一些自制的表情包: tieba.baidu.com/p/552209106…

小豬的Python學習之旅 —— 13.文字識別庫pytesseract初體驗

表情都很有趣嘛,寫個指令碼把圖片都爬下來?走一波流程:

Step 1:Network抓包看下返回的資料是否和Element一致, 或者說有我們想要的資料,而不是通過JS黑魔法進行載入的;

複製下第一個圖的圖片連結,到Network選項卡里的Response 裡查詢以下,嗯,找得到,可以:

小豬的Python學習之旅 —— 13.文字識別庫pytesseract初體驗

Step 2:滾動到底,抓包沒有發現Ajax動態載入資料的蹤跡

Step 3:點選第二頁,抓包發現了Ajax載入的痕跡!!!

小豬的Python學習之旅 —— 13.文字識別庫pytesseract初體驗

同樣拿第一個圖的url搜下,同樣可以找到

小豬的Python學習之旅 —— 13.文字識別庫pytesseract初體驗

三個引數猜測pn為page_number,即頁數,PostMan或者自己 寫程式碼模擬請求,記得塞入Host和X-Requested-With,驗證pn=1 是否為第一頁資料,驗證通過,即所有頁面資料都可以通過這個 介面拿到;

Step 4:先載入拿到末頁是第幾頁,然後走一波迴圈遍歷即可 解析資料獲得圖片url,寫入檔案,使用多個執行緒進行下載 比較簡單,就不詳解了,直接給出程式碼,看不懂的自己複習去:

# 抓取百度貼吧某個帖子裡的所有圖片
import coderpig_n as cpn
import requests
import time
import threading
import queue

tiezi_url = "https://tieba.baidu.com/p/5522091060"
headers = {
    'Host': 'tieba.baidu.com',
    'User-Agent': cpn.user_agent_dict['chrome'],
}

pic_save_dir = 'output/Picture/BaiduTieBa/'
pic_urls_file = 'tiezi_pic_urls.txt'
download_q = queue.Queue()  # 下載佇列


# 獲得頁數
def get_page_count():
    try:
        resp = requests.get(tiezi_url, headers=headers, timeout=5)
        if resp is not None:
            soup = cpn.get_bs(resp.text)
            a_s = soup.find("ul", attrs={'class': 'l_posts_num'}).findAll("a")
            for a in a_s:
                if a.get_text() == '尾頁':
                    return a['href'].split('=')[1]
    except Exception as e:
        print(str(e))


# 下載執行緒
class PicSpider(threading.Thread):
    def __init__(self, t_name, func):
        self.func = func
        threading.Thread.__init__(self, name=t_name)

    def run(self):
        self.func()


# 獲得每頁裡的所有圖片
def get_pics(count):
    while True:
        params = {
            'pn': count,
            'ajax': '1',
            't': int(time.time())
        }
        try:
            resp = requests.get(tiezi_url, headers=headers, timeout=5, params=params)
            if resp is not None:
                soup = cpn.get_bs(resp.text)
                imgs = soup.findAll('img', attrs={'class': 'BDE_Image'})
                for img in imgs:
                    cpn.write_str_data(img['src'], pic_urls_file)
                return None
        except Exception as e:
            pass
    pass


# 下載執行緒呼叫的方法
def down_pics():
    global download_q
    while not download_q.empty():
        data = download_q.get()
        download_pic(data)
        download_q.task_done()


# 下載呼叫的方法
def download_pic(img_url):
    while True:
        proxy_ip = {
            'http': 'http://' + cpn.get_dx_proxy_ip(),
            'https': 'https://' + cpn.get_dx_proxy_ip()
        }
        try:
            resp = requests.get(img_url, headers=headers, proxies=proxy_ip, timeout=5)
            if resp is not None:
                print("下載圖片:" + resp.request.url)
                pic_name = img_url.split("/")[-1]
                with open(pic_save_dir + pic_name, "wb+") as f:
                    f.write(resp.content)
                return None
        except Exception as e:
            pass


if __name__ == '__main__':
    cpn.is_dir_existed(pic_save_dir)
    print("檢索判斷連結檔案是否存在:")
    if not cpn.is_dir_existed(pic_urls_file, mkdir=False):
        print("不存在,開始解析帖子...")
        page_count = get_page_count()
        if page_count is not None:
            headers['X-Requested-With'] = 'XMLHttpRequest'
            for page in range(1, int(page_count) + 1):
                get_pics(page)
        print("連結已解析完畢!")
        headers.pop('X-Requested-With')
    else:
        print("存在")
    print("開始下載圖片~~~~")
    headers['Host'] = 'imgsa.baidu.com'
    pic_list = cpn.load_list_from_file(pic_urls_file)
    threads = []
    for pic in pic_list:
        download_q.put(pic)
    for i in range(0, len(pic_list)):
        t = PicSpider(t_name='執行緒' + str(i), func=down_pics)
        t.daemon = True
        t.start()
        threads.append(t)
    download_q.join()
    for t in threads:
        t.join()
    print("圖片下載完畢")
複製程式碼

執行結果

小豬的Python學習之旅 —— 13.文字識別庫pytesseract初體驗

接著在和UI妹子聊天的時候就可以拿這些表情來鬥圖了,但是問題來了, 總共有165個圖,我每次想說什麼都要開啟圖片一個個看文字是否 符合場景,然後才發,有點呆,而且浪費時間,有沒有什麼快點 找到表情的方法呢?

答:直接把表情裡的文字作為圖片名不就好了,直接檔案搜尋搜關鍵字;

但是問題又來了,一張張去改檔名?多呆哦!

突然想起之前看過一篇**頭腦王者**答題輔助指令碼的文章,就是 利用OCR文字識別,把識別出來的文字丟百度上搜尋,選項頻度最高 的一般就是正確答案,可以試一波這個套路,谷歌為我們提供了一個 免費的ORC文字識別引擎:Tesseract 倉庫地址:github.com/tesseract-o…


1.裝一波環境

穩定版本是3.0,4.0版本還處於研發,一開始以為新版的肯定牛逼 一些,裝了4.0的發現對於中文的識別效率超低,差太遠了,後來 又換回了3.0版本,情況稍微好一些,當然可以通過其他方法提高 中文識別率,圖片裁剪,調節對比度,黃底黑字,自己訓練語言庫等, 不是本節的學習範疇,本節寫個簡單的例子瞭解下怎麼用而已~

更多可移步到:ubuntu下使用Tesseract-ocr(編譯、安裝、使用、訓練新的語言庫) 各個版本介紹:github.com/tesseract-o…


Ubuntu 14.04 環境安裝(其他系統環境後續用到再補充...)

1.安裝tesseract-ocr

sudo apt-get install tesseract-ocr
tesseract --version
複製程式碼

小豬的Python學習之旅 —— 13.文字識別庫pytesseract初體驗

2.安裝pytesseractImage

sudo pip install pytesseract
sudo pip install Image
複製程式碼

3.下載tesseract中文簡體字型檔

預設安裝後是不帶中文簡體庫的,官方倉庫走一波: github.com/tesseract-o… 記得選擇版本Tag,3.0的tesseract-ocr是用不了4.0的字型檔的!!! 如果你下錯了,呼叫的時候會報3.0用不了4.0的字型檔的錯誤!!!

小豬的Python學習之旅 —— 13.文字識別庫pytesseract初體驗

這兩個就是對應中文簡體與繁體:

小豬的Python學習之旅 —— 13.文字識別庫pytesseract初體驗

字型檔下載後需要放到下面的目錄下:/usr/share/tesseract-ocr/tessdata 然後你發現字型檔檔案無法拷貝到該目錄下,因為需要許可權,這裡可以通過 命令列拷貝一波:

sudo cp '/home/jay/下載/chi_sim.traineddata' /usr/share/tesseract-ocr/tessdata
複製程式碼

前面是原始檔,後面是拷貝到哪個目錄下。

好了,到此就準備完成了,接著寫個簡單的程式來識別一波!


2.識別一波圖片

程式碼忒簡單,建立一個Image物件,呼叫下**pytesseract.image_to_string()**方法 就能識別文字了,引數依次是Image物件,識別語言型別,chi_sim中文簡體

import pytesseract
from PIL import Image

image = Image.open('1.png')
text = pytesseract.image_to_string(image, lang='chi_sim')
print(text.replace(" ", ""))
複製程式碼

隨手截一波掘金首頁的分類欄:

小豬的Python學習之旅 —— 13.文字識別庫pytesseract初體驗

執行一波:

小豬的Python學習之旅 —— 13.文字識別庫pytesseract初體驗

識別結果有點感人,調一張表情圖試試:

小豬的Python學習之旅 —— 13.文字識別庫pytesseract初體驗

識別結果:

小豬的Python學習之旅 —— 13.文字識別庫pytesseract初體驗

???都識別出來什麼東西,後面試了幾張圖片我還發現不止識別 錯誤,有時連字都識別不出來...在不自己去訓練字型庫的情況下, 中文識別率真心感人,不過最大的有點優點還是:Tesseract免費。 識別數字或者英語的時候,還湊合,隨手複製一段英文:

小豬的Python學習之旅 —— 13.文字識別庫pytesseract初體驗

設定下lang='eng',輸出結果:

小豬的Python學習之旅 —— 13.文字識別庫pytesseract初體驗

免費的識別率低,試試收費的怎樣,百度雲OCR


3.試試百度雲OCR

收費每天免費500次,拿來完成我們這個圖片命名的小指令碼足矣! 官方文件文字識別 - Python SDK文件

配置流程

1.開通文字識別服務cloud.baidu.com/product/ocr…

2.建立一個應用,然後記下API KeySecret Key 程式裡要用

小豬的Python學習之旅 —— 13.文字識別庫pytesseract初體驗

3.點右上角->使用者中心,抄下自己的使用者ID

小豬的Python學習之旅 —— 13.文字識別庫pytesseract初體驗

4.pip命令安裝一波

sudo pip install baidu-aip
複製程式碼

編寫簡單程式碼

from aip import AipOcr

# 新建一個AipOcr物件
config = {
    'appId': 'XXX',
    'apiKey': 'YYY',
    'secretKey': 'ZZZ'
}
client = AipOcr(**config)


# 讀取圖片
def get_file_content(file_path):
    with open(file_path, 'rb') as fp:
        return fp.read()

# 識別圖片裡的文字
def img_to_str(image_path):
    image = get_file_content(image_path)
    # 呼叫通用文字識別, 圖片引數為本地圖片
    result = client.basicGeneral(image)
    # 結果拼接返回
    if 'words_result' in result:
        return '\n'.join([w['words'] for w in result['words_result']])


if __name__ == '__main__':
    print(img_to_str('1.png'))
複製程式碼

試試上面掘金的那個,輸出結果:

小豬的Python學習之旅 —— 13.文字識別庫pytesseract初體驗

嘖嘖,可以的,試試搞基那個表情?

小豬的Python學習之旅 —— 13.文字識別庫pytesseract初體驗

嗯,還是有點小錯誤,在文件裡找到:

小豬的Python學習之旅 —— 13.文字識別庫pytesseract初體驗

把**basicGeneral** 改為 basicAccurate,結果:

小豬的Python學習之旅 —— 13.文字識別庫pytesseract初體驗

嘖嘖,完美識別,稍微慢了一點點,接下來把程式碼完善下, 把所有的圖片重新命名一波咯!


4.實戰:利用百度OCR識別自動修改檔名

遍歷資料夾,獲得所有的圖片路徑,然後文字識別一波,獲得結果集 里長度最長的字串作為檔名,能識別的就修改下檔名,完整程式碼 如下:

import os
from aip import AipOcr

# 新建一個AipOcr物件
config = {
    'appId': 'XXX',
    'apiKey': 'YYY',
    'secretKey': 'ZZZ'
}
client = AipOcr(**config)

pic_dir = r"/home/jay/圖片/BaiduTieBa/"


# 讀取圖片
def get_file_content(file_path):
    with open(file_path, 'rb') as fp:
        return fp.read()


# 識別圖片裡的文字
def img_to_str(image_path):
    image = get_file_content(image_path)
    # 呼叫通用文字識別, 圖片引數為本地圖片
    result = client.basicGeneral(image)
    # 結果拼接返回
    words_list = []
    if 'words_result' in result:
        if len(result['words_result']) > 0:
            for w in result['words_result']:
                words_list.append(w['words'])
            file_name = get_longest_str(words_list)
            print(file_name)
            os.rename(image_path, pic_dir + str(file_name).replace("/", "") + '.jpg')


# 獲取字串列表中最長的字串
def get_longest_str(str_list):
    return max(str_list, key=len)


# 遍歷某個資料夾下所有圖片
def query_picture(dir_path):
    pic_path_list = []
    for filename in os.listdir(dir_path):
        pic_path_list.append(dir_path + filename)
    return pic_path_list


if __name__ == '__main__':
    pic_list = query_picture(pic_dir)
    if len(pic_list) > 0:
        for i in pic_list:
            img_to_str(i)
複製程式碼

執行結果

小豬的Python學習之旅 —— 13.文字識別庫pytesseract初體驗

要注意一點,高精度版免費只有50次,我一開始不知道,後面跑程式 突然卡住一直不動,這點要注意,後面還是用回了普通模式,所以有 些檔名並不完全是對的,就調調API的事,非常簡單,專案有極大 剛需要用到文字識別的自行去官網瞭解吧~


5.小結

本節簡單的瞭解了一下pytesseract這個免費的OCR識別庫, 對於中文的識別率不高,後面試了下百度雲OCR,順道寫了 一個簡單的實戰專案,都比較簡單,那麼本節就到這裡啦~

小豬的Python學習之旅 —— 13.文字識別庫pytesseract初體驗


來啊,Py交易啊

想加群一起學習Py的可以加下,智障機器人小Pig,驗證資訊裡包含: PythonpythonpyPy加群交易屁眼 中的一個關鍵詞即可通過;

小豬的Python學習之旅 —— 13.文字識別庫pytesseract初體驗

驗證通過後回覆 加群 即可獲得加群連結(不要把機器人玩壞了!!!)~~~ 歡迎各種像我一樣的Py初學者,Py大神加入,一起愉快地交流學♂習,van♂轉py。

小豬的Python學習之旅 —— 13.文字識別庫pytesseract初體驗


相關文章