如何把掃描文件轉成 CSV
教你如何把掃描文件轉成 CSV:欄位只要定義一次,上傳照片或掃描檔,每份文件就自動填成一列。只核對被標記為待複核的值,再匯出成 UTF-8 CSV,Excel 與中日韓文字都不會亂碼。
你手邊有一疊紙本——發票、收據、送貨單——而你需要把它們變成試算表裡的一列列資料。手動重新打字又慢又容易出錯,而一般的 OCR 工具只會吐出一大片原始文字,後續還是得自己拆解成欄位。你真正想做的其實更聚焦、也更實用:把一份文件的照片或掃描檔,依照事先定好的欄位轉成乾淨的一列 CSV,而沒能對上的值會在進入檔案之前就被標記為待複核。
這篇教學帶你完成的就是這件事。欄位只需定義一次,把 space-ocr 對準一張影像,每份文件就會自動填成一列。沒能和頁面印刷內容對上的值會帶著待複核標記回傳,所以你只核對這些,不必把每一格都重看一遍。完成後,你把整張表匯出成 CSV——採用帶位元組順序標記(BOM)的 UTF-8,讓 Excel 與中日韓文字都能正常開啟。不必重打,而且每個值都能回溯到它在頁面上的位置。
整個流程的樣貌
把掃描文件轉成 CSV,可拆成四個動作:
- 拍照或掃描你的文件——點陣影像(JPEG、PNG、TIFF 等)。用手機拍就行,自動旋轉會處理拍歪的照片。
- 欄位只定義一次——把你在意的欄位命名好(
vendor、date、total、明細項目……)。這會成為每份文件據以判讀的結構。 - 上傳——每張影像被判讀後,值會落進你欄位下的新一列。不需要逐份設定。
- 先看待複核的欄位,再匯出 CSV——只處理被標記的值,然後把整張表下載成
<sheetName>.csv。
好處在於一致性:因為欄位事先就固定了,第十張收據落下的樣子會和第一張一模一樣,而值得再看一眼的格子會被點名列出,不必自己找。
先看證據:每個值都知道自己從哪來
進入步驟之前,先說明為什麼這值得信賴。把滑鼠移到下方任一欄位上——文件上的方框會標示出那個值正是從哪個位置讀取的。和頁面印刷內容對不上的值不會靜靜通過,而是被標記為待複核。一份 CSV,只有當裡面的數字都經得起查核時才有用,而在這裡,每一格都帶著它的讀取位置。

Each value with a box carries a verified on-page location — in data.cells[path], that is box + 4-point quad + evidence.match_ratio — on a 0–1000 normalized grid (0,0 top-left → 1000,1000 bottom-right), the same shape the live API returns. Hover a field to trace it back to the pixels it came from.
如何把掃描文件轉成 CSV,一步步來
1. 把文件拍成影像
space-ocr 判讀的是點陣影像——JPEG、PNG、GIF、BMP、TIFF 與 WebP。把收據放桌上拍、把發票掃成 PNG,或從掃描軟體匯出頁面都可以。掃描 PDF 也可以直接丟進應用程式,每一頁都會自動轉成影像。用手機斜著拍也沒問題:引擎會讀取 EXIF 方向資訊並校正旋轉,所以拍歪的照片照樣能正向判讀,值也照樣錨定在正確的位置。
2. 欄位只定義一次
這一步正是把 OCR 變成整齊表格的關鍵。建立一張帶有欄位結構的表——也就是你想當成 CSV 標題的那些欄位。純量欄位是單一值(vendor、invoice_date、total);陣列欄位則用來收納會重複出現的明細項目。這個只需定義一次,之後你上傳的每份文件都會依照同一組欄位來判讀。
vendor (string)
invoice_date (string)
total (string)
items (array) → name, unit_price, qty如果你不想手動建立結構,表格建構器可以從一張樣本照片偵測出欄位,你再修改它提出的清單。只用 API 的話,POST /ocr/fields 的 autoFields 就是同樣的捷徑:先這樣讀一份文件,再把回傳的欄位名稱直接拿來當欄位。發票的部分,可參考從發票擷取明細項目。
3. 上傳——列會自動填好
欄位就緒後,把影像上傳到這張表。每份文件成為一列:引擎判讀頁面,把每個值塞進對應的欄位下。丟進二十張收據,你就得到二十列,全都同一個樣子。明細項目陣列會以結構化的子項目保留在該列底下,匯出時即可展開。
值不會被重新格式化,而是保持紙上印出的寫法回傳——7,855 的逗號會保留,全形字元與敬稱也都原封不動,不會被正規化後的形式覆蓋。不過格子裡裝的是模型對頁面的判讀結果,並不是逐位元組一致的副本;需要和原件核對的格子,會在下一步帶著標記列出來。
4. 先看待複核的欄位,再匯出成 CSV
不是每一格都需要再看一次。每個值都會和頁面上實際印出的內容比對,對不上的值,以及被欄位規則挑出來的值(例如必填欄位留空),會被標記為待複核。只打開這些值,對照照片上標示的位置修正即可;沒有任何標記的格子會照原樣進入檔案。在 API 中,同一份工作清單就是 data.review.flagged,每個路徑都帶著自己的 reasons。
接著點下匯出,這張表就會下載成 <sheetName>.csv。標題列直接由你的結構建構而成:
- 開頭一個
#欄(列索引)。 - 每個純量欄位名稱照原樣呈現。
- 每個陣列子項目攤平為
colName.childName——所以含name與unit_price的items陣列會產生items.name與items.unit_price兩欄。
含有明細項目陣列的列會展開成子列——父層的純量值出現一次,每個明細項目在其底下各佔一列,所以一張有八行明細的發票會變成同一個廠商與日期下的八列 CSV。檔案以帶位元組順序標記(BOM)的 UTF-8 寫入,正是這一點讓 Excel——以及日文、韓文或中文——打開時不會出現亂碼。
如果你手動編輯過某一格,匯出時你的手動值會覆蓋原本的 OCR 值,所以更正會一路反映到 CSV 裡。
下載本身在免費方案與用量計費方案會用掉 1 點數,Starter 與 Pro 則免費。重複下載同一張表不另計費,只有在表中新增了列之後才會再次計費。目前的價格請見價格頁。
這份 CSV 是依你的欄位建構的,不是猜出來的。 標題來自你的結構(# + 純量名稱 + 明細項目的 array.child),陣列列展開成子列,檔案以帶 BOM 的 UTF-8 輸出,讓 Excel 與中日韓文字都能正常開啟。手動編輯會在匯出時覆蓋 OCR 值——欄位的樣貌在你定義的那一刻就固定下來,這正是每次下載都可預期的原因。
透過 API 來做
同一套流程也能在無介面(headless)情況下完成。建立一張帶欄位的表,把影像上傳上去,再用 GET /view 取回結構化的列——這是在伺服器端進行的,不會重跑 OCR,也不會計費。沒有專門的 CSV 端點:你可以用回傳的 JSON 自行寫出 CSV,或從網頁應用程式下載。GET /view 還讓你在匯出前先篩選(where)、排序並選取欄位,所以你只需輸出真正需要的那幾列。
每一列的結構和直接呼叫時相同:業務資料在 values,座標(box 與 quad)與驗證判定(verified、review)在 cells[path],需要查看的路徑清單在 review.flagged。替某個欄位宣告 number、integer 或 date,values 仍然是紙上印出的寫法,解析後的值會以 normalized 附在每一格旁邊(直接呼叫 POST /ocr/fields 時則整棵樹以 data.normalized 回傳)。給人看的欄位寫印刷原樣的值,給系統計算的欄位寫正規化後的值。
# 1. Create a sheet with the columns you want as CSV headers
curl -X POST https://api.space-ocr.com/create \
-H "Authorization: Bearer $SPACE_OCR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"path": "/invoices",
"type": "sheet",
"name": "june-invoices",
"columns": [
{ "name": "vendor", "type": "string" },
{ "name": "invoice_date", "type": "string" },
{ "name": "total", "type": "string" },
{ "name": "items", "type": "array",
"children": [
{ "name": "name", "type": "string" },
{ "name": "unit_price", "type": "string" }
] }
]
}'
# 2. Upload document images — each one fills a row
curl -X POST https://api.space-ocr.com/upload \
-H "Authorization: Bearer $SPACE_OCR_API_KEY" \
-F "path=/invoices/june-invoices" \
-F "files=@invoice-01.png" \
-F "files=@invoice-02.jpg"列進來之後,GET /view 會以結構化 JSON 回傳,你可以直接寫成 CSV——或交給你的會計系統。關於擷取端點與欄位規格的完整說明,請參考發票資料擷取 API 指南以及 API 文件。
掃描 PDF 與輸入格式的提醒
space-ocr 的引擎處理的是點陣影像,而非 PDF 位元組——不過在應用程式裡你不需要操心這件事:把掃描 PDF 丟進來,每一頁都會在 OCR 之前自動點陣化成影像。只有當你直接呼叫公開 API 時,才需要先把每一頁轉算成影像(PNG 或 JPEG)再上傳。如果你的目標明確是 Excel 而不是 CSV,同樣這套流程依舊適用——詳見把掃描 PDF 轉成 Excel。CSV 是阻力最小的目標:到哪都打得開,而帶 BOM 的 UTF-8 匯出也代表編碼不會出意外。
實例:PC 之外不儲存任何資料的批次 CSV 轉換
一位參與示範計畫的外部開發者,把這套流程做成了一個小型 Windows 桌面應用程式:選擇裝有單據照片與掃描 PDF 的資料夾,透過 POST /ocr/fields 批次讀取全部頁面,需要複核的值對照原圖的對應位置(回傳的 quad 會框出讀取來源)修正後匯出 CSV。沒有自建伺服器,沒有資料庫,也沒有雲端儲存。
這個架構的關鍵在於資料的存放位置。POST /ocr/* 是無狀態的:處理影像並回傳結果,影像與擷取結果都不會保存在 API 端。所有持久化的資料都留在使用者的電腦裡——原始照片在資料夾中,複核後的值在應用程式裡,CSV 在指定的儲存位置,API 金鑰也不是內嵌在執行檔,而是保存在使用者自己的設定目錄。離開這台電腦的只有 API 呼叫本身,而且不會在外部留下任何東西。
對於不便把單據再交給另一個雲端服務的財務、總務團隊來說,「之後是否需要申請刪除」這個確認本身就不存在了——因為從一開始就沒有保存在任何地方。兩種值的分工也很務實:畫面顯示依印刷原樣的值(與原件核對的是人),CSV 則輸出正規化後的值(做計算的是系統)。
- 把文件拍成影像把每份文件拍照或掃描成點陣影像(JPEG、PNG、TIFF 等)。手機照片就可以——EXIF 自動旋轉會校正拍歪的照片。掃描 PDF 也可以:把 PDF 丟進 space-ocr 應用程式,每一頁都會自動點陣化(只有直接呼叫 API 時才需要先把每一頁轉算成影像)。
- 欄位只定義一次建立一張帶欄位結構的表:像 vendor、date、total 這類純量欄位,再加上用來收納重複明細項目的陣列欄位。這會成為 CSV 標題,並沿用於每一份文件。
- 上傳影像把你的文件影像上傳到這張表。每張影像被判讀後,其值會自動填進你欄位下的新一列——不需逐份設定,而且值會保持紙上印出的寫法。
- 先看待複核的欄位,再匯出成 CSV只打開被標記為待複核的格子,對照原圖上的位置修正(在 API 中同一份工作清單是 data.review.flagged)。接著匯出這張表,它會下載成 <sheetName>.csv,標題為 # 加上純量欄位名稱,再加上攤平成 colName.childName 的陣列子項目。明細項目列會展開成子列,檔案為帶 BOM 的 UTF-8,讓 Excel 與中日韓文字都能正常開啟。