Golang调用Apache Tika服务解析PDF文档的示例教程
本文档将详细介绍如何使用github.com/google/go-tika/tika库来处理PDF文档。内容包括tika-server-standard-2.1.0.jar的介绍、下载、启动方法,端口检测,以及如何通过Go语言调用服务上传PDF文件并接收返回的文本内容。
1. Apache Tika简介
Apache Tika是一个内容提取工具,可以从各种文档格式中提取文本和元数据。Tika Server是Tika的服务器版本,可以通过HTTP API进行调用。go-tika是Google提供的Go语言客户端库,用于与Tika Server进行交互。
1.1 tika-server-standard-2.1.0.jar介绍
tika-server-standard-2.1.0.jar是Apache Tika 2.1.0版本的服务端程序,提供了RESTful API接口,允许通过HTTP请求来处理各种文档格式。在本项目中,我们使用这个版本来解析PDF文档。
1.2 下载tika-server-standard-2.1.0.jar
可以从Apache Tika官网或镜像站点下载tika-server-standard-2.1.0.jar文件:
https://archive.apache.org/dist/tika/2.1.0/tika-server-standard-2.1.0.jar
在本项目中,该文件已经包含在java-1.8.0目录中。
2. 启动Tika服务
2.1 通过命令行启动Tika服务
要启动Tika服务,需要确保系统已安装Java 8或更高版本。然后在命令行中执行以下命令:
java -jar tika-server-standard-2.1.0.jar
在本项目中,可以通过以下命令启动:
java -jar java-1.8.0/tika-server-standard-2.1.0.jar
默认情况下,Tika服务会在本地9998端口启动。
2.2 在Go程序中启动Tika服务
项目中提供了通过Go程序启动Tika服务的方法:
package main
import (
"fmt" // 用于格式化输出
"os" // 用于操作系统相关功能
"os/exec" // 用于执行外部命令
"path/filepath" // 用于处理文件路径
"time" // 用于时间处理
)
// startTikaServer 通过Java命令启动Tika服务
// 该函数会获取当前目录,构造Java命令并执行启动Tika服务
func startTikaServer() {
// 获取当前工作目录的绝对路径
// filepath.Abs函数会返回指定路径的绝对路径
dir, _ := filepath.Abs(`.`)
// 构造启动Tika服务的命令字符串
// 使用项目中自带的Java运行时和Tika服务jar包
cmdStr := dir + "/java-1.8.0/jre/bin/java -jar " + dir + "/java-1.8.0/tika-server-standard-2.1.0.jar"
// 打印将要执行的命令,便于调试
fmt.Println(cmdStr)
// 使用exec.Command创建一个命令对象
// cmd.exe是Windows命令行解释器
// /c参数表示执行完命令后关闭命令行窗口
// start参数用于在新窗口中启动程序
c := exec.Command("cmd.exe", "/c", "start "+cmdStr)
// 执行命令,如果出错则打印错误信息
if err := c.Run(); err != nil {
fmt.Println("Error: ", err)
}
// 等待一段时间确保服务启动完成
time.Sleep(10 * time.Second)
}
3. 端口检测
在启动Tika服务之前,我们需要检测Tika服务端口(默认9998)是否已经被占用。
package main
import (
"fmt" // 用于格式化输出
"net" // 用于网络操作
"time" // 用于时间处理
)
// IsPortInUse 检查指定端口是否被占用
// 参数:
// - port: 要检查的端口号
// 返回值:
// - bool: 如果端口被占用返回true,否则返回false
func IsPortInUse(port string) bool {
// 使用net.DialTimeout尝试连接到指定端口
// 参数说明:
// - "tcp": 使用TCP协议
// - port: 目标地址和端口,格式为"host:port"
// - 3*time.Second: 连接超时时间设置为3秒
conn, err := net.DialTimeout("tcp", port, 3*time.Second)
// 如果连接出错,说明端口未被占用
if err != nil {
return false
}
// 如果连接成功,关闭连接并返回true
if conn != nil {
conn.Close()
return true
}
// 默认返回false
return false
}
// CheckTikaServerPort 检查Tika服务端口是否可用
// 如果端口不可用,则启动Tika服务
func CheckTikaServerPort() {
// 定义Tika服务的默认端口
port := "127.0.0.1:9998"
// 获取当前时间并格式化,用于日志输出
now := time.Now().Format("2006-01-02 15:04:05")
// 检查端口是否被占用
conn, err := net.DialTimeout("tcp", port, 3*time.Second)
// 如果连接出错,说明端口未开启
if err != nil {
// 打印端口未开启的信息
fmt.Println("["+now+"]", port, "端口未开启(fail)!")
// 打印正在启动端口的信息
fmt.Println("["+now+"]", port, "端口正在启动,请稍后...")
// 调用startTikaServer函数启动Tika服务
startTikaServer()
// 等待20秒确保服务启动完成
time.Sleep(20 * time.Second)
// 打印端口已开启的信息
fmt.Println("["+now+"]", port, "端口已开启(success)!")
} else {
// 如果连接成功,说明端口已开启
if conn != nil {
// 打印端口已开启的信息
fmt.Println("["+now+"]", port, "端口已开启(success)!")
// 关闭连接
conn.Close()
} else {
// 如果连接对象为空,打印端口未开启的信息
fmt.Println("["+now+"]", port, "端口未开启(fail)!")
}
}
}
4. 使用go-tika库解析PDF文档
4.1 导入必要的包
package main
import (
"context" // 用于控制请求的上下文
"fmt" // 用于格式化输出
"log" // 用于记录日志
"os" // 用于文件操作
// 导入go-tika库,用于与Tika服务交互
"github.com/google/go-tika/tika"
)
4.2 创建Tika客户端并解析PDF
// readPdfTika 使用Tika服务解析PDF文件
// 参数:
// - pdfFileName: PDF文件的路径
// 返回值:
// - string: 解析后的文本内容
// - error: 错误信息(如果有)
func readPdfTika(pdfFileName string) (string, error) {
// 打开指定路径的PDF文件
// os.Open函数会返回一个文件对象和可能的错误信息
f, err := os.Open(pdfFileName)
// 如果打开文件时出错,记录错误日志并返回
if err != nil {
log.Fatal(err)
return "", err
}
// 使用defer确保在函数结束时关闭文件
// defer语句会延迟执行,确保即使出现错误也能正确关闭文件
defer f.Close()
// 打印正在处理的文件名
fmt.Println(f.Name())
// 创建Tika客户端
// 第一个参数是HTTP客户端,传入nil表示使用默认的HTTP客户端
// 第二个参数是Tika服务的地址,这里使用本地9998端口
client := tika.NewClient(nil, "http://localhost:9998")
// 调用Tika服务解析PDF文件
// client.Parse方法会向Tika服务发送解析请求
// context.Background()提供一个空的上下文
// f是之前打开的文件对象
body, err := client.Parse(context.Background(), f)
// 打印网络错误信息(如果有的话)
fmt.Printf("->网络错误:%v\n", err)
// 打印解析结果
fmt.Println(body)
// 返回解析结果和错误信息
return body, err
}
4.3 完整的使用示例
func main() {
// 检查Tika服务端口,如果未开启则启动服务
CheckTikaServerPort()
// 指定要解析的PDF文件路径
pdfFile := "example.pdf"
// 调用readPdfTika函数解析PDF文件
content, err := readPdfTika(pdfFile)
// 检查是否有错误
if err != nil {
// 如果有错误,打印错误信息
fmt.Printf("解析PDF文件时出错: %v\n", err)
return
}
// 打印解析结果
fmt.Println("PDF文件解析结果:")
fmt.Println(content)
}
5. 高级用法
5.1 使用Tika客户端的其他方法
go-tika库还提供了其他有用的方法:
// 使用Meta方法提取文档元数据
meta, err := client.Meta(context.Background(), f)
if err != nil {
log.Fatal(err)
}
fmt.Println("文档元数据:", meta)
// 使用Detect方法检测文档类型
mimeType, err := client.Detect(context.Background(), f)
if err != nil {
log.Fatal(err)
}
fmt.Println("文档类型:", mimeType)
// 使用Language方法检测文档语言
language, err := client.Language(context.Background(), content)
if err != nil {
log.Fatal(err)
}
fmt.Println("文档语言:", language)
5.2 处理解析结果
通常需要对Tika返回的文本进行进一步处理:
// 处理解析结果,去除多余空白字符
func processParsedContent(content string) string {
// 将换行符替换为分号,便于后续处理
content = strings.Replace(content, "\r\n", ";", -1)
// 去除HTML标签
re := regexp.MustCompile(`<[^>]*>`)
content = re.ReplaceAllString(content, "")
// 去除多余空格
content = strings.TrimSpace(content)
return content
}
6. 总结
通过本教程,我们学习了如何:
- 了解Apache Tika和go-tika库的基本概念
- 下载和启动Tika服务
- 在Go程序中检测端口并自动启动Tika服务
- 使用go-tika库解析PDF文档
- 处理解析结果
go-tika库提供了一种简单而有效的方式来处理各种文档格式,特别适用于需要从PDF等复杂文档中提取文本的场景。在本项目中,这个功能被用于解析各种类型的PDF看板文件,提取其中的关键信息。