在 AWS Lambda 上執行 Tesseract OCR
最近因為公司爬蟲需求,需要破解驗證碼,因緣際會接觸到 Tesseract ,發現是個不錯的 tool,還有 python library 可以用😍。在不做任何 Image 的 Preprocess,或是 Training 的情況下,已經可以有五、六成的成功率(我好容易滿足啊XD),由於爬蟲架構的需求,我們覺得 Tesseract 很適合放到 Cloud 上,當成一個 Service 執行,因此,就想在 AWS Lambda 上把它跑起來。
簡單來說,需要以下幾個流程才能把 Tesseract + pytesseract 執行起來
- Lambda Function - pytesseract
- Lambda Layer - Tesseract
- Deploy to Lambda - by Serverless
其實之前有寫過一些簡單的 Lambda (就是單純的 Python code)。但是,一想到這個新的獨立 Service,要重新設定一次所有的東西,還要自己 build 一些 module 就覺得麻煩,所以這次用了一個新的 Tool — serverless framework
,輕輕鬆鬆搞定 AWS Lambda Deploy 的流程。
1. Lambda Function - pytesseract
由於驗證碼的需求,我們執行的環境就需要透過 pip 安裝這兩個 package — pytesseract
& Pillow
Lambda 可以讓你把 pip install 的 package 打包成 zip
檔,再包入你自己的 script 後,只要指定好 handler 的 entry point,就可以整包上傳執行了。 .zip
裡的結構大概如下:
├── handler.py
├── PIL/
└── pytesseract/
pytesseract
因為是純 python code,所以 Lambda 執行是沒有問題的。但是 Pillow
的程式碼有些是 C code ,所以在安裝時其實是需要 compile 的。在 Mac or Linux 上,在 build 完後,就會產生 machine dependency 的 .so
檔。如果你把本機端透過 pip 安裝的 python site-packages: PIL 直接包入 .zip
的話,上傳到 Lambda 執行,會產生 PIL
import error。因為 .so
是不相容的,Lambda 在 AWS 執行的 VM OS 是 Amazon Linux。
因此,需要在本機端把 Pillow
的 .so
build 出一份可以在 Lambda 上的 Amazon Linux 才行。不管是用 cross-compile or Docker,只要可以達到我們想要的結果,就是可行的方式。
在下面 serverless
的部分會再解講 build Pillow
的方式。
2. Lambda Layer - Tesseract
在本機端(ex: Mac),如果你想要執行 pytesseract ,除了需要用 pip 安裝 pytesseract 外,還需要透過 brew 安裝 tesseract library
$ brew install tesseract
那麼,在 Lambda 上,該怎麼裝上 tesseract 呢? 也是需要 build 出一個 可以在 Amazon Linux 上執行起來的 tesseract library。這邊的話,沒有官方已經 build 好的版本,所以就必需要自行去 build 才行。
這邊的 github repo - aws lambda tesseract layer 已經幫我們把 Dockerfile 寫好了,可以直接拿來使用。
使用方式
$ git clone https://github.com/bweigel/aws-lambda-tesseract-layer.git
$ cd aws-lambda-tesseract-layer
$ ./build.sh
$ serverless deploy
解釋一下其中大概的流程
- 在 Docker (from
lambcoi/lambda-base
) 中,build 出 Amazon Linux 環境需要的 tesseract library - docker build 完成後,把 container 裡面的
/opt/build-dist
複製一份到本機端 - 最後透過 serverless deploy 到 Lambda 的 Layer 上
基本上 Lambda 的 Function 可以指定使用哪一些 Layer,所以我們 deploy tesseract layer 後,pytesseract Lambda Function 就可以綁定使用了
Dockerfile 裡面的參數可以自行微調
ARG LEPTONICA_VERSION=1.78.0
ARG TESSERACT_VERSION=4.1.0-rc4
ARG OCR_LANG=deu
ARG TESSERACT_DATA_SUFFIX=_fast
ARG TESSERACT_DATA_VERSION=4.0.0
TESSERACT_VERSION
目前最新的是 4.1.0OCR_LANG
這個 script 預設只會裝eng
osd
與OCR_LANG
指定的 language
可以依你的需求,在 Dockerfile 裡多指定一些 language 複製到tesseract/share/tessdata
TESSERACT_DATA_SUFFIX
tesseract train data 分成幾種
- tessdata
- tessdata_fast : train data 檔案比較小,所以跑的速度比較快
- tessdata_best : train data 檔案比較大
3. Serverless
Serverless 針對各個 cloud service 的 serverless solution,提供一個讓使用者們簡單方便的 deploy & manatement 的工具。
因為我們使用的是 AWS Lambda,所以這邊只會介紹 Serverless Lambda 相關的用法。只好在你 project root 裡,寫好一個 serverless.yml
就可以讓 Serverless 幫你處理 build 、deploy 、remove 的動作。在執行 Serverless 的指令時,它會讀取 ~/.aws/credentials
的內容,也可以透過環境變數的方式將 credential 的內容 pass 給 Serverless。細節可以參考 doc
Installation - 透過 npm 安裝 serverless,可以選擇安裝在 system or local,這邊簡單介紹裝在 system 的指令
$ npm install -g serverless
Tips
Serverless 在執行後,會在 project 目錄產生 .serverless/
資料夾,其實砍掉的話也沒差,可以再執行 deploy
or remove
,因為 Serverless 是將 deploy 上去的資訊統統紀錄在 S3 裡面,至於說砍掉 .serverless/
後,如何找到同一個結果(因為 S3 的 serverless 目錄名稱會有 hash 的值),這邊就沒再深入研究了。
4. Serverless - Tesseract Lambda Layer
serverless.yml
service: tesseract-layer
frameworkVersion: ">=1.34.0 <2.0.0"provider:
name: aws
region: us-west-1layers:
tesseract:
path: layer
compatibleRuntimes:
- python3.6
- python3.7
- provider.region : 改成你的 AWS region
- layers.<layer-name>.path : local folder name,裡面的內容會整份打包上傳
執行以下指令,即可 deploy 至 AWS 上
$ serverless deploy
5. Serverless - pytesseract Lambda Function
python requirements.txt
Pillow==6.1.0
pytesseract==0.2.9
serverless.yml
service: my-captchaplugins:
- serverless-python-requirements
- serverless-pseudo-parametersprovider:
name: aws
runtime: python3.7
region: us-west-1
apiKeys:
- my-captcha-keycustom:
pythonRequirements:
dockerizePip: truefunctions:
tesseract-ocr:
handler: handler.lambda_handler
layers:
- arn:aws:lambda:#{AWS::Region}:#{AWS::AccountId}:layer:tesseract:1
events:
- http:
path: my-captcha
method: post
private: true
執行以下指令,即可 deploy 至 AWS 上
$ serverless deploy
在這邊用到兩個 Serverless plugin,安裝方式如下,雖然是透過 serverless 的指令執行,但是其實裝的就是 npm 的套件,安裝完後,會把這套件寫入project root 的 package.json
$ serverless plugin install -n serverless-python-requirements
$ serverless plugin install -n serverless-pseudo-parameters
- serverless-python-requirements : build python package from requirements.txt
- serverless-pseudo-parameters : serverless.yml 裡面出現的變數
#{xxx}
在執行時會被自動取代掉。(ex:#{AWS::AccountId}
#{AWS::Region}
),所以不用填入自己的 AWS region, AccountId ,在執行時會自動抓取
Python package
serverless-python-requirements
會自動讀取 requirements.txt
用 pip 安裝裡面指定的套件,由於 Pillow
會 build c extension .so
,所以需要將 dockerizePip
設成 true , Serverless 在執行時便會使用 Docker build pip package,否則就會在 Lambda 執行時看到 import error。
custom:
pythonRequirements:
dockerizePip: true
Lambda Function + API Gateway
當我們將 Lambda deploy 好後,必須掛上 AWS API Gateway,才能用 API 的方式執行 Lambda Function,因此我們在 serverless.yml 裡面需要加上 events http 的設定
provider:
apiKeys:
- my-captcha-keyfunctions:
tesseract-ocr:
events:
- http:
path: my-captcha # API path
method: post
private: true
這邊要注意到,我們設定 private
為 true,因為我們不希望 AWS API Gateway 的 API 任何人都可以隨便呼叫(預設為 public )。在設 private 為 true 後,要使用 API 的話,必須加上在 HTTP Header 加上 x-api-key
才行。而這把 key ,會在 Serverless deploy 時建出來,因此要注意 Serverless deploy 後的 output,key 會寫在裡面。要注意 output 也會有 API Gateway 的 endpoint URL path。(如果你錯過 output 的話,直接上 AWS Console,也是可以找到的)
Lambda Layer
functions:
tesseract-ocr:
layers:
- arn:aws:lambda:#{AWS::Region}:#{AWS::AccountId}:layer:tesseract:1
在 Lambda Function 要使用我們剛剛 deploy 的 Layer ,必須在 layers
裡輸入剛剛 deploy 的 tesseract layer 的 ARN ID,要注意最後面的 number 1在 Serverless deploy 後可能會改變。
Call Lambda API
在上面的步驟都完成後,可以至 AWS Lambda 頁面的 dashboard,應該可以看到 Serverless 已經幫你把 Function, Layer, API Gateway 都處理好了,接著就可以試著自己呼叫看看結果吧。
cURL -X POST -H "x-api-key: XXXXXX" https://XXXXX.execute-api.us-west-1.amazonaws.com/dev/my-captcha