跳到內容

Python CLI 命令列工具

nextpdf 命令會在終端機執行 PDF 擷取。你可以將它指向某個 NextPDF Connect endpoint,傳入一份 PDF,取得結構化輸出——附引用的文字、表格、完整語意抽象語法樹(AST),或一份中繼資料摘要——再輸出到標準輸出(stdout)或寫入檔案。

nextpdf 命令是一個 Click 命令群組。連線與工作階段選項——--base-url--api-key--log-level--output/-o,以及 --strict——定義在群組層級,因此你要把它們放在子命令之前。子命令及其自身選項(例如 --format--page)則放在之後

nextpdf [GROUP OPTIONS] COMMAND [SUBCOMMAND] PDF_PATH [COMMAND OPTIONS]

把群組選項放在子命令之後會失敗。舉例來說,nextpdf info document.pdf --base-url ... 會回報 Error: No such option: --base-url 並以狀態碼 2 結束,因為 Click 剖析到 --base-url 時,已經進入 info 子命令,而該子命令並未定義這個選項。

避開這個順序陷阱最清楚的做法,是透過環境變數提供認證(見每個 shell 設定一次一節)。下面的範例先以明確旗標呈現,讓正確的順序一目了然。

以 JSON 擷取文字:

Terminal window
nextpdf --base-url http://localhost:8080 --api-key "$NEXTPDF_API_KEY" extract text document.pdf

以逗號分隔值(CSV)格式擷取表格:

Terminal window
nextpdf --base-url http://localhost:8080 --api-key "$NEXTPDF_API_KEY" extract tables invoice.pdf --format csv

檢視文件中繼資料與結構:

Terminal window
nextpdf --base-url http://localhost:8080 --api-key "$NEXTPDF_API_KEY" info document.pdf

取得完整語意 AST:

Terminal window
nextpdf --base-url http://localhost:8080 --api-key "$NEXTPDF_API_KEY" ast document.pdf

印出已安裝的 SDK 版本,且不需連線伺服器:

Terminal window
nextpdf version

version 命令是唯一既不需要 --base-url、也不需要 --api-key 的命令。其他所有命令都會連線到伺服器,並且必須同時提供這兩項。

所有範例都從 NEXTPDF_API_KEY 環境變數讀取 API 金鑰,而非直接寫在命令列上。請把金鑰當成機密看待。若直接寫在命令列上,金鑰會出現在你的 shell 歷史記錄中,也會出現在主機上其他使用者可見的處理程序清單(ps)中。

你要把這些選項放在子命令之前。每個連線選項也會讀取環境變數;如果變數已設定,你可以省略旗標。

選項環境變數預設值用途
--base-urlNEXTPDF_BASE_URL(必填)NextPDF Connect 伺服器 URL。
--api-keyNEXTPDF_API_KEY(必填)用於 bearer 驗證的 API 金鑰。
--log-levelwarning記錄詳細程度:debuginfowarningerror。記錄會輸出到標準錯誤(stderr)。
--output-o標準輸出(stdout)將命令輸出寫入檔案,而非 stdout。
--strict關閉保留供未來使用。這個旗標目前可被剖析,但不會改變任何行為。
--help-h顯示說明並結束。

除了 version 以外,每個命令都必須提供 --base-url--api-key 的值。如果任一項缺漏——也就是既沒有旗標,也沒有環境變數——命令會印出錯誤並以狀態碼 1 結束。

擷取附引用的文字區塊。每個區塊都帶有一個引用錨點(節點識別碼、頁面索引、定界框,以及一個信心分數)。

nextpdf [GROUP OPTIONS] extract text PDF_PATH [--format FORMAT] [--page N] [--headings-only]
選項預設值用途
--formatjsonmarkdownplainjson輸出格式。
--page整數所有頁面只擷取這個以 0 為基底的頁面索引。
--headings-only旗標關閉只擷取標題節點。

PDF_PATH 是一個檔案路徑,或用 - 從 stdin 讀取 PDF 位元組。

擷取每一張表格,並附帶引用錨點與儲存格層級結構。

nextpdf [GROUP OPTIONS] extract tables PDF_PATH [--format FORMAT] [--page-start N] [--page-end N]
選項預設值用途
--formatjsoncsvjson輸出格式。
--page-start整數第一頁起始頁面索引(以 0 為基底)。
--page-end整數最後一頁結束頁面索引(以 0 為基底)。

PDF_PATH 是一個檔案路徑,或用 - 從 stdin 讀取。

以 JSON 回傳完整的語意 AST:這是一棵由各種節點(標題、內文段、表格、清單、圖表)組成的階層式樹狀結構,並帶有定界框與文字內容。

nextpdf [GROUP OPTIONS] ast PDF_PATH [--page-start N] [--page-end N] [--token-budget N]
選項預設值用途
--page-start整數第一頁起始頁面索引(以 0 為基底)。
--page-end整數最後一頁結束頁面索引(以 0 為基底)。
--token-budget整數無上限回傳 AST 的概略 token 上限。

PDF_PATH 是一個檔案路徑,或用 - 從 stdin 讀取。ast 命令會產生單一文件樹;它不會比較兩份 PDF。若要進行結構化比對,請見 範例:比對兩個 PDF 版本一節。

印出單一文件的精簡 JSON 摘要:schema 版本、來源雜湊、頁數、估計 token 數、根節點型別,以及根層級子項數量。

nextpdf [GROUP OPTIONS] info PDF_PATH

PDF_PATH 是一個檔案路徑,或用 - 從 stdin 讀取。

印出已安裝的 SDK 版本(例如 nextpdf 1.1.0)並結束。這個命令不會連線到任何伺服器,也不需要任何認證。

nextpdf version

把連線選項以環境變數形式設定一次,便能省略重複的旗標。這種做法也能完全避開選項順序陷阱,因為認證完全不會出現在命令列上。

Terminal window
export NEXTPDF_BASE_URL=http://localhost:8080
export NEXTPDF_API_KEY=your-key
nextpdf extract text document.pdf

在 Windows PowerShell 上:

Terminal window
$env:NEXTPDF_BASE_URL = "http://localhost:8080"
$env:NEXTPDF_API_KEY = "your-key"
nextpdf extract text document.pdf

建議從機密儲存區,或從一個已排除於版本控制之外的 .env 檔案載入金鑰。不要把正式環境的金鑰貼進共用的終端機工作階段,或貼進你會提交的指令碼。

你可以用 --format 為每個命令選擇輸出格式。text 與 table 命令支援多種格式;astinfo 則一律輸出 JSON。

命令格式預設值
extract textjsonmarkdownplainjson
extract tablesjsoncsvjson
astjsonjson
infojsonjson

當下游程式需要頁面索引、信心分數或節點識別碼時,選擇 JSON。當試算表或表格式管線要消費這些表格時,選擇 CSV。當結果要由人或純文字工具閱讀時,選擇 plainmarkdown 文字。

text 命令會輸出一個由附引用區塊組成的 JSON 陣列。每個區塊都有 text、一個 citation 物件(node_idpage_indexbboxconfidence),以及一個選用的 node_type。用 --output(或重新導向 stdout)把輸出送到檔案,然後再剖析它。

以下 shell 範例使用 jq,只保留第 0 頁的標題:

Terminal window
nextpdf --output blocks.json extract text report.pdf --format json
jq '[.[] | select(.citation.page_index == 0 and .node_type == "heading") | .text]' blocks.json

同樣的資料也能在 Python 中順利剖析。CLI 會寫出一個 JSON 陣列,因此你可以用標準函式庫載入它,並讀取其中有型別的欄位:

"""Parse cited text blocks emitted by `nextpdf extract text --format json`."""
import json
from pathlib import Path
def load_headings(blocks_path: Path) -> list[str]:
"""Return the text of every heading block on page 0.
Args:
blocks_path: Path to the JSON file written by `nextpdf extract text`.
Returns:
The text of each heading-type block whose citation is on page 0.
"""
raw = blocks_path.read_text(encoding="utf-8")
blocks: list[dict[str, object]] = json.loads(raw)
headings: list[str] = []
for block in blocks:
citation = block["citation"]
if block.get("node_type") == "heading" and citation["page_index"] == 0:
headings.append(str(block["text"]))
return headings
if __name__ == "__main__":
for heading in load_headings(Path("blocks.json")):
print(heading)

當你需要的是經過驗證、有型別的模型,而非原始字典時,請直接呼叫 SDK,而不要剖析 CLI 輸出。請見 Python 總覽一節,以了解 NextPDF 用戶端及其 CitedTextBlock 回傳型別。

加上 --format csv 時,table 命令會為每一張表格寫出一個 CSV 區塊。每張表格前都有一行註解 # Table N (pM),標示其以 1 為基底的表格編號與以 0 為基底的頁面索引。連續表格之間以一行空白行分隔。CLI 會用 Python 的 csv 模組對儲存格值加引號與跳脫,所以含有逗號、引號或換行的值都能安全往返。

Terminal window
nextpdf --output tables.csv extract tables statement.pdf --format csv

由於這個檔案包含多個 CSV 區塊,在你把每個區塊當成獨立表格剖析之前,先依註解行切分:

"""Split multi-table CSV output from `nextpdf extract tables --format csv`."""
import csv
import io
from pathlib import Path
def read_tables(csv_path: Path) -> list[list[list[str]]]:
"""Parse the multi-block CSV file into a list of tables.
Each table is a list of rows; each row is a list of cell strings.
The leading `# Table N (pM)` comment row is dropped from every table.
Args:
csv_path: Path to the file written by `nextpdf extract tables`.
Returns:
One parsed table per `# Table` block in the file.
"""
text = csv_path.read_text(encoding="utf-8")
tables: list[list[list[str]]] = []
current: list[str] = []
for line in text.splitlines(keepends=True):
if line.startswith("# Table ") and current:
tables.append(_parse_block(current))
current = []
current.append(line)
if current:
tables.append(_parse_block(current))
return tables
def _parse_block(lines: list[str]) -> list[list[str]]:
"""Parse one CSV block, discarding its leading comment row."""
reader = csv.reader(io.StringIO("".join(lines)))
rows = [row for row in reader if row]
return rows[1:] if rows and rows[0] and rows[0][0].startswith("# Table ") else rows
if __name__ == "__main__":
for index, table in enumerate(read_tables(Path("tables.csv")), start=1):
print(f"table {index}: {len(table)} rows")

CLI 使用三種結束碼。在 shell 指令碼中檢查 $?(或在 PowerShell 中檢查 $LASTEXITCODE),依成功或失敗分支處理,並從 stderr 讀取診斷訊息——stderr 會與 stdout 上的資料保持分開。

結束碼意義範例
0成功。命令已完成;version 已印出。
1執行階段錯誤。CLI 會把 Error: <message> 印到 stderr。找不到輸入檔案或輸入檔案不是一般檔案、stdin 為空、缺漏或無效的 --base-url/--api-key、任何伺服器端錯誤(需要授權、超出配額、未標記的 PDF、建構逾時,或其他 API 失敗)。
2使用方式錯誤,由 Click 回報。未知的命令或選項(包含放在子命令之後的群組選項)、缺漏必要引數(例如 PDF_PATH)。

每個伺服器端失敗都會以結束碼 1 呈現,並在 stderr 上附帶一則可供人閱讀的訊息。SDK 會擲出一個有型別的例外——NextPDFLicenseError(HTTP 402)、QuotaExceededError(HTTP 429)、AstNoStructTreeError(HTTP 422,未標記的 PDF)、AstBuildTimeoutError(HTTP 504),或基底的 NextPDFAPIError。CLI 會在它們共同的 NextPDFError 基底之下捕捉所有這些例外、印出訊息,並以 1 結束。CLI 不會為每種失敗類型提供不同的結束碼。舉例來說,若要在指令碼中區分配額錯誤與授權錯誤,請檢視 stderr 上的訊息文字,或直接呼叫 SDK(例外類別請見 Python 總覽一節)。

以下是一種把資料與診斷訊息分開的指令碼模式:

#!/usr/bin/env bash
set -euo pipefail
# Credentials come from the environment, not the command line.
: "${NEXTPDF_BASE_URL:?set NEXTPDF_BASE_URL}"
: "${NEXTPDF_API_KEY:?set NEXTPDF_API_KEY}"
if nextpdf --output contract.ast.json ast contract.pdf; then
echo "AST written to contract.ast.json"
else
status=$?
echo "nextpdf failed with exit code ${status}" >&2
exit "${status}"
fi

請注意,--output 會把資料寫入指定的檔案,並且只把確認行 Written to <path> 印到 stderr,所以 stdout 會保持空白。不加 --output 時,資料會送到 stdout,而你可以重新導向它。

以下每則範例都只使用經過驗證的命令與旗標。每個情況下,認證都來自環境變數。

把整個資料夾的發票轉成每份文件一個 CSV 檔案,供試算表或會計管線使用:

#!/usr/bin/env bash
set -euo pipefail
: "${NEXTPDF_BASE_URL:?set NEXTPDF_BASE_URL}"
: "${NEXTPDF_API_KEY:?set NEXTPDF_API_KEY}"
mkdir -p out
for pdf in invoices/*.pdf; do
name="$(basename "${pdf}" .pdf)"
nextpdf --output "out/${name}.csv" extract tables "${pdf}" --format csv
done

每個 out/<name>.csv 都會為每一張偵測到的表格保存一個 CSV 區塊,且每個區塊前都有一個 # Table N (pM) 標頭。用上面示範的 CSV 讀取器剖析這些區塊。

--headings-onlymarkdown 格式結合,產生一份可以閱讀或貼進筆記的快速大綱:

Terminal window
nextpdf --output outline.md extract text whitepaper.pdf --headings-only --format markdown

CLI 的 ast 命令會回傳單一文件樹;它沒有 diff 子命令。結構化比對位於 SDK 中的 client.ast.get_ast_diff(...),以及 Model Context Protocol(MCP)伺服器中的 nextpdf_diff 工具。透過 SDK 執行這個比對:

"""Compare two PDF revisions structurally with the NextPDF SDK.
The API key is read from the environment, never hard-coded.
"""
import os
from pathlib import Path
from nextpdf import NextPDF
def diff_revisions(original: Path, modified: Path) -> None:
"""Print a structural diff summary between two PDF revisions.
Args:
original: Path to the earlier PDF revision.
modified: Path to the later PDF revision.
"""
base_url = os.environ["NEXTPDF_BASE_URL"]
api_key = os.environ["NEXTPDF_API_KEY"]
client = NextPDF(base_url=base_url, api_key=api_key)
result = client.ast.get_ast_diff(
original.read_bytes(),
modified.read_bytes(),
)
summary = result.summary
print(f"added: {summary.added_node_count}")
print(f"removed: {summary.removed_node_count}")
print(f"changed: {summary.changed_node_count}")
for entry in result.diff:
preview = entry.text_preview or ""
print(f" {entry.type:<8} {entry.node_type:<12} p{entry.page_index} {preview}")
if __name__ == "__main__":
diff_revisions(Path("contract-v1.pdf"), Path("contract-v2.pdf"))

若要從 AI Agent(代理)而非指令碼執行同樣的比對,請註冊 MCP 伺服器並呼叫 nextpdf_diff 工具。請見 Python MCP 伺服器頁面。

- 從 stdin 讀取 PDF 位元組,便能將 nextpdf 串接在某個會將 PDF 輸出到 stdout 的工具之後:

Terminal window
curl --silent https://example.com/report.pdf | nextpdf info -

這個 - 引數會告訴命令從 stdin 讀取文件。如果沒有任何位元組傳入,命令會回報錯誤並以 1 結束。

CLI 會在記憶體中建構每個回應,再一次性寫出,所以重新導向或管線輸出都很直接,但輸出並非以漸進方式產生。在第一個位元組到達 stdout 或 --output 檔案之前,龐大的 AST 或表格集合會先完整緩衝。請以整份文件的回應來規劃記憶體與延遲,而非以串流為前提。

每次 nextpdf 呼叫都會建立全新的用戶端與 HTTP 連線,所以對許多檔案進行迴圈時,會逐檔開啟與關閉一條連線。相較於伺服器端的擷取時間,這個連線成本通常很小,但在大規模時它確實是實際的額外負擔。

  • 重複使用同一個 endpoint。 把每次呼叫都指向同一個 NextPDF Connect 部署,讓伺服器能重複使用已預熱的快取與連線池。除非你刻意做負載平衡,否則避免把一個批次分散到多個 endpoint。
  • 限制每次呼叫的工作量。--page--page-start/--page-end,或 --token-budget 只處理你需要的頁面。較小的頁面範圍能同時減少伺服器時間與回應大小;--token-budget 則會限制你的 agent 必須讀取的 AST 量。
  • 大型工作就在單一處理程序中批次處理。 對於高量批次,請優先使用 Python SDK,而非重複的 CLI 呼叫。單一長期存活的 NextPDF(或 AsyncNextPDF)用戶端會在每份文件之間重複使用同一條池化的 HTTP 連線,省去 CLI 迴圈每次都要付出的逐處理程序啟動與連線建立成本。Python 總覽展示了用戶端的生命週期,而 AsyncNextPDF 則支援跨多份 PDF 的並行擷取。
  • 讓記錄遠離資料路徑。 批次執行時,把 --log-level 維持在預設值。診斷記錄會輸出到 stderr,不會汙染 stdout 資料,但把層級提高到 debug 會增加雜訊與少許額外負擔。