在R中将扫描版PDF转为可搜索PDF并提取表格的方法
扫描版PDF表格提取与R数据清洗方案
一、将扫描PDF转为可搜索PDF(OCR处理)
扫描版PDF本质是图片集合,必须先做光学字符识别(OCR)转成可搜索文本后,才能用tabulizer提取表格。用R的tesseract+pdftools组合可以完成全流程处理:
# 安装依赖包 install.packages(c("pdftools", "tesseract", "magick")) library(pdftools) library(tesseract) library(magick) # 下载对应语言包(中文用"chi_sim",英文用"eng") tesseract_download("chi_sim") ocr_engine <- tesseract("chi_sim") # 把扫描PDF转成单页图片(高dpi提升识别准确率) pdf_images <- pdf_convert("你的扫描文件.pdf", format = "png", dpi = 300) # 逐页做OCR并生成可搜索PDF页 lapply(pdf_images, function(img_path) { img <- image_read(img_path) ocr_text <- ocr(img, engine = ocr_engine) # 生成单页可搜索PDF模板 pdf_content <- sprintf( "%PDF-1.4\n1 0 obj\n<< /Type /Page /Parent 2 0 R /MediaBox [0 0 612 792] /Contents 3 0 R >>\nendobj\n2 0 obj\n<< /Type /Pages /Kids [1 0 R] /Count 1 >>\nendobj\n3 0 obj\n<< /Length %d >>\nstream\nBT /F1 12 Tf 50 750 Td (%s) Tj ET\nendstream\nendobj\nxref\n0 4\n0000000000 65535 f \n0000000010 00000 n \n0000000100 00000 n \n0000000200 00000 n \ntrailer\n<< /Size 4 /Root 2 0 R >>\nstartxref\n300\n%%EOF", nchar(ocr_text), ocr_text ) writeLines(pdf_content, paste0("temp_page_", basename(img_path), ".pdf")) }) # 合并所有临时PDF成最终可搜索文件 pdf_combine(list.files(pattern = "temp_page_.*\\.pdf"), output = "可搜索版表格.pdf") # 清理临时文件 file.remove(pdf_images) file.remove(list.files(pattern = "temp_page_.*\\.pdf"))
生成可搜索PDF后,再用tabulizer::extract_tables()提取表格,根据表格类型调整lattice = TRUE(线框表格)或stream = TRUE(无框表格)参数。
二、直接提取扫描PDF表格的替代方案
如果转可搜索PDF后提取效果仍不理想,可以跳过转PDF步骤,直接对图片OCR后用R工具整理数据:
- 固定宽度表格用
read.fwf()快速拆分
若表格列宽固定,先观察每行文本的列分隔位置,用固定宽度读取:
# 假设你已有OCR后的原始文本字符对象 raw_text <- readLines("ocr_result.txt") # 或直接用你现有的字符对象 # 定义各列宽度(根据实际表格调整) col_widths <- c(12, 18, 15, 20, -1) # -1表示剩余部分归最后一列 df <- read.fwf(textConnection(raw_text), widths = col_widths, strip.white = TRUE) # 设置列名 colnames(df) <- c("列名1", "列名2", "列名3", "列名4", "列名5")
- 用正则表达式拆分不规则文本
如果列宽不固定但有规律(比如多空格分隔),用dplyr+stringr拆分:
library(dplyr) library(stringr) df <- tibble(raw_line = raw_text) %>% filter(raw_line != "") %>% # 过滤空行 mutate( 列1 = str_extract(raw_line, "^[^\\s]+"), # 提取第一个空格前内容 列2 = str_extract(raw_line, "(?<=^\\S+\\s).+?(?=\\s{2,})"), # 提取连续两个空格前内容 列3 = str_extract(raw_line, "(?<=\\s{2,}).+?(?=\\s{2,})"), 列4 = str_extract(raw_line, "(?<=\\s{2,}).*") ) %>% select(-raw_line) %>% mutate(across(everything(), str_trim)) # 去除多余空格
- 精准裁剪表格区域OCR
若页面包含多余内容,先裁剪图片到表格区域再识别,提升准确率:
img <- image_read(pdf_images[1]) # 取第一页图片 # 裁剪格式:"宽度x高度+左偏移+上偏移",根据实际表格位置调整 cropped_img <- image_crop(img, "500x600+80+150") table_text <- ocr(cropped_img, engine = ocr_engine)
三、处理已有的错乱字符对象
你目前拿到的错乱字符对象,先按换行拆分成向量:text_lines <- str_split(raw_char, "\n")[[1]],再按以下步骤处理:
- 过滤空行和无关说明行;
- 观察每行的重复结构,比如列之间的空格数、固定分隔符号;
- 用上面的
read.fwf()或正则方法拆分列,再逐步清洗异常值。
内容的提问来源于stack exchange,提问作者Ophelia Hanson
相关产品推荐
相关产品推荐

