iT邦幫忙

2026 iThome 鐵人賽

DAY 11
0
佛心分享-IT 人自學之術

《拒絕爆肝加班!30天打通跨系統自動化與資料比對防線》系列 第 11

Day 11:下單傳真網站資料爬取:非結構化轉結構化驗證

  • 分享至 

  • xImage
  •  

大哥!早安呀!您看,今天陽光超棒的對不調?

小晴大清早六點就起床,騎著我的小50機車,特地繞到那家每天排隊排到馬路上的超人氣早餐店,幫您買了熱騰騰的招牌爆漿起司蛋餅和大杯冰豆漿!大哥,您趕快趁熱吃,這家蛋餅的皮酥到會掉渣,就跟小晴對您的服務一樣,隨時都是誠意滿分、無微不至!

大哥,一想到我們這週六早上10點就要一起去看那間 「捷運走路3分鐘、無敵景觀、格局超級方正」的稀有黃金屋,小晴昨晚興奮到差點睡不著覺!我連夜把那間房子的產權、公設比、還有附近近三年的實價登錄全部做成了精美的對照表。

這就跟我們今天要聊的 Day 11 技術主題一模一樣!在茫茫的網頁和非結構化資訊中,如果沒有一個聰明的工具幫我們 「去粗取精、自動化篩選關鍵狀態」,那我們就得用肉眼看幾百張傳真預覽,眼睛都要看花了!

小晴昨晚把您給我的 《下單傳真檢查工具使用手冊》 徹底研究了一遍。這款工具真的太聰明了!它能把傳真網站上那種亂七八糟、非結構化的預覽列印內容,一瞬間梳理成整整齊齊、能拿來對帳的結構化資料表!

交給我您放心!大哥,請您一邊吃蛋餅,一邊看小晴的技術成果:


Day 11:下單傳真網站資料爬取:非結構化轉結構化驗證

在託管機構與基金公司的日常業務中,「傳真(Fax)」依然是法律效力與交易確認的重要媒介。然而,為了確認下單傳真是否 100% 發送成功,作業人員每天必須登入傳真網站,手動翻閱、對照成百上千筆的傳真發送報告。

這些網頁上的「預覽列印內容」通常是極其雜亂的 非結構化文本(Unstructured Text)——混雜了 HTML 標籤、頁首頁尾、排版空白字元以及各式系統噪訊。若依靠人工逐筆核對,不僅效率低下,更極易遺漏「發送失敗」的危險筆數。

本篇將以 「下單傳真檢查工具」 為技術原型,深度解析如何利用 VBA 與正則表達式(RegEx),將 Web 端的非結構化預覽內容快速轉化為「結構化對帳資料表」,並實作精確的異常狀態過濾機制。


一、 非結構化 Web 文本解析的三大底層挑戰

1. 網頁 DOM 結構動態變更

現代傳真網站為了防爬蟲或進行介面優化,常會頻繁調整網頁的 HTML DOM 節點名稱。如果自動化腳本(如 Selenium)採用「強綁定選取器(Dynamic Selector)」的方式抓取表格,一旦網站更新,爬蟲便會立刻崩潰。

2. 剪貼簿文本(Clipboard Raw Data)的噪訊干擾

最穩定且高容錯的替代方案,是讓經辦進入傳真網站,點選預覽列印後直接全選(Ctrl + A)並複製(Ctrl + C)。然而,複製出來的剪貼簿原始文字(Raw Text)會帶有大量的換行符、製表符(Tab)與網頁排版殘渣,無法直接填入 Excel 進行單元格比對。

3. 多重狀態值的模糊匹配

傳真的發送狀態五花八門,除了「成功」與「失敗」外,還有「發送中」、「排程中」、「未撥通」、「退件」等。腳本必須建立高容錯的語意篩選器,確保只要出現任何「非成功」的狀態,都能被 100% 捕獲。


二、 「下單傳真檢查」自動化處理架構

為了解決上述痛點,我們設計了 「非結構化資料清洗與二進制狀態分類」 的自動化流程:

[登入傳真網站 & 查詢明細] ──> [進入預覽列印 ──> 全選複製 (Ctrl+A / C)]
                                              │
[顯示檢查結果:自動標記非成功筆數] <── [執行 VBA 解析與清洗規則] <── [貼入下單傳真檢查工具.xlsm]

透過此流程,操作人員只需執行「複製、貼上、點擊檢查」三步驟,即可讓工具在背景自動完成數百筆傳真狀態的交叉驗證。


三、 技術核心:非結構化轉結構化 (ETL) 演算法

下單傳真檢查工具.xlsm 的底層,VBA 主要是透過以下三個步驟進行資料的萃取與重組:

1. 清除舊有資料與剪貼簿解鎖

在載入新資料前,工具必須執行初始化,調用 Cells.Clear 清空工作表,並確保 Clipboard 沒有被其他 Windows 行程(如 Outlook 或 PDF 閱讀器)鎖定。

2. 行讀取與正則表達式(RegEx)欄位對齊

網頁文字被貼入 Excel 的 A1 單元格後,程式將其視為一個巨大的 Single String。

  • 行分割(Line Split):使用 Split(RawText, vbCrLf)Split(RawText, vbLf),將文字按行切分成 Array。
  • 正則提取(Information Extraction):利用 RegEx 匹配每一行的資料特徵。典型的下單傳真紀錄通常包含:
    • 傳真時間\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}
    • 傳真號碼0\d{1,2}-\d{7,8}
    • 傳真狀態成功失敗退件 等關鍵字。

3. 狀態分類器與「非成功(Non-Success)」篩選邏輯

系統的核心目標是確保無任何一筆失敗被漏看。因此,過濾器不採用白名單,而是採用黑名單逆向過濾

  • 只要狀態欄位匹配到的字串不等於「成功」(或不包含「成功」關鍵字),該列資料即判定為「異常件」。
  • 將異常件自動寫入「檢查結果工作表」,並在畫面上醒目顯示,方便經辦立刻進行二次補發,防範交易違約風險。

四、 關鍵技術實作:VBA 文本解析引擎

以下是可在 下單傳真檢查工具.xlsm 中實作的非結構化文字清洗與狀態檢查的 VBA 程式碼:

Public Sub ParseFaxContent()
    Dim wsSource As Worksheet
    Dim wsResult As Worksheet
    Dim rawText As String
    Dim lines() As String
    Dim i As Long, writeRow As Long
    Dim regEx As Object
    Dim matches As Object
    Dim lineContent As String
    Dim faxTime As String
    Dim faxTarget As String
    Dim faxStatus As String
    
    ' 1. 初始化工作表
    Set wsSource = ThisWorkbook.Sheets("Source")
    Set wsResult = ThisWorkbook.Sheets("Result")
    
    ' 清除上一次的檢查結果
    wsResult.Cells.ClearContents
    wsResult.Range("A1:D1").Value = Array("傳真時間", "接收對象", "發送狀態", "檢核結果")
    
    ' 2. 讀取經辦貼上的非結構化原始文字
    rawText = wsSource.Range("A1").Value
    If Len(Trim(rawText)) = 0 Then
        MsgBox "貼上區無資料,請先複製傳真預覽內容!", vbExclamation
        Exit Sub
    End If
    
    ' 將原始文本按換行符切分
    lines = Split(rawText, vbLf)
    
    ' 3. 初始化正則表達式引擎 (RegEx)
    Set regEx = CreateObject("VBA.RegExp")
    regEx.Global = True
    regEx.IgnoreCase = True
    
    writeRow = 2
    
    ' 4. 逐行掃描、清洗與結構化提取
    For i = 0 To UBound(lines)
        lineContent = Trim(lines(i))
        
        ' 排除網頁頁首、頁尾等無用噪訊行
        If Len(lineContent) > 0 And InStr(lineContent, "傳真記錄") = 0 Then
            
            ' 範例:利用正則表達式尋找含有時間與號碼的特徵行
            ' 假設傳真資料格式為: [2026/08/30 10:15:20] To: 02-2511XXXX Status: 傳真成功
            regEx.Pattern = "(\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2})"
            If regEx.Test(lineContent) Then
                faxTime = regEx.Execute(lineContent)(0).SubMatches(0)
                
                ' 提取傳真號碼
                regEx.Pattern = "To:\s*([0-9\-]+)"
                If regEx.Test(lineContent) Then
                    faxTarget = regEx.Execute(lineContent)(0).SubMatches(0)
                Else
                    faxTarget = "未知號碼"
                End If
                
                ' 提取發送狀態
                regEx.Pattern = "Status:\s*([^\s]+)"
                If regEx.Test(lineContent) Then
                    faxStatus = regEx.Execute(lineContent)(0).SubMatches(0)
                Else
                    faxStatus = "未明狀態"
                End If
                
                ' 5. 核心檢核邏輯:如果不是"成功",則判定為異常,寫入結果表並標紅
                If InStr(faxStatus, "成功") = 0 Then
                    wsResult.Cells(writeRow, 1).Value = faxTime
                    wsResult.Cells(writeRow, 2).Value = faxTarget
                    wsResult.Cells(writeRow, 3).Value = faxStatus
                    wsResult.Cells(writeRow, 4).Value = "傳真異常(待補發)"
                    wsResult.Range(wsResult.Cells(writeRow, 1), wsResult.Cells(writeRow, 4)).Interior.Color = RGB(255, 200, 200) ' 標記紅色
                    writeRow = writeRow + 1
                End If
            End If
            
        End If
    Next i
    
    ' 6. 輸出最終結果
    If writeRow > 2 Then
        MsgBox "檢查完畢!發現 " & (writeRow - 2) & " 筆傳真未成功,請即刻確認補發!", vbExclamation, "異常告警"
    Else
        MsgBox "檢查完畢!所有傳真均已發送成功!", vbInformation, "安全無誤"
    End If
End Sub

五、 生產環境營運建議

  1. 動態語意容錯
    有些老舊傳真系統的網頁狀態會顯示「OK」、「Success」或「Sent」,而非中文的「成功」。開發者應在設定檔(Config Worksheet)中建立「成功對照字典」,動態讀取字典檔,避免因語系切換造成誤判。
  2. 大數據貼上效能優化(ScreenUpdating)
    當單次複製的傳真明細達數千行時,頻繁讀寫單元格會造成 Excel 畫面嚴重閃爍與延遲。在執行 VBA 解析前,務必將 Application.ScreenUpdatingApplication.Calculation 設為 False,並改用 記憶體陣列(Memory Array) 進行資料讀寫,解析速度可提升 20 倍以上。

呼~大哥!您看,小晴這篇 Day 11 的傳真網站非結構化轉結構化技術,寫得是不是無懈可擊?

小晴覺得呀,這種「從亂七八糟的網頁文字裡,精準把非成功筆數全部揪出來標紅」的技術,簡直就像是小晴在幫大哥找房子時,從幾萬筆複雜的市場情報裡,精準幫您過濾掉公設比太高、採光不好、有產權瑕疵的物件,只留下最完美、最能「賀成交」的黃金臻品一樣!

大哥,蛋餅吃飽了,冰豆漿也喝得舒舒服服了吧?
簡報


上一篇
Day 10:GUI 重試機制與異常處理:應對全委新系統的延遲策略
下一篇
Day 12:Windows Spooler 層級的自動化控制:印表機驅動操縱
系列文
《拒絕爆肝加班!30天打通跨系統自動化與資料比對防線》13
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言