# 加载 pdf 数据

> [!WARNING]
> Pdf 支持目前处于实验阶段，可能会发生变化。

Pdf 数据集包含 [Pdf](/docs/datasets/main/zh/package_reference/main_classes#datasets.Pdf) 类型的列，其中包含 `pdfplumber` 对象。

> [!TIP]
> 要处理 pdf 数据集，您需要安装 `pdfplumber` 包。请参阅 [安装](https://github.com/jsvine/pdfplumber#installation) 指南了解如何安装。

加载 pdf 数据集并调用 pdf 列时，pdf 文件会作为 `pdfplumber` Pdf 进行解码：

```py
>>> from datasets import load_dataset, Pdf

>>> dataset = load_dataset("path/to/pdf/folder", split="train")
>>> dataset[0]["pdf"]
<pdfplumber.pdf.PDF at 0x1075bc320>
```

> [!WARNING]
> 首先使用行索引，然后使用 `pdf` 列来索引 pdf 数据集 - `dataset[0]["pdf"]` - 以避免创建数据集中的所有 pdf 对象。否则，如果数据集很大，这可能是一个缓慢且耗时的过程。

如需了解如何加载任意类型的数据集，请参阅通用加载指南。

## 阅读页面

使用 `.pages` 属性直接从 pdf 中访问页面。

然后你可以使用 `pdfplumber` 函数来读取文本、表格和图像，例如：

```python
>>> pdf = dataset[0]["pdf"]
>>> first_page = pdf.pages[0]
>>> first_page
<Page:1>
>>> first_page.extract_text()
Docling Technical Report
Version1.0
ChristophAuer MaksymLysak AhmedNassar MicheleDolfi NikolaosLivathinos
PanosVagenas CesarBerrospiRamis MatteoOmenetti FabianLindlbauer
KasperDinkla LokeshMishra YusikKim ShubhamGupta RafaelTeixeiradeLima
ValeryWeber LucasMorin IngmarMeijer ViktorKuropiatnyk PeterW.J.Staar
AI4KGroup,IBMResearch
Ru¨schlikon,Switzerland
Abstract
This technical report introduces Docling, an easy to use, self-contained, MIT-
licensed open-source package for PDF document conversion.
...
>>> first_page.images
In [24]: first_page.images
Out[24]: 
[{'x0': 256.5,
  'y0': 621.0,
  'x1': 355.49519999999995,
  'y1': 719.9952,
  'width': 98.99519999999995,
  'height': 98.99519999999995,
  'name': 'Im1',
  'stream': <PDFStream(44): raw=88980, {'Type': /'XObject', 'Subtype': /'Image', 'BitsPerComponent': 8, 'ColorSpace': /'DeviceRGB', 'Filter': /'DCTDecode', 'Height': 1024, 'Length': 88980, 'Width': 1024}>,
  'srcsize': (1024, 1024),
  'imagemask': None,
  'bits': 8,
  'colorspace': [/'DeviceRGB'],
  'mcid': None,
  'tag': None,
  'object_type': 'image',
  'page_number': 1,
  'top': 72.00480000000005,
  'bottom': 171.0,
  'doctop': 72.00480000000005}]
>>> first_page.extract_tables()
[]
```

您也可以将每一页加载为 `PIL.Image`：

```python
>>> import PIL.Image
>>> import io
>>> first_page.to_image()
<pdfplumber.display.PageImage at 0x107d68dd0>
>>> buffer = io.BytesIO()
>>> first_page.to_image().save(buffer)
>>> img = PIL.Image.open(buffer)
>>> img
<PIL.PngImagePlugin.PngImageFile image mode=P size=612x792>
```

请注意，您可以将 `resolution=` 传递给 `.to_image()`，以高于默认值（72 ppi）的分辨率渲染图像。

## 本地文件

您可以从 pdf 路径加载数据集。使用 [cast_column()](/docs/datasets/main/zh/package_reference/main_classes#datasets.Dataset.cast_column) 函数接受一列 pdf 文件路径，并使用 [Pdf](/docs/datasets/main/zh/package_reference/main_classes#datasets.Pdf) 特征将其解码为 `pdfplumber` pdf：
```py
>>> from datasets import Dataset, Pdf

>>> dataset = Dataset.from_dict({"pdf": ["path/to/pdf_1", "path/to/pdf_2", ..., "path/to/pdf_n"]}).cast_column("pdf", Pdf())
>>> dataset[0]["pdf"]
<pdfplumber.pdf.PDF at 0x1657d0280>
```

如果只想加载 pdf 数据集的底层路径而不解码 pdf 对象，请在 [Pdf](/docs/datasets/main/zh/package_reference/main_classes#datasets.Pdf) 特征中设置 `decode=False`：

```py
>>> dataset = dataset.cast_column("pdf", Pdf(decode=False))
>>> dataset[0]["pdf"]
{'bytes': None,
 'path': 'path/to/pdf/folder/pdf0.pdf'}
```

## PdfFolder

您也可以通过 `PdfFolder` 数据集构建器加载数据集，这无需编写自定义 dataloader。这使得 `PdfFolder` 非常适合快速创建和加载包含数千个 pdf 的数据集，用于不同的视觉任务。您的 pdf 数据集结构应如下所示：

```
folder/train/resume/0001.pdf
folder/train/resume/0002.pdf
folder/train/resume/0003.pdf

folder/train/invoice/0001.pdf
folder/train/invoice/0002.pdf
folder/train/invoice/0003.pdf
```

如果数据集遵循 `PdfFolder` 结构，则可以直接使用 [load_dataset()](/docs/datasets/main/zh/package_reference/loading_methods#datasets.load_dataset) 加载：

```py
>>> from datasets import load_dataset

>>> dataset = load_dataset("username/dataset_name")
>>> # OR locally:
>>> dataset = load_dataset("/path/to/folder")
```

对于本地数据集，这相当于在 [load_dataset()](/docs/datasets/main/zh/package_reference/loading_methods#datasets.load_dataset) 中手动传入 `pdffolder` 以及 `data_dir` 中的目录：

```py
>>> dataset = load_dataset("pdffolder", data_dir="/path/to/folder")
```

然后，您可以将 PDF 文件作为 `pdfplumber.pdf.PDF` 对象进行访问：

```
>>> dataset["train"][0]
{"pdf": <pdfplumber.pdf.PDF at 0x161715e50>, "label": 0}

>>> dataset["train"][-1]
{"pdf": <pdfplumber.pdf.PDF at 0x16170bd90>, "label": 1}
```

若要忽略元数据文件中的信息，请在 [load_dataset()](/docs/datasets/main/zh/package_reference/loading_methods#datasets.load_dataset) 中设置 `drop_metadata=True`：

```py
>>> from datasets import load_dataset

>>> dataset = load_dataset("username/dataset_with_metadata", drop_metadata=True)
```

如果没有元数据文件，`PdfFolder` 会自动从目录名推断标签名称。如果要丢弃自动创建的标签，请设置 `drop_labels=True`。在这种情况下，您的数据集将只包含一个 pdf 列：

```py
>>> from datasets import load_dataset

>>> dataset = load_dataset("username/dataset_without_metadata", drop_labels=True)
```

最后，`filters` 参数允许你基于标签或元数据中的条件，仅加载数据集的一个子集。如果元数据采用 Parquet 格式，这一点尤其有用，因为该格式支持快速过滤。同时，建议将此参数与 `streaming=True` 一起使用，因为默认情况下，数据集会在过滤之前被完整下载。

```python
>>> filters = [("label", "=", 0)]
>>> dataset = load_dataset("username/dataset_name", streaming=True, filters=filters)
```

> [!TIP]
> 有关创建自己的 `PdfFolder` 数据集的更多信息，请参阅 [创建 pdf 数据集](./document_dataset) 指南。

## Pdf 解码

默认情况下，在迭代数据集时，pdf 会按顺序解码为 pdfplumber `PDFs`。它会按顺序解码 pdf 的元数据，直到你访问 pdf 页面之前，不会读取这些页面。

不过，可以使用多线程解码来显著加快数据集的处理速度：

```python
>>> import os
>>> num_threads = num_threads = min(32, (os.cpu_count() or 1) + 4)
>>> dataset = dataset.decode(num_threads=num_threads)
>>> for example in dataset:  # up to 20 times faster !
...     ...
```

您可以使用 `num_threads` 来启用多线程。这对于加速远程数据流式传输特别有用。不过，对于位于高速磁盘上的本地数据，它可能比 `num_threads=0` 更慢。

如果您对以 pdfplumber 解码的 `PDFs` 文档不感兴趣，而希望直接访问路径/字节，则可以禁用解码：

```python
>>> dataset = dataset.decode(False)
```

注意：[IterableDataset.decode()](/docs/datasets/main/zh/package_reference/main_classes#datasets.IterableDataset.decode) 目前仅适用于流式数据集。

