0Pricing
AI Agents · บทเรียน

การแยกวิเคราะห์ PDF ด้วย PyMuPDF และ pdfplumber

ดึงข้อความ ตาราง และข้อมูลกำกับจาก PDF ด้วยโปรแกรม

การแยกวิเคราะห์ PDF ด้วย PyMuPDF และ pdfplumber เป็นบทเรียน AI Agents ฟรีบน CoddyKit นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน AI Agents และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส AI Agents มีบทเรียนทั้งหมด 4 บทเรียน

เหตุใดการแยกวิเคราะห์ PDF จึงไม่ใช่เรื่องง่าย

PDF เป็นรูปแบบการนำเสนอ ไม่ใช่รูปแบบข้อมูล ข้อความถูกจัดเก็บเป็นอักขระภาพที่วางตามตำแหน่ง ไม่ใช่ย่อหน้าตามตรรกะ การแยกข้อความที่มีความหมายจึงต้องเข้าใจการจัดวาง ลำดับการอ่าน คุณสมบัติของแบบอักษร และจัดการกรณีต่าง ๆ เช่น การจัดวางหลายคอลัมน์ หัวกระดาษ/ท้ายกระดาษ และรูปภาพที่ฝังอยู่

มีไลบรารีหลักที่ใช้กันอย่างแพร่หลายสองรายการ ได้แก่ PyMuPDF (ความเร็ว) และ pdfplumber (การแยกตาราง)

พื้นฐาน PyMuPDF

PyMuPDF (นำเข้าในชื่อ fitz) เป็นไลบรารี PDF สำหรับ Python ที่เร็วที่สุด รองรับการแยกข้อความ ข้อมูลเมตา รูปภาพ และการเรนเดอร์ ติดตั้งด้วย pip install pymupdf

import fitz  # PyMuPDF

# Open a PDF
doc = fitz.open('document.pdf')

print(f'Pages: {len(doc)}')
print(f'Metadata: {doc.metadata}')

# Extract text from all pages
full_text = ''
for page_num in range(len(doc)):
    page = doc[page_num]
    text = page.get_text()  # plain text extraction
    full_text += f'--- Page {page_num + 1} ---\n{text}\n'

doc.close()
print(full_text[:500])

โหมดการแยกข้อความของ PyMuPDF

page.get_text() รองรับรูปแบบผลลัพธ์หลายแบบ ใช้ 'text' สำหรับข้อความธรรมดา ใช้ 'blocks' สำหรับบล็อกข้อความพร้อมกรอบขอบเขต และใช้ 'dict' สำหรับผลลัพธ์แบบมีโครงสร้างที่ละเอียด ซึ่งรวมชื่อและขนาดแบบอักษรไว้ด้วย

import fitz

doc = fitz.open('report.pdf')
page = doc[0]

# Mode 1: plain text
plain = page.get_text('text')

# Mode 2: blocks (each block has bbox + text)
blocks = page.get_text('blocks')
for block in blocks:
    x0, y0, x1, y1, text, block_no, block_type = block
    if block_type == 0:  # text block (1 = image)
        print(f'Block at ({x0:.0f},{y0:.0f}): {text[:80]}')

# Mode 3: dict (full detail including font info)
page_dict = page.get_text('dict')
for block in page_dict['blocks']:
    if block.get('type') == 0:  # text
        for line in block['lines']:
            for span in line['spans']:
                print(f"Font: {span['font']}, Size: {span['size']:.1f}, Text: {span['text']}")

doc.close()

การแยกข้อมูลเมตาของหน้า

ข้อมูลเมตาของหน้าช่วยให้เอเจนต์เข้าใจโครงสร้างเอกสาร ได้แก่ จำนวนหน้า ชื่อเอกสาร ผู้เขียน วันที่สร้าง และขนาดหน้า PyMuPDF เปิดให้เข้าถึงข้อมูลทั้งหมดนี้ได้

import fitz

def extract_pdf_metadata(filepath):
    doc = fitz.open(filepath)
    meta = doc.metadata
    info = {
        'title':    meta.get('title', 'Unknown'),
        'author':   meta.get('author', 'Unknown'),
        'subject':  meta.get('subject', ''),
        'creator':  meta.get('creator', ''),
        'created':  meta.get('creationDate', ''),
        'modified': meta.get('modDate', ''),
        'pages':    len(doc),
        'page_size': {
            'width':  doc[0].rect.width,
            'height': doc[0].rect.height
        }
    }
    doc.close()
    return info

meta = extract_pdf_metadata('contract.pdf')
print(f"Title: {meta['title']}, Pages: {meta['pages']}")

การใช้ pdfplumber เพื่อแยกตาราง

pdfplumber มีความสามารถโดดเด่นในการแยกตารางจาก PDF โดยใช้การวิเคราะห์ทางเรขาคณิตเพื่อตรวจจับขอบเขตเซลล์ แม้ใน PDF ที่ไม่มีการกำกับตารางไว้อย่างชัดเจน

ติดตั้งด้วย pip install pdfplumber

import pdfplumber

with pdfplumber.open('financial_report.pdf') as pdf:
    for page_num, page in enumerate(pdf.pages):
        tables = page.extract_tables()
        for table_idx, table in enumerate(tables):
            print(f'Page {page_num+1}, Table {table_idx+1}:')
            # table is a list of rows; each row is a list of cell strings
            headers = table[0]
            for row in table[1:]:
                row_dict = dict(zip(headers, row))
                print(row_dict)

การตั้งค่าตารางของ pdfplumber

การแยกตารางของ pdfplumber สามารถปรับแต่งด้วยการตั้งค่าเพื่อรองรับรูปแบบตารางต่าง ๆ เช่น เส้นตารางที่กำหนดไว้อย่างชัดเจน คอลัมน์ที่คั่นด้วยช่องว่าง หรือการจัดวางแบบผสม

import pdfplumber

# Custom table settings for borderless tables
table_settings = {
    'vertical_strategy':   'text',   # 'lines', 'lines_strict', 'text', 'explicit'
    'horizontal_strategy': 'text',
    'snap_tolerance':       5,
    'join_tolerance':       3,
    'edge_min_length':     50,
    'min_words_vertical':   3,
    'min_words_horizontal': 1
}

with pdfplumber.open('nolines_table.pdf') as pdf:
    page = pdf.pages[0]
    table = page.extract_table(table_settings)
    if table:
        import csv
        import io
        output = io.StringIO()
        writer = csv.writer(output)
        writer.writerows(table)
        csv_string = output.getvalue()
        print(csv_string[:300])

การจัดการรูปแบบหลายคอลัมน์

บทความวิชาการและหนังสือพิมพ์ใช้การจัดวางแบบหลายคอลัมน์ การแยกข้อความแบบพื้นฐานจะอ่านข้ามคอลัมน์จากซ้ายไปขวา ทำให้ได้ข้อความที่สับสน แก้ไขโดยจัดเรียงบล็อกข้อความตามคอลัมน์ก่อน

import fitz

def extract_multicolumn_text(page, n_columns=2):
    page_width = page.rect.width
    col_width = page_width / n_columns

    blocks = page.get_text('blocks')
    # Filter text blocks only
    text_blocks = [b for b in blocks if b[6] == 0]

    # Assign each block to a column based on x position
    columns = [[] for _ in range(n_columns)]
    for block in text_blocks:
        x0 = block[0]
        col_idx = min(int(x0 / col_width), n_columns - 1)
        columns[col_idx].append(block)

    # Sort each column by vertical position
    for col in columns:
        col.sort(key=lambda b: b[1])  # sort by y0

    # Read columns left to right
    full_text = ''
    for col in columns:
        for block in col:
            full_text += block[4] + '\n'
    return full_text

การกรองหัวกระดาษและท้ายกระดาษ

หัวกระดาษและท้ายกระดาษของ PDF จะปรากฏซ้ำในทุกหน้าและทำให้ข้อความที่แยกออกมาปะปน ควรระบุด้วยตำแหน่งแนวตั้ง (10% ด้านบนหรือด้านล่างของหน้า) แล้วไม่นำสิ่งเหล่านี้ไปรวมในการแยกเนื้อหา

import fitz

def extract_without_headers_footers(page, margin_ratio=0.08):
    page_height = page.rect.height
    top_margin = page_height * margin_ratio
    bottom_margin = page_height * (1 - margin_ratio)

    blocks = page.get_text('blocks')
    content_blocks = []

    for block in blocks:
        x0, y0, x1, y1, text, block_no, block_type = block
        if block_type != 0:
            continue  # skip image blocks
        # Skip blocks in header or footer zone
        if y0 < top_margin or y1 > bottom_margin:
            continue
        content_blocks.append(text)

    return '\n'.join(content_blocks)

การแบ่งข้อความ PDF เป็นชิ้นสำหรับเอเจนต์

PDF ขนาดยาวต้องแบ่งออกเป็นชิ้นสำหรับการทำเอ็มเบดดิงและการค้นคืน ควรแบ่งตรงขอบเขตตามธรรมชาติ เช่น ย่อหน้า ส่วน หรือหน้า และให้ชิ้นต่าง ๆ มีเนื้อหาซ้อนทับกัน เพื่อไม่ให้บริบทถูกตัดขาดกลางประโยค

import fitz

def pdf_to_chunks(filepath, chunk_size=1000, overlap=200):
    doc = fitz.open(filepath)
    chunks = []

    for page_num in range(len(doc)):
        page = doc[page_num]
        page_text = page.get_text()

        # Split into chunks with overlap
        start = 0
        while start < len(page_text):
            end = start + chunk_size
            chunk = page_text[start:end]
            chunks.append({
                'text': chunk,
                'page': page_num + 1,
                'char_start': start,
                'source': filepath
            })
            start += chunk_size - overlap  # overlap

    doc.close()
    return chunks

chunks = pdf_to_chunks('research_paper.pdf')
print(f'Total chunks: {len(chunks)}')
print(f'Sample: {chunks[0]["text"][:200]}')

การผสาน PyMuPDF กับพีดีเอฟพลัมเบอร์

ใช้ PyMuPDF สำหรับการแยกข้อความ (เร็วกว่า) และพีดีเอฟพลัมเบอร์สำหรับการตรวจจับตาราง (แม่นยำกว่า) ตัวแยกข้อมูลแบบผสานจะทำงานทั้งสองอย่างในแต่ละหน้า แล้วส่งคืนเนื้อหาแบบมีโครงสร้าง โดยแยกข้อความกับตารางออกจากกัน

import fitz
import pdfplumber

def full_pdf_extract(filepath):
    result = {'text_by_page': [], 'tables': []}

    # Text extraction with PyMuPDF
    doc = fitz.open(filepath)
    for i in range(len(doc)):
        text = extract_without_headers_footers(doc[i])
        result['text_by_page'].append({'page': i + 1, 'text': text})
    doc.close()

    # Table extraction with pdfplumber
    with pdfplumber.open(filepath) as pdf:
        for page_num, page in enumerate(pdf.pages):
            tables = page.extract_tables()
            for t in tables:
                result['tables'].append({
                    'page': page_num + 1,
                    'headers': t[0] if t else [],
                    'rows': t[1:] if t and len(t) > 1 else []
                })

    return result

การบันทึกข้อความที่แยกแล้วลงไฟล์

หลังจากแยกข้อความจาก PDF แล้ว ให้บันทึกในรูปแบบที่เอเจนต์ขั้นถัดไปสามารถใช้งานได้ ไฟล์ข้อความธรรมดาเหมาะสำหรับกระบวนการทำเอ็มเบดดิง ส่วนข้อมูลแบบมีโครงสร้างจะรักษาโครงสร้างของหน้าไว้เพื่อการติดตามแหล่งอ้างอิง

import json, os

class FakePage:
    def __init__(self, text): self.text = text
    def get_text(self): return self.text

class FakeDoc(list):
    def close(self): pass

def fitz_open(path):
    return FakeDoc([FakePage('Page 1 text'), FakePage('Page 2 text')])

def pdf_to_text_file(pdf_path, output_dir):
    doc = fitz_open(pdf_path)
    base = os.path.splitext(os.path.basename(pdf_path))[0]
    txt_path = os.path.join(output_dir, base + '.txt')
    with open(txt_path, 'w', encoding='utf-8') as f:
        for i, page in enumerate(doc):
            f.write(f'--- Page {i+1} ---\n{page.get_text()}\n')
    json_path = os.path.join(output_dir, base + '.json')
    pages = [{'page': i+1, 'text': p.get_text()} for i, p in enumerate(doc)]
    with open(json_path, 'w') as f:
        json.dump({'source': pdf_path, 'pages': pages}, f, indent=2)
    doc.close()
    print(f'Saved: {txt_path} and {json_path}')
    return txt_path, json_path

pdf_to_text_file('sample.pdf', '.')

ตรวจสอบความรู้

ไลบรารีไพธอนใดเหมาะที่สุดสำหรับการแยกตารางจากไฟล์ PDF

ทบทวน: การแยกวิเคราะห์ PDF ด้วย PyMuPDF และพีดีเอฟพลัมเบอร์

PyMuPDF (fitz) เป็นตัวเลือกที่รวดเร็วสำหรับการแยกข้อความ ข้อมูลเมทาดาทา และการจัดการเค้าโครงแบบหลายคอลัมน์ ส่วน พีดีเอฟพลัมเบอร์โดดเด่นด้านการแยกตารางด้วยกลยุทธ์เชิงเรขาคณิตที่กำหนดค่าได้

เทคนิคสำคัญ ได้แก่ ใช้ get_text('blocks') สำหรับการแยกข้อมูลที่คำนึงถึงตำแหน่ง กรองส่วนหัวและท้ายกระดาษตามตำแหน่งแนวตั้ง จัดการเค้าโครงหลายคอลัมน์ด้วยการเรียงบล็อกตามคอลัมน์ และแบ่งข้อความเป็นชิ้นที่มีส่วนซ้อนทับกันสำหรับระบบค้นคืนของเอเจนต์ ควรใช้ทั้งสองไลบรารีร่วมกันเพื่อให้ได้ผลลัพธ์ที่ดีที่สุด

คำถามที่พบบ่อย

บทเรียน “การแยกวิเคราะห์ PDF ด้วย PyMuPDF และ pdfplumber” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การแยกวิเคราะห์ PDF ด้วย PyMuPDF และ pdfplumber” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส AI Agents ให้อัปเกรดเป็น CoddyKit PRO คอร์ส AI Agents มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การแยกวิเคราะห์ PDF ด้วย PyMuPDF และ pdfplumber”

ดึงข้อความ ตาราง และข้อมูลกำกับจาก PDF ด้วยโปรแกรม คุณปฏิบัติ AI Agents ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน AI Agents หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน AI Agents บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน

บทเรียน “การแยกวิเคราะห์ PDF ด้วย PyMuPDF และ pdfplumber” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน AI Agents นี้ได้ไหม

ได้ บทเรียน AI Agents ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การแยกวิเคราะห์ PDF ด้วย PyMuPDF และ pdfplumber
  2. OCR สำหรับเอกสารสแกน
  3. ตัวแทนถามตอบจากเอกสารหลายฉบับ
  4. การจำแนกและกำหนดเส้นทางเอกสาร
← กลับไปที่ AI Agents