golang 手动解析 epub 电子书格式

如题,本篇简单分析如何使用go语言解析epub格式的电子书,获取其内部资源内容。

EPUB格式

首先我们需要了解epub格式具有哪些特点。

已知的是,epub是一种类似doc或者pdf,可以提供图文并茂电子书的格式。

那么我们首先使用二进制编辑器打开,看看能收集到哪些信息:

在这里插入图片描述

可以看到是 50 4B (PK) 开头的文件,也就是说,他本身根本就是个 ZIP 压缩文件。

经常上班的朋友都知道,zip格式是比较简单的压缩格式,其文件头部分包含了整篇文件的目录索引。那么我们直接通过压缩软件打开EPUB格式一探究竟。

在这里插入图片描述

非常顺利,我们发现epub就是个zip包,其中的内容大概包括配置文件、html或xml、图片资源等等。
那么我们先使用 golang 读取这个文件及其内容。

解包

首先,我使用 archive/zip 这个库来解包

	// 创建ZIP读取器
	info, _ := file.Stat()
	zipReader, err := zip.NewReader(file, info.Size())
	if err != nil {
		fmt.Println("Error creating ZIP reader:", err)
		return
	}

	// 在内存中存储文本文件内容
	textFiles := make(map[string][]byte)

	for _, zipFile := range zipReader.File {

		var content bytes.Buffer

		// 打开并读取ZIP条目的内容
		rc, err := zipFile.Open()
		if err != nil {
			fmt.Println("Error opening ZIP entry for reading:", err)
			continue
		}
		defer rc.Close()

		_, err = io.Copy(&content, rc)
		if err != nil {
			fmt.Println("Error copying data from ZIP entry:", err)
			continue
		}

		textFiles[zipFile.Name] = content.Bytes()
	}

我将文件路径作为 key,文件内容作为 value 存储到 textFiles 这个 map 中。

定位资源

这里省略逐个文件探索的过程,直接给出解析思路。
在这部分我使用 github.com/PuerkitoBio/goquery 库来解析 xml、html 文件

首先,我们要解析 META-INF/container.xml 这个文件,这个文件应当是整个 epub 的入口。我们来看看这个文件的内容大概是什么样的。

<container xmlns="urn:oasis:names:tc:opendocument:xmlns:container" version="1.0">
<rootfiles>
<rootfile full-path="OPS/content.opf" media-type="application/oebps-package+xml"/>
</rootfiles>
</container>

可以见得,入口文件在 full-path 属性指定了一个后缀为 opf 的文件作为引导,除此之外没有多少有用的信息。其实这个 OPS/content.opf 据我的实践,在大部分情况下都固定是这位置。但我还是建议大家从头解析,因为你不确定你遇到的格式是否遵循主流约定。

以下三步是从头解析,或者你也可以跳过前两步,直接解析 OPS/content.opf 但我不推荐你这样做。

// 使用 go-query 解析 META-INF/container.xml
	metaDoc, metaErr := goquery.NewDocumentFromReader(bytes.NewReader([]byte(textFiles["META-INF/container.xml"])))
	if metaErr != nil {
		log.Printf("读取 META-INF 出错: %v", metaErr)
		//c.JSON(core.RetErr(metaErr.Error()))
		return
	}
// 获取opf文件路径
	confPath, _ := metaDoc.Find("rootfile").Attr("full-path")
// 解析opf文件
	confDoc, confErr := goquery.NewDocumentFromReader(bytes.NewReader([]byte(textFiles[confPath])))
	if confErr != nil {
		log.Printf("读取配置文件 %s 出错: %v", confPath, confErr)
	}

这里我们已经解析了opf文件,实际上,我们通常会看看opf的文件结构是什么样的,这里补充一下吧。opf是纯文本格式,可以直接通过记事本打开。

在这里插入图片描述
红色标注的分别是封面资源、书籍内容资源。注意,这个xml的格式并不规范,这两部分标签应当是平级的。(下方红框处有多余的缩进,这是错误的)

解析内容

在头部的 metadata 标签中,还会提供一些额外的信息,感兴趣的小伙伴可以分析一下。简单看起来包括语言、作者等信息。

//计算 opf 文件的相对路径
	opfPath := confPath[:strings.LastIndex(confPath, "/")+1]
// 解析opf文件
	confDoc, confErr := goquery.NewDocumentFromReader(bytes.NewReader([]byte(textFiles[confPath])))
	if confErr != nil {
		log.Printf("读取配置文件 %s 出错: %v", confPath, confErr)
	}
// 读取作者(如果有的话)
    confDoc.Find("dc\\:creator").Eq(0).Text()

注意,我们核心关注的是,解析 manifest 标签中的内容,该文件会有其他标签容易混淆。例如 spine 标签,其中也有章节结构的,但我们要解析的是 manifest 标签。

// 解析 manifest 标签
confDoc.Find("manifest").Find("item").Each(func(i int, item *goquery.Selection) {
		mediaType, _ := item.Attr("media-type")
		//log.Printf("正在处理第 %d 个章节, href=%s, media-type=%s", i, item.AttrOr("href", ""), mediaType)
	})

我的思路比较懒,因为只关注类型为 html / xml 等内容,所以我判断 media-type 是否以 “ml” 结尾。
小伙伴们可以做一些更复杂的逻辑,例如进一步解析图片、css、或其他内容。

以下demo用于放在上面那段代码的括号中,提供简易的文件解析。
对文件内容的解析,简易的使用 “ * ” 星号一把梭,也就是解析xml中所有文字信息。

	if strings.HasSuffix(mediaType, "ml") {
			//内容页
			chapterDoc, chapterErr := goquery.NewDocumentFromReader(bytes.NewReader(textFiles[opfPath+item.AttrOr("href", "")]))
			if chapterErr != nil {
				log.Printf("读取章节文件 %s 出错: %v", item.AttrOr("href", ""), chapterErr)
			}

			//处理章节内容
			var strBuilder strings.Builder
			chapterDoc.Find("*").Each(func(i int, item *goquery.Selection) {
				strBuilder.WriteString(item.Text())
				strBuilder.WriteString("\n")
			})

			内容字串 := strBuilder.String()

		} else if strings.HasPrefix(mediaType, "image/") {
			imgCover, _ = item.Attr("href")
			//提取图片
			图片文件 := textFiles[opfPath+imgCover]
		}

本篇完

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/899185.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

重学SpringBoot3-集成Hazelcast

重学SpringBoot3-集成Hazelcast 1. Hazelcast 的作用2. Spring Boot 3 整合 Hazelcast 的步骤2.1 添加 Hazelcast 依赖2.2 配置 Hazelcast 实例 3. 集成 Hazelcast 与 Spring Boot 缓存4. 验证 Hazelcast 缓存5. Hazelcast 集群配置6. 总结 Hazelcast 是一个流行的开源内存数据…

Linux重点yum源配置

1.配置在线源 2.配置本地源 3.安装软件包 4.测试yum源配置 5.卸载软件包

浅谈人工智能之基于阿里云使用vllm搭建Llama3

浅谈人工智能之基于阿里云使用vllm搭建Llama3 引言 随着人工智能技术的迅速发展&#xff0c;Llama3作为一个先进的语言模型&#xff0c;受到广泛关注。本文将介绍如何在阿里云上使用VLLM搭建Llama3&#xff0c;为用户提供一套完整的技术流程。 环境准备 阿里云账户 确保您…

记录:网鼎杯2024赛前热身WEB01

目录扫描&#xff0c;发现上传点&#xff0c;判断可能存在文件上传漏洞&#xff0c;并根据文件后缀判断网站开发语言为php 编写蚁剑一句话木马直接上传 蚁剑连接 这里生成 的flag是随机的&#xff0c;因为烽火台反作弊会随机生成环境&#xff0c;在一顿查找后&#xff0c;在hom…

【部署篇】RabbitMq-03集群模式部署

一、准备主机 准备3台主机用于rabbitmq部署&#xff0c;文章中是在centos7上安装部署rabbitmq3.8通过文章中介绍的方式可以同样在centos8、centos9上部署&#xff0c;只需下载对应的版本进行相同的操作。 主机IP角色说明192.168.128.31种子节点192.168.128.32普通节点192.16…

【达梦数据库】两台或多台服务器之间免密登录设置-【dmdba用户】

目录 背景1、服务器A免密登录本机1.1、生成私钥&#xff08;id_rsa&#xff09;和公钥&#xff08;id_rsa.pub&#xff09;1.2、追加公钥到服务器A的密码登录权限管理文件1.3、结果验证 2、服务器A免密登录服务器B2.1、确认服务器B有目的文件夹2.2、服务器A的公钥复制到服务器B…

网安加·百家讲坛 | 徐一丁:金融机构网络安全合规浅析

作者简介&#xff1a;徐一丁&#xff0c;北京小西牛等保软件有限公司解决方案部总监&#xff0c;网络安全高级顾问。2000年开始从事网络安全工作&#xff0c;主要领域为网络安全法规标准研究、金融行业安全咨询与解决方案设计、信息科技风险管理评估等。对国家网络安全法规标准…

react18中的合成事件与浏览器中的原生事件

React 通过将事件 normalize 以让他们在不同浏览器中拥有一致的属性。 合成事件 SyntheticEvent 实例将被传递给你的事件处理函数&#xff0c;它是浏览器的原生事件的跨浏览器包装器。除兼容所有浏览器外&#xff0c;它还拥有和浏览器原生事件相同的接口&#xff0c;包括 stopP…

项目文章 | 药学TOP期刊PRChIP-seq助力揭示激酶LIMK2促进梗死不良重构的机制

急性心肌梗死&#xff08;MI&#xff09;是全球死亡的主要原因&#xff0c;尽管MI的死亡率有所下降&#xff0c;缺血性心力衰竭的发病率却呈上升趋势。这一现象提示我们&#xff0c;尽管在急救和治疗急性心肌梗死方面取得了进展&#xff0c;但心脏在梗死后的长期功能恢复仍然是…

Pr 视频效果:自动重构

视频效果/变换/自动重构 Transform/Auto Reframe 自动重构 Auto Reframe效果是用于快速调整视频素材以适应不同长宽比的一项强大工具。 随着各种平台和设备的多样化&#xff0c;视频内容需要适应不同的屏幕尺寸和比例&#xff0c;如 16:9&#xff08;横屏&#xff09;、9:16&am…

「Qt Widget中文示例指南」如何实现半透明背景?

Qt 是目前最先进、最完整的跨平台C开发工具。它不仅完全实现了一次编写&#xff0c;所有平台无差别运行&#xff0c;更提供了几乎所有开发过程中需要用到的工具。如今&#xff0c;Qt已被运用于超过70个行业、数千家企业&#xff0c;支持数百万设备及应用。 本文将为大家展示如…

新鲜出炉,ECCV2024.9.25 首次提出基于 YOLO 目标检测的无源域自适应

原文标题&#xff1a;Source-Free Domain Adaptation for YOLO Object Detection 中文标题&#xff1a;基于 YOLO 目标检测的无源域自适应 论文地址&#xff1a; https://arxiv.org/abs/2409.16538 代码地址&#xff1a; GitHub - vs-cv/sf-yolo 1、Abstract 无源域自适应&…

单细胞 | 转录因子足迹分析

数据加载 在本案例中&#xff0c;将采用之前在轨迹构建案例中已经介绍并处理过的数据集。 library(Signac)library(Seurat)bone <- readRDS("cd34.rds")DimPlot(bone, label TRUE) 要执行足迹分析&#xff0c;必须首先向对象中添加Motif 信息&#xff0c;这包括每…

微软发布 Win11 22H2/23H2 十月可选更新KB5044380!

系统之家于10月23日发出最新报道&#xff0c;微软针对Win11 22H2和23H2用户&#xff0c;发布了10月可选更新KB5044380&#xff0c;用户安装后版本号升至22621.4391和22631.4391。本次更新开始推出屏幕键盘的新游戏板键盘布局&#xff0c;支持用户使用Xbox控制器在屏幕上移动和键…

Burp Suite基本介绍

Burp Suite基本介绍 官网&#xff1a;https://portswiggernet Burp的作用 目标: 用于渗透测试&#xff0c;发现漏洞手段:拦截HTTP数据、对数据进行分析和处理&#xff0c;漏洞扫描场景:测试SQL注入、文件上传、XSS、CSRF、FUZZ、重放攻击、密码暴破、爬取数据、逻辑漏洞... …

Spring Boot论坛网站:安全特性与性能优化

4系统概要设计 4.1概述 本系统采用B/S结构(Browser/Server,浏览器/服务器结构)和基于Web服务两种模式&#xff0c;是一个适用于Internet环境下的模型结构。只要用户能连上Internet,便可以在任何时间、任何地点使用。系统工作原理图如图4-1所示&#xff1a; 图4-1系统工作原理…

word取消自动单词首字母大写

情况说明&#xff1a;在word输入单词后首字母会自动变成大写 &#xff08;1&#xff09;点击菜单栏文件 &#xff08;2&#xff09;点击“更多”——>“选项” &#xff08;3&#xff09;点击“校对”——>“自动更正选项” &#xff08;4&#xff09;取消“句首字母大写…

ubuntu22 安装labelimg制作自己的深度学习目标检测数据集

参考文章&#xff1a;目标检测---利用labelimg制作自己的深度学习目标检测数据集-CSDN博客 以上文章是windows下使用的方法&#xff0c;本章是在ubuntu22下使用的方法 一、准备工作 确保您的Ubuntu系统已安装Python 3.7或更高版本。可以通过在终端输入 python3 --version 来检…

kafka消息队列

kafka消息队列 什么是消息队列消息队列的应用场景异步处理应用耦合限流削峰消息驱动的系统 消息队列的两种模式点对点模式发布/订阅模式 常用的消息队列介绍PulsarPulsar 的特性Pulsar 存储架构Pulsar 消息消费 Kafka与Pulsar对比Pulsar 的主要优势&#xff1a;&#xff08;Pre…

海报在线制作系统小程序源码

海报在线制作系统小程序源码&#xff0c;是一款集功能性、实用性与便捷性于一体的创新工具。该小程序源码专为满足用户快速、高效制作各类海报的需求而设计&#xff0c;无需专业的设计技能或复杂的软件操作&#xff0c;即可轻松上手。 在功能性方面&#xff0c;这款海报小程序…