Skip to content
LlamaParse 文档版本 跟随上游 源快照 cd8c8f95 更新于 2026-10-16

本教程演示如何在开启专门的图表解析的情况下解析 PDF,从含图表的那页抽出表格数据,并用 pandas 做基础的数据分析。我们沿用《2024 执行摘要》PDF,即解析 PDF 并理解输出 所用的同一份;它的第三页含有一张 Parse 能转成结构化数据的图表。

1. 准备

把 API key 设成环境变量,SDK 会自动读取:

终端窗口

export LLAMA_CLOUD_API_KEY="llx-..."

安装 SDK 并构造一个 client。本例用 pandas 分析解析出的表格,因此 Python 标签页会一并安装它。

  • Python
  • TypeScript
  • Go
  • Java
  • CLI

终端窗口

pip install "llama-cloud>=2.8" pandas
from llama_cloud import LlamaCloud

client = LlamaCloud()  # reads LLAMA_CLOUD_API_KEY from the environment

终端窗口

npm install @llamaindex/llama-cloud
import LlamaCloud from '@llamaindex/llama-cloud';
import fs from 'fs';

const client = new LlamaCloud(); // reads LLAMA_CLOUD_API_KEY from the environment

终端窗口

go get github.com/run-llama/llama-parse-go
import llamacloud "github.com/run-llama/llama-parse-go"

client := llamacloud.NewClient() // reads LLAMA_CLOUD_API_KEY from the environment
implementation("ai.llamaindex:llama-cloud:1.3.0")
import ai.llamaindex.llamacloud.client.LlamaCloudClient;
import ai.llamaindex.llamacloud.client.okhttp.LlamaCloudOkHttpClient;

// reads LLAMA_CLOUD_API_KEY from the environment
LlamaCloudClient client = LlamaCloudOkHttpClient.fromEnv();

终端窗口

go install github.com/run-llama/llama-parse-cli/cmd/llp@latest

llp 会从环境里读取 LLAMA_CLOUD_API_KEY(也可用 --api-key 传入)。

后面几步的分析用到 pandas(仅 Python)—— 每种语言都能解析这份图表 PDF 并取出表格;只有 DataFrame 那部分是 Python 专有。

2. 开启专门的图表解析

专门的图表解析 会让 Parse 以更高保真度抽取 chart 与 graph 的数据。通过 processing_options 开启它,并请求 items 视图,这样就能拿到逐页的结构化表格(以及图形)。

我们解析同一份执行摘要 PDF 并请求 items,以便从第 3 页取出表格 —— 那页包含下面这张图:

示例图表

在 Python 与 TypeScript 里,expand 是传给解析调用的参数。而在 Go、Java 与 CLI 里,expand 是取结果时的查询参数,因此那几种做法是先创建任务、轮询到终态,再请求 items 视图。

下载这份报告:

终端窗口

curl -fL -o executive-summary-2024.pdf https://fiscal.treasury.gov/system/files/files/reports-statements/financial-report/2024/executive-summary-2024.pdf
  • Python
  • TypeScript
  • Go
  • Java
  • CLI
# Upload the file
file = client.files.create(file="./executive-summary-2024.pdf", purpose="parse")

# Parse with specialized chart parsing, and request the items view
result = client.parsing.parse(
    file_id=file.id,
    tier="agentic_plus",
    version="latest",
    processing_options={"specialized_chart_parsing": "agentic_plus"},
    expand=["items"],
)
// Upload the file
const file = await client.files.create({
  file: fs.createReadStream('./executive-summary-2024.pdf'),
  purpose: 'parse',
});

// Parse with specialized chart parsing, and request the items view
const result = await client.parsing.parse({
  file_id: file.id,
  tier: 'agentic_plus',
  version: 'latest',
  processing_options: { specialized_chart_parsing: 'agentic_plus' },
  expand: ['items'],
});
// Upload the file
f, err := os.Open("./executive-summary-2024.pdf")
if err != nil {
  log.Fatal(err)
}
defer f.Close()

file, err := client.Files.New(ctx, llamacloud.FileNewParams{File: f, Purpose: "parse"})
if err != nil {
  log.Fatal(err)
}

// Parse with specialized chart parsing (expand is a GET parameter in Go)
job, err := client.Parsing.New(ctx, llamacloud.ParsingNewParams{
  FileID:  llamacloud.String(file.ID),
  Tier:    llamacloud.ParsingNewParamsTierAgenticPlus,
  Version: llamacloud.ParsingNewParamsVersionLatest,
  ProcessingOptions: llamacloud.ParsingNewParamsProcessingOptions{
    SpecializedChartParsing: "agentic_plus",
  },
})
if err != nil {
  log.Fatal(err)
}

// Poll until the job reaches a terminal status, then request the items view
getParams := llamacloud.ParsingGetParams{Expand: []string{"items"}}
result, err := client.Parsing.Get(ctx, job.ID, getParams)
if err != nil {
  log.Fatal(err)
}
for result.Job.Status != "COMPLETED" && result.Job.Status != "FAILED" && result.Job.Status != "CANCELLED" {
  time.Sleep(2 * time.Second)
  result, err = client.Parsing.Get(ctx, job.ID, getParams)
  if err != nil {
    log.Fatal(err)
  }
}
if result.Job.Status != "COMPLETED" {
  log.Fatalf("parse ended as %s", result.Job.Status)
}
// Upload the file
FileCreateResponse file = client.files().create(FileCreateParams.builder()
        .file(Paths.get("./executive-summary-2024.pdf"))
        .purpose("parse")
        .build());

// Parse with specialized chart parsing (expand is a query parameter in Java)
ParsingCreateResponse job = client.parsing().create(ParsingCreateParams.builder()
        .fileId(file.id())
        .tier(ParsingCreateParams.Tier.AGENTIC_PLUS)
        .version(ParsingCreateParams.Version.LATEST)
        .processingOptions(ParsingCreateParams.ProcessingOptions.builder()
                .specializedChartParsing(
                        ParsingCreateParams.ProcessingOptions.SpecializedChartParsing.AGENTIC_PLUS)
                .build())
        .build());

// Poll until the job reaches a terminal status, then request the items view
ParsingGetParams getParams = ParsingGetParams.builder()
        .jobId(job.id())
        .addExpand("items")
        .build();

ParsingGetResponse result = client.parsing().get(getParams);
while (!result.job().status().equals(ParsingGetResponse.Job.Status.COMPLETED)
        && !result.job().status().equals(ParsingGetResponse.Job.Status.FAILED)
        && !result.job().status().equals(ParsingGetResponse.Job.Status.CANCELLED)) {
    Thread.sleep(2000);
    result = client.parsing().get(getParams);
}
if (!result.job().status().equals(ParsingGetResponse.Job.Status.COMPLETED)) {
    throw new RuntimeException("parse ended as " + result.job().status());
}

终端窗口

# Upload the file
FILE_ID=$(llp files create \
  --file ./executive-summary-2024.pdf \
  --purpose parse | jq -r '.id')

# Parse with specialized chart parsing
JOB_ID=$(llp parsing create \
  --file-id "$FILE_ID" \
  --tier agentic_plus \
  --version latest \
  --processing-options.specialized-chart-parsing agentic_plus \
  | jq -r '.id')

# Poll until the job reaches a terminal status
while true; do
  STATUS=$(llp parsing get --job-id "$JOB_ID" | jq -er '.job.status') || break
  case "$STATUS" in COMPLETED|FAILED|CANCELLED) break ;; esac
  sleep 2
done

3. 取第 3 页的表格数据

PDF 的第三页(在 items 树里索引为 2)含有一张图表。开启图表解析后,Parse 通常会把图表的数据表示成 items 树里的一个 table。我们收集该页的第一张表,并用它的 rows 做后续分析。

  • Python
  • TypeScript
  • Go
  • Java
  • CLI
page_three = result.items.pages[2]  # third page (0-indexed)

tables = [item for item in page_three.items if getattr(item, "type", None) == "table"]
if not tables:
    raise ValueError("No table found on page 3. Try the agentic_plus tier.")

rows = tables[0].rows
print(f"Chart table has {len(rows)} rows")
const pageThree = result.items.pages[2]; // third page (0-indexed)

let rows;
for (const item of pageThree.items) {
  if ('type' in item && item.type === 'table' && 'rows' in item) {
    rows = item.rows;
    break;
  }
}
if (!rows) {
  throw new Error('No table found on page 3. Try the agentic_plus tier.');
}
console.log(`Chart table has ${rows.length} rows`);
page := result.Items.Pages[2] // third page (0-indexed)

var rows [][]*llamacloud.TableItemRowUnion
for _, item := range page.Items {
  if item.Type == "table" {
    rows = item.Rows
    break
  }
}
if rows == nil {
  log.Fatal("No table found on page 3. Try the agentic_plus tier.")
}
fmt.Printf("Chart table has %d rows\n", len(rows))
ParsingGetResponse.Items.Page page = result.items().get().pages().get(2); // third page (0-indexed)
if (!page.isStructuredResult()) {
    throw new RuntimeException("No table found on page 3. Try the agentic_plus tier.");
}
ParsingGetResponse.Items.Page.StructuredResultPage pageThree = page.asStructuredResult();

var rows = pageThree.items().stream()
        .filter(ParsingGetResponse.Items.Page.StructuredResultPage.Item::isTable)
        .findFirst()
        .orElseThrow(() -> new RuntimeException("No table found on page 3. Try the agentic_plus tier."))
        .asTable()
        .rows();

System.out.println("Chart table has " + rows.size() + " rows");

终端窗口

# Pull the rows of the first table on page 3 (index 2)
llp parsing get --job-id "$JOB_ID" --expand items \
  | jq -r 'if .job.status == "COMPLETED" then .items.pages[2].items | map(select(.type == "table"))[0].rows
    else "Parse job failed: \(.job.error_message // .)" end'

4. 把财年图表载入 pandas

下面的分析使用 Python + pandas。这一页的图表是一张分组柱状图,展示 2020–2024 各财年的 Budget Deficit(预算赤字)与 Net Operating Cost(净运营成本),单位均为十亿美元。我们把它的表格整理成一个干净的时间序列 DataFrame:

import pandas as pd

# First row as column names, rest as data
header = rows[0]
df = pd.DataFrame(rows[1:], columns=header)

money_cols = [
    "Budget Deficit (Billions of Dollars)",
    "Net Operating Cost (Billions of Dollars)",
]

df["Fiscal Year"] = df["Fiscal Year"].astype(int)

print("DataFrame:")
print(df)
DataFrame:
   Fiscal Year Budget Deficit (Billions of Dollars)  \
0         2020                             $3,131.9
1         2021                             $2,775.6
2         2022                             $1,375.5
3         2023                             $1,695.2
4         2024                             $1,832.8

  Net Operating Cost (Billions of Dollars)
0                                 $3,841.4
1                                 $3,094.9
2                                 $4,171.0
3                                 $3,417.2
4                                 $2,425.0

5. 分析赤字与净运营成本的差异

数据整理干净后,我们就能复现图表文字部分描述的那几层关键关系。

1. 两个序列的逐年的变化

df["Deficit YoY Change"] = df["Budget Deficit (Billions of Dollars)"].diff()
df["Net Operating Cost YoY Change"] = df["Net Operating Cost (Billions of Dollars)"].diff()

print(df[["Fiscal Year",
          "Budget Deficit (Billions of Dollars)",
          "Net Operating Cost (Billions of Dollars)",
          "Deficit YoY Change",
          "Net Operating Cost YoY Change"]])
   Fiscal Year  Budget Deficit (Billions of Dollars)  \
0         2020                                3131.9
1         2021                                2775.6
2         2022                                1375.5
3         2023                                1695.2
4         2024                                1832.8

   Net Operating Cost (Billions of Dollars)  Deficit YoY Change  \
0                                    3841.4                 NaN
1                                    3094.9              -356.3
2                                    4171.0             -1400.1
3                                    3417.2               319.7
4                                    2425.0               137.6

   Net Operating Cost YoY Change
0                            NaN
1                         -746.5
2                         1076.1
3                         -753.8

这会凸显出例如 2022 年净运营成本的急剧上升,以及 2023–2024 的回落。

2. 净运营成本与预算赤字之间的差值

df["Gap (Net Operating Cost - Deficit)"] = (
    df["Net Operating Cost (Billions of Dollars)"]
    - df["Budget Deficit (Billions of Dollars)"]
)

print("\nGap between Net Operating Cost and Budget Deficit (billions):")
print(df[["Fiscal Year", "Gap (Net Operating Cost - Deficit)"]])

print("\nYear with largest gap:")
print(df.loc[df["Gap (Net Operating Cost - Deficit)"].idxmax()])

print("\nYear with smallest gap:")
print(df.loc[df["Gap (Net Operating Cost - Deficit)"].idxmin()])
Gap between Net Operating Cost and Budget Deficit (billions):
   Fiscal Year  Gap (Net Operating Cost - Deficit)
0         2020                               709.5
1         2021                               319.3
2         2022                              2795.5
3         2023                              1722.0
4         2024                               592.2

Year with largest gap:
Fiscal Year                                 2022.0
Budget Deficit (Billions of Dollars)        1375.5
Net Operating Cost (Billions of Dollars)    4171.0
Deficit YoY Change                         -1400.1
Net Operating Cost YoY Change               1076.1
Gap (Net Operating Cost - Deficit)          2795.5
Name: 2, dtype: float64

Year with smallest gap:
Fiscal Year                                 2021.0
Budget Deficit (Billions of Dollars)        2775.6
Net Operating Cost (Billions of Dollars)    3094.9
Deficit YoY Change                          -356.3
Net Operating Cost YoY Change               -746.5
Gap (Net Operating Cost - Deficit)           319.3
Name: 1, dtype: float64

这会复现那段叙述:2022 年两个指标的分歧最大,而到了 2024 年差距已明显收窄。

3. 快速可视化(可选)

ax = df.plot(
    x="Fiscal Year",
    y=[
        "Budget Deficit (Billions of Dollars)",
        "Net Operating Cost (Billions of Dollars)",
    ],
    kind="bar",
    title="U.S. Budget Deficit & Net Operating Cost (Billions of Dollars)",
)
ax.set_ylabel("Billions of dollars")

这张柱状图与 PDF 里的 Chart 1 高度一致,但如今背后是一个 DataFrame,你可以继续切片、聚合或喂给下游分析。

pandas 绘图

总结

  • PDF 里有图表想变成结构化数据时,用专门的图表解析(processing_options.specialized_chart_parsing:"agentic" 或 "agentic_plus")。
  • 在 expand 里请求 items,以拿到逐页的表格(与图形)。
  • 从含图表的那页(这里是第 3 页)取出 表格行,用 rows 搭一个 pandas DataFrame,再按需做汇总、绘图或筛选。

更多选项(例如 efficient 与 agentic 的差别)见专门的图表解析。

BytesRouter 是社区翻译站点,所有译文仅供参考,一切以官方英文原文为准。