經過前面的 todo list 專案練習後, 我已大致熟悉 agy 的用法了, 本篇要先來解決一個實務問題. 我之前手刻的市圖爬蟲程式在 6/18 早上突然失靈了, 檢視市圖網站才知道登入頁面多了一個數字驗證碼輸入欄位, 需判讀數字輸入正確號碼才能登入成功.
爬蟲停擺兩周了, 如果還是要手刻來解決恐怕曠日廢時, 這次要改用 agy 來升版.
本系列之前的文章參考 :
關於市圖爬蟲程式參考 :
1. 建立專案目錄並啟動 agy :
首先在 projects 下建立專案目錄 :
PS D:\antigravity_cli\projects> mkdir ksml-clawler
PS D:\antigravity_cli\projects> cd ksml-clawler
然後將之前的爬蟲程式 ksml_lib_13.py 與從市圖網站抓下來的登入頁面截圖 jpg 檔 ksml_login.jpg 複製到專案目錄底下 :
PS D:\antigravity_cli\projects\ksml-crawler> dir
目錄: D:\antigravity_cli\projects\ksml-crawler
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2026/6/5 上午 12:43 8858 ksml_lib_13.py (舊版爬蟲)
-a---- 2026/6/27 上午 01:13 240936 ksml_login.jpg (新登入頁面截圖)
接著啟動 agy :
PS D:\antigravity_cli\projects\ksml-clawler> agy
輸入下列提示詞 :
這個現有的圖書館爬蟲程式因為網站最近在登入頁面加入了「數字圖形驗證碼」,導致舊的 Selenium 程式無法順利登入。
我已經把現有的爬蟲程式 `ksml_lib_13.py` 與登入頁面的實體截圖 `ksml_login.jpg` 放在當前目錄下了。
專案目標:
- 目標網址:https://webpacx.ksml.edu.tw/personal/
- 核心任務:只修改「登入功能」,使其能夠成功處理數字圖形驗證碼,其餘資料擷取邏輯保持不變。
重構方向提示:
在 Python 中引入輕量級的 OCR 套件(例如 pytesseract 或 ddddocr),自動對驗證碼圖片進行局部截圖與辨識後自動輸入。
如果 OCR 辨識失敗導致登入錯誤,請讓程式具備自動重新整理驗證碼、重新截圖辨識並重試(Retry)最多 3 次的機制。
💡 【關鍵:帳密讀取與 Cron Job 相容性需求】
- 我原本的程式是在 Cron Job 中透過命令列參數帶入帳密執行的,格式為:`python ksml_lib_13.py <username> <password>`。
- 為了不破壞現有的排程自動化,重構後的登入機制必須採用命令列參數設計:
檢查是否有命令列參數(`sys.argv`),若有則直接使用排程帶入的帳密。否則跳出程式.
請先不要修改程式碼。
1. 請先閱讀 `ksml_lib_13.py` 了解現有登入邏輯,並結合 `ksml_login.jpg` 截圖與目標網址,分析驗證碼的 HTML 結構與更新機制。
2. 為我產出一個重構的 Implementation Plan (實作計畫),並說明你需要安裝哪些額外的 Python 套件或工具(如 OCR 相關依賴)。
3. 專案成果為新版爬蟲程式 `ksml_lib_14.py`
Claude 規劃結果如下 :
▸ Thought for 5s
The user wants me to first analyze the existing crawler program and the login pa...
好的,我先來閱讀現有程式碼與截圖,然後分析目標網站的登入結構。
● Read(D:/antigravity_cli/projects/ksml-crawler/ksml_lib_13.py)
● Read(D:/antigravity_cli/projects/ksml-crawler/ksml_login.jpg) (ctrl+o to expand)
截圖已清楚看到驗證碼樣式,接著我去實際抓取目標網站的 HTML 結構,了解驗證碼 <img>
元素與刷新機制。
● ReadURL(https://webpacx.ksml.edu.tw/personal/)
● Read(C:/Users/tony1/.gemini/antigravi...tem_generated/steps/7/content.md) (ctrl+o to expand)
這個 HTML
是高度壓縮的,難以直接找到驗證碼結構。讓我用搜索的方式在原始碼中尋找驗證碼相關關鍵字。
● WebSearch(webpacx.ksml.edu.tw captcha img src HTML structure login)
● Search(Captcha keyword search in HTML) (ctrl+o to expand)
網站的 HTML
是壓縮過的,我已從截圖中收集到足夠的視覺資訊了。現在我整合所有分析,產出重構計畫。
● Create(C:/Users/tony1/.gemini/antigrav...5b6a6fe1/implementation_plan.md) (ctrl+o to expand)
以下是完整的分析報告與實作計畫:
──────
## 📋 分析摘要
### 現有登入邏輯( ksml_lib_13.py )
步驟 | 程式碼 | 說明
---------------------------|-----------------------------------|---------------------------
1 | find_element(By.ID, 'logxinid') | 填帳號
2 | find_element(By.ID, 'pincode') | 填密碼
3 | .btn_grp → input → .click() | 點登入按鈕
❌ | 跳過驗證碼 | 導致失敗
### 驗證碼特性(從截圖分析)
從 ksml_login.jpg 可觀察到:
• 類型:4-5 位純數字,彩色交錯(紫/藍/橘)
• 背景:白色,干擾少 → OCR 友善
• 旁邊有刷新按鈕(🔄) → 可程式化刷新重試
──────
## 🔧 實作計畫
詳細計畫請見 → implementation_plan.md
### 核心決策
#### 1. OCR 套件選型:選用 ddddocr ✅
pip install ddddocr
• 優點:專為中文圖形驗證碼訓練、純 Python、無外部系統依賴
• 比較: pytesseract 需額外安裝 Tesseract 可執行檔,在 Cron Job 環境更麻煩
#### 2. 新版登入流程(含 3 次重試)
填帳號 → 填密碼 → [最多3次迴圈]
→ 截取驗證碼圖片(Selenium element.screenshot_as_png)
→ ddddocr 辨識 → 填入驗證碼欄位
→ 點登入 → 判斷成功?
✓ 找到 .redblock → 登入成功,繼續爬取
✗ 找不到 → 點 🔄 刷新 → 重試
→ 3次仍失敗 → return (None, None)
#### 3. 命令列相容性:完全不動 ✅
原有 sys.argv[1] / sys.argv[2] 的 Cron Job 格式完全保留:
python ksml_lib_14.py <username> <password>
──────
## ⚠️ 實作前的必要確認步驟
由於網站 HTML 是壓縮的,在正式撰寫 ksml_lib_14.py 前,需要確認以下 3 個元素的確切
ID/selector:
元素 | 預測可能的 ID | 確認方法
-----------------------------|----------------------------|--------------------------------
驗證碼圖片 <img> | captchaImg 、 vcode_img | F12 / browser.page_source
驗證碼輸入框 <input> | vcode 、 captcha | F12 / placeholder 含「驗證碼」
刷新按鈕 | refreshCaptcha | F12 / onclick 含 refresh
──────
## ✅ 確認後即可開始撰寫 ksml_lib_14.py
請問您是否要:
1. 直接授權我產出 ksml_lib_14.py (我會在程式碼中加入自動偵測元素的邏輯)?
2. 或先用瀏覽器 F12 確認驗證碼元素的 ID 後再告訴我?
Claude 要求我確認驗證碼圖片, 輸入框, Refresh 按鈕的 ID, 我用 F12 去查網頁原始碼, 發現只有輸入框元件有 ID, 其它兩個元件沒有 ID :
> 驗證碼相關的三個元件如下 :
<input name="captcha" id="captcha" type="text" placeholder="請輸入驗證碼,並區分大小寫" value="">
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIwAAAAyCAIAAAABYqRsAAAK/0lEQVR42u2beVTTVxbH/WOmZ452nHaO03amdWqrVj0erfuG1W7TVqtDrdXO6LR2mWkVN1y
... (略) ... ZCeQGuR1Bf0pWWwE+70pQPJME6H6Dik/4GGQ8Ih4Q2HhEPCGw4JbzgkHBLecEh4wyHhkPCGQ8Ih4Q2HhDcc0v9v+y/alGmPzd5YpQAAAABJRU5ErkJggmh5dzE3ODMwMDU1NDYxODllYg==" class="captcha" alt="驗證碼圖片如無法讀取可以移到右邊替代方案" style="background: none;">
<button type="button" class="btn reflashbtn">更換驗證碼</button>
其中只有驗證碼輸入框有 ID, 你可能需要用 class 或 xpath 來定位.
Claude 規劃如下 :
▸ Thought for 1m 4s
The user has provided the HTML for the three captcha elements:
完美!三個元素都確認了:
元素 | Selector
---------------------------------------------|---------------------------------------------
驗證碼輸入框 | By.ID, 'captcha'
驗證碼圖片 | By.CSS_SELECTOR, 'img.captcha'
刷新按鈕 | By.CLASS_NAME, 'reflashbtn'
還有一個重要發現:驗證碼圖片的 src 是 data:image/png;base64,...
內嵌格式,這讓我可以直接從屬性取得 base64 bytes 餵給 ddddocr
,比截圖更精確、更快!現在直接產出 ksml_lib_14.py :
● Create(D:/antigravity_cli/projects/ksml-crawler/ksml_lib_14.py) (ctrl+o to expand)
ksml_lib_14.py 已建立完成。以下是重點說明:
──────
## 🔑 關鍵實作細節
### 驗證碼圖片處理(最乾淨的方式)
由於 src 是 data:image/png;base64,... 內嵌格式,不需要任何 HTTP 請求,直接解碼即可:
img_src = captcha_img.get_attribute('src')
b64_data = img_src.split(',', 1)[1] # 去掉 "data:image/png;base64," 前綴
img_bytes = base64.b64decode(b64_data) # 得到 PNG bytes
result = ocr.classification(img_bytes) # ddddocr 辨識
### Implicit Wait 衝突處理
登入成功判斷用 WebDriverWait(5秒) 而非 find_element ,為避免與 implicitly_wait(60)
衝突,採用暫時停用再恢復的方式:
browser.implicitly_wait(0) # 暫停,讓 WebDriverWait 的 5 秒生效
try:
WebDriverWait(browser, 5).until(...)
finally:
browser.implicitly_wait(60) # 無論成敗都恢復
### 確認的三個 Selector
用途 | Selector
---------------------------------------------|---------------------------------------------
驗證碼圖片 | By.CSS_SELECTOR, 'img.captcha'
驗證碼輸入框 | By.ID, 'captcha'
刷新按鈕 | By.CLASS_NAME, 'reflashbtn'
──────
## 📦 部署前安裝套件
在執行 Cron Job 的主機上安裝:
pip install ddddocr
──────
## ✅ 與舊版相容性
• Cron Job 指令 完全不變: python ksml_lib_14.py <username> <password>
• 借閱/預約資料擷取邏輯一行未動
• 舊版 ksml_lib_13.py 保留不受影響
Cluade 已經完成重構實作, 由於爬蟲程式是在樹莓派執行, 先將 ksml_lib_14.py 傳送到樹莓派上, 然後安裝 ddddocr 套件, 但是此套件之依賴套件有些無法在 Pi 3 Bulleye 的 Python 3.9.2 上安裝, 所以要求 Claude 改用替代方案解決, 因為市圖驗證碼是簡單的數字圖片, 只要用經典的開源文字識別套件 Tesseract 就可以達到很高識別精確度 :
> 你在此專案使用的 ddddocr 套件無法在目標主機樹莓派 Pi 3B Bulleye 的 Python 3.9.2 安裝執行,
請改用經典的 Tesseract OCR 實作
The user wants to replace ddddocr with Tesseract OCR (pytesseract) because ddddo...
▸ Thought for 30s
了解,Raspberry Pi 3B Bullseye 的 ARM 架構對 ddddocr 的 ONNX 依賴支援不佳。改用
pytesseract + Pillow 搭配影像預處理是在樹莓派上最穩定的方案。
● Read(D:/antigravity_cli/projects/ksml-crawler/ksml_lib_14.py) (ctrl+o to expand)
確認了需要修改的範圍,現在一次完成所有 OCR 相關的替換:
● Edit(D:/antigravity_cli/projects/ksml-crawler/ksml_lib_14.py) (ctrl+o to expand)
修改完成,來驗證最終的 solve_captcha 與 login_with_captcha 函式完整正確:
● Read(D:/antigravity_cli/projects/ksml-crawler/ksml_lib_14.py) (ctrl+o to expand)
第 107 行有一個多餘的空行,順手清掉:
● Edit(D:/antigravity_cli/projects/ksml-crawler/ksml_lib_14.py) (ctrl+o to expand)
ksml_lib_14.py 已更新完成。
──────
## 📝 變更摘要
### 替換內容
項目 | 舊版(ddddocr) | 新版(pytesseract)
------------|---------------------------------|--------------------------------------------
imports | import ddddocr | import io , import pytesseract , from
| | PIL import Image
OCR 物件 | ocr = | 不需要,pytesseract 為靜態呼叫
| ddddocr.DdddOcr(show_ad=False) |
辨識呼叫 | ocr.classification(img_bytes) | pytesseract.image_to_string(img,
| | config=...)
影像預處理 | 無 | 灰階 → 二值化 → 放大3倍
### solve_captcha() 的影像預處理邏輯
彩色 PNG → 灰階 (L mode) → 二值化 threshold=200 → 放大 3× (LANCZOS)
• threshold=200:彩色文字(紫/藍/橘)在灰階下通常 < 200,白色背景 ≥ 200,切分乾淨
• 放大 3×:原始驗證碼圖片較小,Tesseract 對低解析度圖片準確率差,放大後顯著改善
• 白名單 0-9 :排除 Tesseract 誤判為字母的情況
• re.sub(r'[^0-9]', '', raw) :最後一道過濾,清除 Tesseract 殘留的換行或空白
──────
## 🔧 樹莓派部署指令
# 1. 安裝系統套件(只需一次)
sudo apt-get install tesseract-ocr
# 2. 安裝 Python 套件
pip install pytesseract Pillow
# 3. 執行(與舊版完全相同)
python ksml_lib_14.py <帳號> <密碼>
這樣就完成實作了.
2. 驗收專案成果 :
安裝底層 OCR 套件 :
pi@kaopi3:~ $ sudo apt-get install tesseract-ocr
正在讀取套件清單... 完成
正在重建相依關係... 完成
正在讀取狀態資料... 完成
The following packages were automatically installed and are no longer required:
chromium-codecs-ffmpeg-extra freeglut3 libfuse2 libglu1-mesa libmikmod3
libportmidi0 libqt5designer5 libqt5help5 libqt5test5 librtimulib-dev
librtimulib-utils librtimulib7 libsdl-mixer1.2 libsdl-ttf2.0-0 libturbojpeg0
python3-kms++ python3-libcamera python3-opengl python3-piexif python3-prctl
python3-pyqt5 python3-pyqt5.sip python3-rtimulib python3-v4l2
Use 'sudo apt autoremove' to remove them.
下列的額外套件將被安裝:
liblept5 libtesseract4 tesseract-ocr-eng tesseract-ocr-osd
下列【新】套件將會被安裝:
liblept5 libtesseract4 tesseract-ocr tesseract-ocr-eng tesseract-ocr-osd
升級 0 個,新安裝 5 個,移除 0 個,有 15 個未被升級。
需要下載 6,859 kB 的套件檔。
此操作完成之後,會多佔用 21.6 MB 的磁碟空間。
是否繼續進行 [Y/n]? [Y/n] y
下載:1 http://raspbian.raspberrypi.org/raspbian bullseye/main armhf liblept5 armhf 1.79.0-1.1+deb11u1 [899 kB]
下載:2 http://raspbian.raspberrypi.org/raspbian bullseye/main armhf libtesseract4 armhf 4.1.1-2.1+rpi1 [1,082 kB]
下載:3 http://raspbian.raspberrypi.org/raspbian bullseye/main armhf tesseract-ocr-eng all 1:4.00~git30-7274cfa-1.1 [1,592 kB]
下載:4 http://raspbian.raspberrypi.org/raspbian bullseye/main armhf tesseract-ocr-osd all 1:4.00~git30-7274cfa-1.1 [2,991 kB]
下載:5 http://raspbian.raspberrypi.org/raspbian bullseye/main armhf tesseract-ocr armhf 4.1.1-2.1+rpi1 [295 kB]
取得 6,859 kB 用了 15s (468 kB/s)
選取了原先未選的套件 liblept5:armhf。
(讀取資料庫 ... 目前共安裝了 106135 個檔案和目錄。)
正在準備解包 .../liblept5_1.79.0-1.1+deb11u1_armhf.deb……
Unpacking liblept5:armhf (1.79.0-1.1+deb11u1) ...
選取了原先未選的套件 libtesseract4:armhf。
正在準備解包 .../libtesseract4_4.1.1-2.1+rpi1_armhf.deb……
Unpacking libtesseract4:armhf (4.1.1-2.1+rpi1) ...
選取了原先未選的套件 tesseract-ocr-eng。
正在準備解包 .../tesseract-ocr-eng_1%3a4.00~git30-7274cfa-1.1_all.deb……
Unpacking tesseract-ocr-eng (1:4.00~git30-7274cfa-1.1) ...
選取了原先未選的套件 tesseract-ocr-osd。
正在準備解包 .../tesseract-ocr-osd_1%3a4.00~git30-7274cfa-1.1_all.deb……
Unpacking tesseract-ocr-osd (1:4.00~git30-7274cfa-1.1) ...
選取了原先未選的套件 tesseract-ocr。
正在準備解包 .../tesseract-ocr_4.1.1-2.1+rpi1_armhf.deb……
Unpacking tesseract-ocr (4.1.1-2.1+rpi1) ...
設定 tesseract-ocr-eng (1:4.00~git30-7274cfa-1.1) ...
設定 liblept5:armhf (1.79.0-1.1+deb11u1) ...
設定 libtesseract4:armhf (4.1.1-2.1+rpi1) ...
設定 tesseract-ocr-osd (1:4.00~git30-7274cfa-1.1) ...
設定 tesseract-ocr (4.1.1-2.1+rpi1) ...
執行 man-db (2.9.4-2) 的觸發程式……
執行 libc-bin (2.31-13+rpt2+rpi1+deb11u13) 的觸發程式……
安裝 Pillow 與 pytesseract 套件 :
pi@kaopi3:~ $ pip install pytesseract Pillow
Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
Collecting pytesseract
Downloading https://www.piwheels.org/simple/pytesseract/pytesseract-0.3.13-py3-none-any.whl (14 kB)
Requirement already satisfied: Pillow in /usr/lib/python3/dist-packages (8.1.2)
Requirement already satisfied: packaging>=21.3 in ./.local/lib/python3.9/site-packages (from pytesseract) (26.2)
Installing collected packages: pytesseract
Successfully installed pytesseract-0.3.13
pi@kaopi3:~ $ python ksml_lib_14.py xyz 123456
主機 : kaopi3
[嘗試 1/3] 驗證碼辨識結果: 65495
登入成功(第 1 次嘗試)
擷取借閱紀錄 ... OK
擷取預約紀錄 ... OK
資源已釋放
產生借書到期摘要 ... OK
產生預約書摘要 ... OK
{'message': 'xyz 的資料已更新', 'status': 'success'}
執行時間:86.35315299034119
也有驗證兩次才過關的 :
pi@kaopi3:~ $ python ksml_lib_14.py abc 123456
主機 : kaopi3
[嘗試 1/3] 驗證碼辨識結果: 301
[嘗試 1/3] 登入失敗,準備重試...
[嘗試 2/3] 驗證碼辨識結果: 75530
登入成功(第 2 次嘗試)
擷取借閱紀錄 ... OK
擷取預約紀錄 ... OK
資源已釋放
產生借書到期摘要 ... OK
產生預約書摘要 ... OK
{'message': 'abc 的資料已更新', 'status': 'success'}
執行時間:155.63533067703247
檢查 render.com 上的爬蟲結果已更新 :
哇, 原本要折騰一個禮拜以上的工作半天就搞定了.
3. 上傳 GitHub :
在 repo 根倉庫 antigravity_cli 下, 用 git add . 指令追蹤新加入的專案 :
PS D:\antigravity_cli> git add .
warning: in the working copy of 'projects/ksml-crawler/ksml_lib_14.py', LF will be replaced by CRLF the next time Git touches it
用 git commit 提交變更 :
PS D:\antigravity_cli> git commit -m "feat: add ksml-crawler"
[main c7e4816] feat: add ksml-crawler
3 files changed, 581 insertions(+)
create mode 100644 projects/ksml-crawler/ksml_lib_13.py
create mode 100644 projects/ksml-crawler/ksml_lib_14.py
create mode 100644 projects/ksml-crawler/ksml_login.jpg
最後用 git push 推送專案至 repo :
PS D:\antigravity_cli> git push origin main
Enumerating objects: 9, done.
Counting objects: 100% (9/9), done.
Delta compression using up to 16 threads
Compressing objects: 100% (7/7), done.
Writing objects: 100% (7/7), 210.16 KiB | 8.41 MiB/s, done.
Total 7 (delta 3), reused 0 (delta 0), pack-reused 0 (from 0)
remote: Resolving deltas: 100% (3/3), completed with 2 local objects.
To https://github.com/tony1966/antigravity_cli.git
601e3ee..c7e4816 main -> main
完成後檢視 GitHub 已有此專案 :
檢視 token 用量餘額 :





沒有留言 :
張貼留言