You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python通用提取无全边框表格为文本及DataFrame

通用无全边框表格提取方案(支持多行拆分字段自动合并)

这套方案不需要针对单张表格手动指定坐标,可适配绝大多数无外边框、存在字段折行的业务表格,输出结果支持直接转pandas DataFrame或纯文本。

依赖安装

先安装所需依赖包,OCR引擎默认用Tesseract,需要提前在本地安装对应程序并配置好需要的语言识别包:
pip install opencv-python numpy pandas pytesseract

核心实现逻辑

整套流程不需要单表配置坐标,所有结构识别全为自适应逻辑:

  • 自动识别表格结构:通过自适应阈值做图像二值化,结合形态学运算自动提取水平/垂直分隔线,推算行列边界;如果表格没有内部竖线,自动切换为列投影模式,按列方向的空白间隙切分列
  • 单元格内容识别:按自动计算的单元格边界切分图块,做OTSU二值化提升识别率后调用OCR提取文字
  • 折行字段自动合并:通过通用规则识别折行:如果某一行的首列内容不含数字、计量单位等指标类特征,判定为上一行名称字段的拆分内容,自动拼接到上一行对应单元格
  • 结构化输出:清洗空行后将二维表数据转换为DataFrame,支持直接导出为CSV、文本等格式

可直接运行的代码

import cv2
import numpy as np
import pandas as pd
import pytesseract

# 若tesseract不在系统环境变量,取消下面一行注释改成本地安装路径
# pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract.exe'

def extract_borderless_table(img_path, ocr_lang='chi_sim+eng'):
    # 读取图片自动预处理
    img = cv2.imread(img_path)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    binary = cv2.adaptiveThreshold(~gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 15, -2)

    # 自动检测水平、垂直分隔线,阈值根据图片尺寸自适应计算
    h, w = binary.shape
    horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (w//10, 1))
    vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1, h//10))
    
    horizontal_lines = cv2.erode(binary, horizontal_kernel, iterations=2)
    horizontal_lines = cv2.dilate(horizontal_lines, horizontal_kernel, iterations=2)
    vertical_lines = cv2.erode(binary, vertical_kernel, iterations=2)
    vertical_lines = cv2.dilate(vertical_lines, vertical_kernel, iterations=2)

    # 提取所有线的坐标,自动计算行列边界
    h_y_coords = []
    contours_h, _ = cv2.findContours(horizontal_lines, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    for cnt in contours_h:
        x,y,w_cnt,h_cnt = cv2.boundingRect(cnt)
        h_y_coords.append(y)
    h_y_coords = sorted(list(set(h_y_coords)))

    v_x_coords = []
    contours_v, _ = cv2.findContours(vertical_lines, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    for cnt in contours_v:
        x,y,w_cnt,h_cnt = cv2.boundingRect(cnt)
        v_x_coords.append(x)
    v_x_coords = sorted(list(set(v_x_coords)))

    # 处理无线条靠间距区分的场景:如果检测到的竖线少于2条,自动按列投影切分
    if len(v_x_coords) <2:
        col_projection = np.sum(binary, axis=0)
        col_break_points = np.where(col_projection < 10)[0]
        v_x_coords = []
        for i in range(len(col_break_points)-1):
            if col_break_points[i+1] - col_break_points[i] > 20:
                v_x_coords.append(col_break_points[i])
        v_x_coords = sorted(list(set(v_x_coords)))

    # 切分单元格+OCR识别
    rows = []
    for i in range(len(h_y_coords)-1):
        current_row = []
        y1, y2 = h_y_coords[i], h_y_coords[i+1]
        for j in range(len(v_x_coords)-1):
            x1, x2 = v_x_coords[j], v_x_coords[j+1]
            cell_roi = gray[y1:y2, x1:x2]
            # 预处理单元格提升识别率
            _, cell_binary = cv2.threshold(cell_roi, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
            text = pytesseract.image_to_string(cell_binary, lang=ocr_lang).strip().replace('\n', '')
            current_row.append(text)
        rows.append(current_row)

    # 自动合并折行的名称字段
    cleaned_rows = []
    for row in rows:
        # 跳过全空行
        if not any([t.strip() for t in row]):
            continue
        # 判断当前行是不是上一行的折行:第一列内容非空且没有数字/指标特征,且上一行存在
        is_wrap_line = False
        if cleaned_rows:
            first_col_text = row[0].strip()
            # 折行判断规则:第一列有内容,且不含数字、百分号、货币单位这类指标特征
            if first_col_text and not any(c.isdigit() for c in first_col_text) and not any(u in first_col_text for u in ['%','元','万元','吨']):
                # 把当前行所有内容拼接到上一行对应单元格
                for idx, cell_text in enumerate(row):
                    if cell_text.strip():
                        cleaned_rows[-1][idx] += cell_text.strip()
                is_wrap_line = True
        if not is_wrap_line:
            cleaned_rows.append([t.strip() for t in row])

    # 转成DataFrame,默认第一行为表头,不符合的话可以手动调整
    df = pd.DataFrame(cleaned_rows[1:], columns=cleaned_rows[0])
    return df

# 调用示例
if __name__ == '__main__':
    table_df = extract_borderless_table('your_table_image.png')
    print(table_df)
    # 导出文本/CSV
    table_df.to_csv('table_output.csv', index=False, encoding='utf-8-sig')

适配说明

  • 如果对OCR识别精度要求更高,可以把代码里的pytesseract替换为PaddleOCR,表格结构检测、折行合并的逻辑完全不需要改动
  • 折行判断规则可根据自身业务场景全局调整,比如新增指标类关键词、修改特征判断逻辑,调整后可适配同类型所有表格,不需要单表改配置
  • 如果是PDF里的表格,只需要在读取图片环节加一步pdf2image把PDF页转成OpenCV可读取的图片数组,后续逻辑完全复用

内容的提问来源于stack exchange,提问作者stephsmith

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.02 09:18:27