Introduction

Common pitfalls when extracting data from PDFs include: tables extracted by pdftotext turning into strings without delimiters; PyPDF2 providing only plain text and losing row/column structures; and successfully extracting tables but being unable to explain why certain cells are misaligned. To obtain character-level coordinates, lines, and rectangles, and then manually determine which characters constitute a table cell, generic text extraction tools are generally insufficient.

The Skill introduced below is pdfplumber Python PDF text and table extraction library, which wraps the pdfplumber library into a callable Agent Skill, specifically designed to solve the problem of “obtaining structured information from PDFs.”

What is this

One-sentence positioning: pdfplumber is a Python library used to extract detailed information—text, tables, lines, rectangles, and curves—from PDFs, and supports visual debugging.

  • Upstream Project: jsvine/pdfplumber, built on top of pdfminer.six
  • Skill Origin: A community Skill on SkillHub, coordinates @user_3c6cb52e/pdfplumber-python-pdf-text-table-extraction, published by user_3c6cb52e, tagged as community
  • Version: 1.0.0
  • Category: office-efficiency
  • Tags: requires_api_key=false, meaning no additional API Key application is required

The problem it solves is: reconstructing layout objects into programmable data structures on machine-generated PDFs, especially structured tables.

Core Functions

Verified against upstream documentation, the confirmed capabilities are as follows.

  1. Text Extraction. Page.extract_text() extracts plain text, while extract_text(layout=True) preserves the layout. The latter is used in the CLI with --format text.

  2. Table Extraction. page.extract_tables() extracts structured tables and returns nested lists; the accompanying page.find_tables() is used to locate table bounding boxes for further cropping or verification. This is pdfplumber’s primary advantage over other libraries.

  3. Character-level and Graphic-level Objects. Each page exposes .chars, .lines, .rects, .curves, and .images lists. Each element is a dictionary containing fields like x0, top, x1, bottom, and text, allowing for direct position-based filtering and sorting.

  4. Layout Cropping and Filtering. .crop(), .within_bbox(), and .outside_bbox() crop the page by bounding box, while .filter() filters objects using custom functions. Bounding boxes are 4-tuples (x0, top, x1, bottom).

  5. Visual Debugging. page.debug_tablefinder() draws the bounding boxes of detected tables as images, used to troubleshoot “why this table was not recognized.”

  6. Form Field Value Extraction. It can read field names and values from PDF AcroForm forms.

  7. CLI. The command-line tool supports csv, json, and text output formats, and can specify page ranges and object types.

Installation and Activation

Upstream Library Installation

The upstream library is installed via pip:

pip install pdfplumber

The upstream repository currently has passing test records on Python 3.10, 3.11, 3.12, 3.13, and 3.14. Earlier Chinese documentation marked Python 3.8–3.11, which is inconsistent with current descriptions; the repository’s current test matrix should be taken as the standard.

CLI Installation

The command-line tool is installed along with pdfplumber[cli]:

pip install "pdfplumber[cli]"

Skill Activation

SkillHub page coordinates:

@user_3c6cb52e/pdfplumber-python-pdf-text-table-extraction

The Skill version is 1.0.0, source community, tag requires_api_key=false. This Skill is based on the general SKILL.md format; therefore, in any Agent supporting this format, it can be loaded simply by placing the Skill directory in the corresponding location of the host project.

It should be noted that: the crawl of the SkillHub page this time was unsuccessful. The coordinates, version, category, and tags listed above are taken from pre-crawled data, which also recorded a rating of 100,000, 1,191 downloads, and 0 installs. The rating of 99,742 and 1,161 downloads given in the task description are inconsistent with the data. Since the page could not be verified a second time, these two figures are not adopted in this article.

Additionally, the data does not provide specific installation command differences for Cursor, Codex CLI, or Claude Code, nor does it specify the exact path of the Skill directory within the host project. This information did not appear in the crawled data, so no inference is made in this article.

CLI Parameters

The available parameters for the CLI are as follows:

pdfplumber < input.pdf > output.csv
Parameter Description
--format [format] csv, json, or text. csv and json return detailed information for each object; json additionally includes PDF-level and page-level metadata and dictionary nesting properties; text returns plain text from Page.extract_text(layout=True).
--pages [list of pages] Space-separated 1-based page numbers or ranges, e.g., 1, 11-15.
--types [list of object types] Optional char, rect, line, curve, image, annot, etc. Defaults to all.
--laparams A JSON string passed to pdfplumber.open(..., laparams=...), e.g., '{"detect_vertical": true}'.
--precision [integer] Number of decimal places for floating point numbers. Default is no rounding.

Typical Usage

Command Line: Export Object Information for the Entire PDF

curl "https://raw.githubusercontent.com/jsvine/pdfplumber/stable/examples/pdfs/background-checks.pdf" > background-checks.pdf
pdfplumber background-checks.pdf > background-checks.csv

The output is a CSV containing information for every character, line, and rectangle in the PDF. Using --format json outputs a more complete nested structure.

Python: Open PDF and Read the First Character of the First Page

import pdfplumber

with pdfplumber.open("path/to/file.pdf") as pdf:
    first_page = pdf.pages[0]
    print(first_page.chars[0])

The x in pdfplumber.open(x) can be a file path, a file object loaded as bytes, or a file-like object.

Python: Load Encrypted PDF

pdfplumber.open("file.pdf", password="test")

Python: Pass Layout Analysis Parameters

pdfplumber.open("file.pdf", laparams={"line_overlap": 0.7})

laparams works directly on the layout engine of pdfminer.six.

Python: Extract Tables

import pdfplumber

with pdfplumber.open("report.pdf") as pdf:
    for page in pdf.pages:
        for table in page.extract_tables():
            print(table)

extract_tables() returns a nested list; the outer layer represents tables, the inner layer represents rows, and the elements are cell texts. When you need to locate the position of a table on the page, use page.find_tables(), and the returned objects have a .bbox attribute.

Python: Debug Table Detection

page.debug_tablefinder()

This method renders the detected bounding boxes as an image output to judge whether the table’s row and column lines are correctly identified.

Python: Crop Page

page.crop((x0, top, x1, bottom))

Objects that fall at least partially within the crop box are retained, while parts outside are sliced. Use page.within_bbox(...) if you only want objects completely inside the box, and page.outside_bbox(...) for objects completely outside.

Applicable Scenarios and Precautions

Suitable scenarios:

  1. Machine-generated PDFs, i.e., files output by typesetting software, reporting systems, or PDF generation libraries, where the text is a real text layer rather than an image.
  2. Scenarios requiring tables to be restored into row/column structures and then converted to CSV, DataFrame, or database entries.
  3. Scenarios requiring positioning, cropping, or filtering specific areas by coordinates, such as taking only the top-right corner of a page.
  4. Scenarios requiring troubleshooting why extraction results are incorrect; visual debugging is faster than repeatedly printing coordinates.

Limitations to note:

  1. Not applicable to scanned PDFs. The documentation explicitly states that it “works best on computer-generated PDFs and does not support scanned PDFs.” Scanned documents require OCR first.
  2. Table detection depends on lines or character alignment on the page. If the table in the original PDF has no drawn lines and the characters do not form clear column alignments, find_tables() may fail to detect or cut columns incorrectly. In this case, strategies need to be adjusted or laparams used.
  3. Memory usage for large PDFs. Page objects cache layout and object information by default to avoid repeated parsing. Processing large files may consume significant memory due to caching. Call page.close() to release it when needed.
  4. Metadata parsing is lenient by default. Invalid metadata values are only warnings by default; if you want parsing to fail with an exception, pass strict_metadata=True.
  5. Coordinate system origin is the top-left corner of the PDF page. top is the distance from the top, not a traditional y-coordinate. Pay attention when doing interval judgments.

Conclusion

The value of pdfplumber lies in transforming a PDF from “a text stream” into “a set of objects with coordinates,” thereby making text extraction, table restoration, area cropping, and result debugging programmable steps. For machine-generated PDFs, especially scenarios requiring structured tables, it is a relatively complete option in the current Python ecosystem.

Skill Address: https://www.skillhub.cn/skills/user_3c6cb52e/pdfplumber-python-pdf-text-table-extraction

Upstream Project: https://github.com/jsvine/pdfplumber