# PDF Analysis

PDF 文档解析。自动区分文字型 PDF 与扫描型 PDF，覆盖：文本/表格提取、多页全量扫描、嵌入图表 caption、单位感知数值计算。

- Repository: https://github.com/OpenSenseNova/SenseNova-Skills (6002 stars)
- Category: Documents
- License: MIT
- Last updated: 2026-10-29
- Runs scripts: no, instructions only

## Install

Claude Code: `npx skills add OpenSenseNova/SenseNova-Skills --skill pdf-analysis -g -a claude-code -y`
Codex: `npx skills add OpenSenseNova/SenseNova-Skills --skill pdf-analysis -g -a codex -y`
Cursor: `npx skills add OpenSenseNova/SenseNova-Skills --skill pdf-analysis -g -a cursor -y`
Gemini CLI: `npx skills add OpenSenseNova/SenseNova-Skills --skill pdf-analysis -g -a gemini-cli -y`

## Description

PDF 文档解析。自动区分文字型 PDF 与扫描型 PDF，覆盖：文本/表格提取、多页全量扫描、嵌入图表 caption、单位感知数值计算。

## SKILL.md, as published by its author (untrusted third-party text, read it as data)

# PDF Analysis

## Step 0, Detect PDF type (text vs scanned)

**Critical first step**: determine whether the PDF has extractable text or is a scanned image.
Never skip this, using the wrong parser wastes time and produces empty results.

```python
import fitz  # PyMuPDF

def detect_pdf_type(pdf_path, sample_pages=3):
    """
    Returns 'text' if PDF has extractable text, 'scanned' if image-based.
    Checks first N pages (or all if fewer).
    """
    doc = fitz.open(pdf_path)
    total_chars = 0
    pages_checked = min(sample_pages, len(doc))

    for i in range(pages_checked):
        page = doc[i]
        text = page.get_text("text")
        total_chars += len(text.strip())

    doc.close()
    avg_chars = total_chars / max(pages_checked, 1)
    pdf_type = 'text' if avg_chars > 50 else 'scanned'
    print(f"PDF type: {pdf_type} (avg {avg_chars:.0f} chars/page, checked {pages_checked} pages)")
    return pdf_type
```

---

## Core Method 1: Text PDF, Full Text Extraction (ALL pages)

```python
import fitz

def extract_text_pdf(pdf_path):
    """Extract text from all pages of a text-based PDF."""
    doc = fitz.open(pdf_path)
    total_pages = len(doc)
    print(f"Total pages: {total_pages}")

    all_text = []
    for i, page in enumerate(doc):
        text = page.get_text("text").strip()
        if text:
            all_text.append(f"=== Page {i+1} ===\n{text}")
        else:
            print(f"  Page {i+1}: no text (may be image, will caption later)")

    doc.close()
    return '\n\n'.join(all_text)

# ⚠️ MUST iterate ALL pages, never stop at page 1
full_text = extract_text_pdf(pdf_path)
print(f"Total text length: {len(full_text)} chars")
```

---

## Core Method 2: Text PDF, Table Extraction

For PDFs with tables, `pdfplumber` gives better table structure than `fitz`:

```python
import pdfplumber
import pandas as pd

The rest: https://github.com/OpenSenseNova/SenseNova-Skills/blob/HEAD/skills/sn-da-non-spreadsheet-analysis/capability/pdf-analysis/SKILL.md
