如何使用Golang像Camelot Python一样从PDF中提取表格
如何使用Golang像Camelot Python一样从PDF中提取表格 如何像 Python 的 Camelot 库一样从 PDF 中提取表格。
2 回复
嗨,@packs,经过一番搜索,我未能找到一个Go社区普遍喜欢的Go PDF库;我建议你通过调用Python子进程、嵌入libpython或其他一些机制,来配合Camelot获取你所需的功能。
也许这里的其他人会有更好的建议 ¯\_(ツ)_/¯
更多关于如何使用Golang像Camelot Python一样从PDF中提取表格的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在Golang中从PDF提取表格可以使用以下两种主要方法:
1. 使用unipdf库(推荐)
package main
import (
"fmt"
"log"
"github.com/unidoc/unipdf/v3/extractor"
"github.com/unidoc/unipdf/v3/model"
)
func extractTablesFromPDF(pdfPath string) {
// 打开PDF文件
f, err := os.Open(pdfPath)
if err != nil {
log.Fatal(err)
}
defer f.Close()
// 创建PDF阅读器
pdfReader, err := model.NewPdfReader(f)
if err != nil {
log.Fatal(err)
}
// 获取页数
numPages, err := pdfReader.GetNumPages()
if err != nil {
log.Fatal(err)
}
// 遍历每一页
for pageNum := 1; pageNum <= numPages; pageNum++ {
page, err := pdfReader.GetPage(pageNum)
if err != nil {
log.Fatal(err)
}
// 创建提取器
ex, err := extractor.New(page)
if err != nil {
log.Fatal(err)
}
// 提取文本
text, err := ex.ExtractText()
if err != nil {
log.Fatal(err)
}
// 这里需要实现表格检测逻辑
// unipdf不直接提供表格提取,需要基于文本位置分析
fmt.Printf("Page %d:\n%s\n", pageNum, text)
}
}
2. 使用gofpdf和自定义表格检测
package main
import (
"fmt"
"strings"
"github.com/jung-kurt/gofpdf"
)
type TableCell struct {
Text string
X, Y float64
Width float64
Height float64
}
func detectTablesFromText(text string, positions []TableCell) [][]string {
// 简单的表格检测算法示例
var tables [][]string
// 按行分割
lines := strings.Split(text, "\n")
// 检测表格特征(如对齐的列、分隔线等)
for i, line := range lines {
// 检查是否为表格行(包含多个制表符或连续空格)
if strings.Count(line, " ") > 2 || strings.Contains(line, "\t") {
// 分割单元格
cells := strings.Fields(line)
tables = append(tables, cells)
fmt.Printf("检测到表格行 %d: %v\n", i+1, cells)
}
}
return tables
}
// 使用正则表达式提取表格数据
func extractWithRegex(text string) {
// 匹配表格模式
re := regexp.MustCompile(`(\S+\s+){2,}\S+`)
matches := re.FindAllString(text, -1)
for _, match := range matches {
fmt.Printf("疑似表格行: %s\n", match)
}
}
3. 结合外部工具(Tabula)
package main
import (
"os/exec"
"encoding/csv"
"io"
"fmt"
)
func extractWithTabula(pdfPath, outputPath string) error {
// 调用Tabula命令行工具
cmd := exec.Command("java", "-jar", "tabula.jar",
pdfPath,
"--pages", "all",
"--format", "CSV",
"--output", outputPath)
output, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("tabula执行失败: %v\n输出: %s", err, output)
}
// 读取CSV结果
file, err := os.Open(outputPath)
if err != nil {
return err
}
defer file.Close()
reader := csv.NewReader(file)
for {
record, err := reader.Read()
if err == io.EOF {
break
}
if err != nil {
return err
}
fmt.Printf("表格行: %v\n", record)
}
return nil
}
4. 完整的表格提取示例
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
type PDFTableExtractor struct {
MinColSpacing float64
MinRowSpacing float64
}
func (e *PDFTableExtractor) Extract(pdfPath string) ([][][]string, error) {
// 读取PDF文本内容
text, err := e.extractTextFromPDF(pdfPath)
if err != nil {
return nil, err
}
// 检测表格结构
tables := e.detectTables(text)
return tables, nil
}
func (e *PDFTableExtractor) detectTables(text string) [][][]string {
var tables [][][]string
var currentTable [][]string
scanner := bufio.NewScanner(strings.NewReader(text))
inTable := false
for scanner.Scan() {
line := scanner.Text()
// 简单的表格检测逻辑
if e.isTableRow(line) {
if !inTable {
inTable = true
currentTable = [][]string{}
}
cells := e.parseTableRow(line)
currentTable = append(currentTable, cells)
} else {
if inTable && len(currentTable) > 0 {
tables = append(tables, currentTable)
inTable = false
}
}
}
return tables
}
func (e *PDFTableExtractor) isTableRow(line string) bool {
// 检测是否为表格行的启发式规则
trimmed := strings.TrimSpace(line)
if len(trimmed) == 0 {
return false
}
// 检查是否有多个连续空格或制表符
spaceCount := strings.Count(line, " ")
tabCount := strings.Count(line, "\t")
return spaceCount >= 2 || tabCount >= 1
}
func (e *PDFTableExtractor) parseTableRow(line string) []string {
// 使用正则表达式或自定义逻辑分割单元格
// 这里使用简单的空格分割
return strings.Fields(line)
}
Golang目前没有直接等同于Camelot的库,上述方法提供了不同的实现途径。对于复杂的PDF表格,建议结合多种方法或考虑使用外部工具。

