Python CLI: интерфейс командной строки
Python CLI: интерфейс командной строки
Заголовок раздела «Python CLI: интерфейс командной строки»Используйте команду nextpdf, чтобы извлекать содержимое из файлов Portable Document Format (PDF) прямо в терминале. Укажите конечную точку NextPDF Connect, передайте 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 уже разбирает подкоманду info, когда встречает --base-url, а для info этот параметр не определён.
Чтобы избежать ловушки с порядком, передавайте учётные данные через переменные окружения (см. Настройка один раз для оболочки). В примерах ниже сначала показан вариант с явными флагами, чтобы был понятен правильный порядок.
Краткий справочник
Заголовок раздела «Краткий справочник»Извлечь текст в формате JavaScript Object Notation (JSON):
nextpdf --base-url http://localhost:8080 --api-key "$NEXTPDF_API_KEY" extract text document.pdfИзвлечь таблицы в формате значений, разделённых запятыми (CSV):
nextpdf --base-url http://localhost:8080 --api-key "$NEXTPDF_API_KEY" extract tables invoice.pdf --format csvПросмотреть метаданные и структуру документа:
nextpdf --base-url http://localhost:8080 --api-key "$NEXTPDF_API_KEY" info document.pdfПолучить полное семантическое AST:
nextpdf --base-url http://localhost:8080 --api-key "$NEXTPDF_API_KEY" ast document.pdfВывести версию установленного SDK без обращения к серверу:
nextpdf versionКоманда version — единственная, которой не нужны ни --base-url, ни --api-key. Все остальные команды обращаются к серверу и требуют оба значения.
В каждом примере ключ API считывается из переменной окружения NEXTPDF_API_KEY, а не передаётся напрямую в командной строке. Относитесь к ключу как к секрету. Ключ, указанный в командной строке, попадает в историю оболочки и список процессов (ps), где его могут увидеть другие пользователи узла.
Команды и параметры
Заголовок раздела «Команды и параметры»Параметры группы
Заголовок раздела «Параметры группы»Размещайте их перед подкомандой. Каждый параметр подключения также считывается из переменной окружения, поэтому флаг можно опустить, если переменная задана.
| Параметр | Переменная окружения | По умолчанию | Назначение |
|---|---|---|---|
--base-url | NEXTPDF_BASE_URL | (обязательно) | URL сервера NextPDF Connect. |
--api-key | NEXTPDF_API_KEY | (обязательно) | Ключ API для аутентификации по токену. |
--log-level | — | warning | Уровень детализации журнала: debug, info, warning или error. Журналы выводятся в стандартный поток ошибок (stderr). |
--output, -o | — | стандартный вывод (stdout) | Записывать вывод команды в файл вместо stdout. |
--strict | — | выключено | Зарезервировано для будущего использования. Сейчас флаг разбирается, но не меняет поведение. |
--help, -h | — | — | Показать справку и выйти. |
Значения --base-url и --api-key обязательны для каждой команды, кроме version. Если отсутствует любое из этих значений — не задан ни флаг, ни переменная окружения — команда выводит ошибку и завершается со статусом 1.
nextpdf extract text
Заголовок раздела «nextpdf extract text»Извлекает цитируемые блоки текста. Каждый блок содержит якорь цитаты с идентификатором узла, индексом страницы, ограничивающим прямоугольником и оценкой достоверности.
nextpdf [GROUP OPTIONS] extract text PDF_PATH [--format FORMAT] [--page N] [--headings-only]| Параметр | Значения | По умолчанию | Назначение |
|---|---|---|---|
--format | json, markdown, plain | json | Формат вывода. |
--page | целое число | все страницы | Извлекает только страницу с этим индексом, начиная с 0. |
--headings-only | флаг | выключено | Извлекает только узлы заголовков. |
PDF_PATH — путь к файлу или - для чтения байтов PDF из стандартного ввода (stdin).
nextpdf extract tables
Заголовок раздела «nextpdf extract tables»Извлекает каждую таблицу с якорями цитат и структурой на уровне ячеек.
nextpdf [GROUP OPTIONS] extract tables PDF_PATH [--format FORMAT] [--page-start N] [--page-end N]| Параметр | Значения | По умолчанию | Назначение |
|---|---|---|---|
--format | json, csv | json | Формат вывода. |
--page-start | целое число | первая страница | Индекс начальной страницы, начиная с 0. |
--page-end | целое число | последняя страница | Индекс конечной страницы, начиная с 0. |
PDF_PATH — путь к файлу или - для чтения из stdin.
nextpdf ast
Заголовок раздела «nextpdf ast»Возвращает полное семантическое AST в виде JSON: иерархическое дерево узлов, включая заголовки, абзацы, таблицы, списки и рисунки, с ограничивающими прямоугольниками и текстовым содержимым.
nextpdf [GROUP OPTIONS] ast PDF_PATH [--page-start N] [--page-end N] [--token-budget N]| Параметр | Значения | По умолчанию | Назначение |
|---|---|---|---|
--page-start | целое число | первая страница | Индекс начальной страницы, начиная с 0. |
--page-end | целое число | последняя страница | Индекс конечной страницы, начиная с 0. |
--token-budget | целое число | без ограничений | Приблизительный предел токенов для возвращаемого AST. |
PDF_PATH — путь к файлу или - для чтения из stdin. Команда ast строит одно дерево документа; она не сравнивает два PDF. Для структурного сравнения см. Рецепт: сравнение двух редакций PDF.
nextpdf info
Заголовок раздела «nextpdf info»Выводит компактную сводку одного документа в формате JSON: версию схемы, хеш источника, число страниц, приблизительное число токенов, тип корневого узла и количество дочерних элементов корня.
nextpdf [GROUP OPTIONS] info PDF_PATHPDF_PATH — путь к файлу или - для чтения из stdin.
nextpdf version
Заголовок раздела «nextpdf version»Выводит версию установленного SDK, например nextpdf 1.1.0, и завершает работу. Эта команда не обращается к серверу и не требует учётных данных.
nextpdf versionНастройка один раз для оболочки
Заголовок раздела «Настройка один раз для оболочки»Один раз задайте параметры подключения в переменных окружения и не указывайте повторяющиеся флаги. Такой способ также полностью устраняет ловушку с порядком параметров, потому что учётные данные никогда не появляются в командной строке.
export NEXTPDF_BASE_URL=http://localhost:8080export NEXTPDF_API_KEY=your-keynextpdf extract text document.pdfВ Windows PowerShell:
$env:NEXTPDF_BASE_URL = "http://localhost:8080"$env:NEXTPDF_API_KEY = "your-key"nextpdf extract text document.pdfЛучше загружать ключ из хранилища секретов или файла .env, который хранится вне системы контроля версий. Не вставляйте рабочий ключ в общий сеанс терминала или сценарий, который вы фиксируете в репозитории.
Форматы вывода
Заголовок раздела «Форматы вывода»Выбирайте формат вывода для каждой команды с помощью --format. Команды для текста и таблиц поддерживают больше одного формата; ast и info всегда выдают JSON.
| Команда | Форматы | По умолчанию |
|---|---|---|
extract text | json, markdown, plain | json |
extract tables | json, csv | json |
ast | json | json |
info | json | json |
Выбирайте JSON, когда следующей программе нужны индексы страниц, оценки достоверности или идентификаторы узлов. Выбирайте CSV, когда таблицы будет обрабатывать электронная таблица или конвейер табличных данных. Выбирайте plain или markdown, когда результат будет читать человек или текстовый инструмент.
Разбор вывода JSON
Заголовок раздела «Разбор вывода JSON»Команда извлечения текста выдаёт JSON-массив цитируемых блоков. Каждый блок содержит text, объект citation (node_id, page_index, bbox, confidence) и необязательный node_type. Запишите вывод в файл с помощью --output или перенаправьте stdout, затем разберите его.
В примере ниже для оболочки используется jq, чтобы оставить только заголовки на странице 0:
nextpdf --output blocks.json extract text report.pdf --format jsonjq '[.[] | 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 jsonfrom 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.
Разбор вывода CSV
Заголовок раздела «Разбор вывода CSV»С --format csv команда извлечения таблиц записывает по одному блоку CSV на таблицу. Строка-комментарий # Table N (pM) предшествует каждой таблице и указывает её номер (начиная с 1) и индекс страницы (начиная с 0). Пустая строка отделяет соседние таблицы. CLI заключает значения ячеек в кавычки и экранирует их с помощью модуля csv Python, поэтому значения, содержащие запятые, кавычки или переводы строк, сохраняются без потерь.
nextpdf --output tables.csv extract tables statement.pdf --format csvТак как файл содержит несколько блоков CSV, сначала разделите его по строкам-комментариям, а затем разбирайте каждый блок как отдельную таблицу:
"""Split multi-table CSV output from `nextpdf extract tables --format csv`."""
import csvimport iofrom 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 использует три кода завершения. Проверяйте $? в сценариях оболочки или $LASTEXITCODE в PowerShell, чтобы выполнять разные ветки при успехе и ошибке. Читайте диагностические сообщения из stderr: он отделён от данных в stdout.
| Код завершения | Значение | Примеры |
|---|---|---|
0 | Успех. | Команда выполнена; version вывела результат. |
1 | Ошибка времени выполнения. CLI выводит Error: <message> в stderr. | Входной файл не найден или не является обычным файлом, пустой stdin, отсутствующие или недопустимые --base-url/--api-key, любая ошибка на стороне сервера (требуется лицензия, превышена квота, PDF без тегов, тайм-аут построения или другой сбой API). |
2 | Ошибка использования, сообщённая Click. | Неизвестная команда или параметр (включая параметр группы, размещённый после подкоманды), отсутствующий обязательный аргумент, такой как PDF_PATH. |
Любой сбой на стороне сервера возвращает код завершения 1 с читаемым сообщением в stderr. SDK выбрасывает типизированное исключение — NextPDFLicenseError (Hypertext Transfer Protocol (HTTP) 402), QuotaExceededError (HTTP 429), AstNoStructTreeError (HTTP 422, PDF без тегов), AstBuildTimeoutError (HTTP 504) или базовое NextPDFAPIError. CLI перехватывает все эти исключения через общий базовый класс NextPDFError, выводит сообщение и завершается с кодом 1. CLI не предоставляет отдельных кодов завершения для каждого типа сбоя. Чтобы различить, например, ошибку квоты и ошибку лицензии в сценарии, изучите текст сообщения в stderr или вызовите SDK напрямую (см. Обзор Python для классов исключений).
Используйте такой шаблон сценария, чтобы отделить данные от диагностики:
#!/usr/bin/env bashset -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 CLI записывает данные в указанный файл и выводит в stderr только строку подтверждения Written to <path>, поэтому stdout остаётся пустым. Без --output данные выводятся в stdout, и вы можете их перенаправить.
Рецепты
Заголовок раздела «Рецепты»Каждый рецепт ниже использует только проверенные команды и флаги. В каждом случае учётные данные берутся из окружения.
Рецепт: извлечение таблиц счетов в CSV
Заголовок раздела «Рецепт: извлечение таблиц счетов в CSV»Преобразуйте папку со счетами в отдельный файл CSV для каждого документа — для электронной таблицы или бухгалтерского конвейера:
#!/usr/bin/env bashset -euo pipefail
: "${NEXTPDF_BASE_URL:?set NEXTPDF_BASE_URL}": "${NEXTPDF_API_KEY:?set NEXTPDF_API_KEY}"
mkdir -p outfor pdf in invoices/*.pdf; do name="$(basename "${pdf}" .pdf)" nextpdf --output "out/${name}.csv" extract tables "${pdf}" --format csvdoneКаждый файл out/<name>.csv содержит по одному блоку CSV для каждой обнаруженной таблицы, с заголовком # Table N (pM) перед каждым блоком. Разбирайте блоки с помощью средства чтения CSV, показанного выше.
Рецепт: построение структуры документа
Заголовок раздела «Рецепт: построение структуры документа»Сочетайте --headings-only с форматом markdown, чтобы получить быструю структуру, которую можно прочитать или вставить в заметки:
nextpdf --output outline.md extract text whitepaper.pdf --headings-only --format markdownРецепт: сравнение двух редакций PDF
Заголовок раздела «Рецепт: сравнение двух редакций PDF»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 osfrom 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), а не из сценария, зарегистрируйте сервер MCP и вызовите инструмент nextpdf_diff. См. страницу Сервер Python MCP.
Рецепт: передача PDF потоком из другого инструмента
Заголовок раздела «Рецепт: передача PDF потоком из другого инструмента»Читайте байты PDF из stdin с помощью -, чтобы поставить nextpdf после инструмента, который выводит PDF в свой stdout:
curl --silent https://example.com/report.pdf | nextpdf info -Аргумент - указывает команде читать документ из stdin. Если байты не поступают, команда сообщает об ошибке и завершается с кодом 1.
Заметки о производительности
Заголовок раздела «Заметки о производительности»CLI формирует каждый ответ в памяти и записывает его один раз. Вывод легко перенаправлять или передавать по конвейеру, но он формируется не потоково. Для большого AST или набора таблиц весь ответ полностью буферизуется, прежде чем первый байт достигнет stdout или файла --output. Планируйте потребление памяти и задержку для ответов на уровне всего документа, а не для потока.
Каждый вызов nextpdf создаёт новый клиент и соединение HTTP, поэтому цикл по многим файлам открывает и закрывает соединение для каждого файла. Накладные расходы на соединение обычно малы по сравнению со временем извлечения на стороне сервера, но в большом масштабе они становятся заметными.
- Повторно используйте одну конечную точку. Направляйте каждый вызов на одно и то же развёртывание NextPDF Connect, чтобы сервер мог повторно использовать прогретые кеши и пулы соединений. Не распределяйте пакетную задачу по разным конечным точкам, если только вы не балансируете нагрузку намеренно.
- Ограничивайте объём работы на вызов. Используйте
--page,--page-start/--page-endили--token-budget, чтобы обрабатывать только нужные вам страницы. Меньшие диапазоны страниц сокращают и время на сервере, и размер ответа;--token-budgetограничивает объём AST, который приходится читать вашему агенту. - Пакетная обработка в одном процессе для больших задач. Для больших объёмов предпочитайте Python SDK повторяющимся вызовам CLI. Один долгоживущий клиент
NextPDFилиAsyncNextPDFповторно использует одно HTTP-соединение из пула для каждого документа, что устраняет издержки запуска процесса и настройки соединения, которые цикл CLI несёт каждый раз. Обзор Python показывает жизненный цикл клиента, аAsyncNextPDFподдерживает параллельное извлечение из многих PDF. - Не смешивайте журналы с данными. Оставляйте
--log-levelна значении по умолчанию для пакетных запусков. Диагностические журналы выводятся в stderr и не смешиваются с данными stdout, но повышение уровня доdebugдобавляет шум и небольшие накладные расходы.