(这可能是一个XY问题,更多关于上下文的信息在最后)
有没有什么方法可以根据章节标题以编程方式拆分 pdf?那是
从此 pdf 中生成 2 个 pdf,其中一个包含直到“XY”部分的所有内容,第二个包含其余所有内容。
我知道如何根据页码分割 PDF,但是还有更多“语义”可用的吗?
(简而言之,最初的问题是:NSF 希望在一个文档中包含参考文献列表,在另一个文档中包含描述,并且由于我使用 LaTeX / pandoc 来生成我的文档,因此将所有内容都包含在 1 个文档中然后再使用会更简单显然,链接并不重要。)
答案1
我喜欢用于pdftk
此类工作。
如果我使用 Latex 创建一个基本文档,它可能如下所示:
\documentclass{report}
\usepackage{blindtext} % For lorem ipsum text
\usepackage{hyperref} % Turns chapters/sections into bookmarks
\begin{document}
\chapter{First Chapter}
\Blindtext[10]
\section{Subsection of chapter 1}
\Blindtext[3]
\chapter{Second Chapter}
\Blindtext[20]
\chapter{Third Chapter}
\Blindtext
\pdfbookmark{Example bookmark}{A}
\Blindtext
\end{document}
当我运行它时pdflatex
,它会生成一个 13 页的 PDF,其中每个章节都有自动书签、第 1.1 节的深度书签、稍后的手动书签以及许多 lorem ipsum 段落。
现在我们有了一个 pdf 文件,我们可以用它pdftk
来获得一些关于它的见解。数据很多,所以我将其缩减为有趣的部分。
$ pdftk sample.pdf dump_data
InfoBegin
...
NumberOfPages: 13
BookmarkBegin
BookmarkTitle: First Chapter
BookmarkLevel: 1
BookmarkPageNumber: 1
BookmarkBegin
BookmarkTitle: Subsection of chapter 1
BookmarkLevel: 2
BookmarkPageNumber: 3
BookmarkBegin
BookmarkTitle: Second Chapter
BookmarkLevel: 1
BookmarkPageNumber: 5
BookmarkBegin
BookmarkTitle: Third Chapter
BookmarkLevel: 1
BookmarkPageNumber: 11
BookmarkBegin
BookmarkTitle: Example bookmark
BookmarkLevel: 1
BookmarkPageNumber: 12
PageMediaBegin
...
当我们点击BookmarkBegin
标签时,我们就知道我们有一个书签。当我们看到时,BookmarkTitle: X
我们知道我们已经到达了部分X
。BookmarkPageNumber:
每个书签都有一个关联的书签。您可以将其用于您的拆分。您还可以使用BookmarkLevel
来过滤您想要拆分的级别(章节、部分、小节)。
假设您想在第 1 章和第 2 章之间进行拆分。从数据中我们可以看到,我们需要在第 4 页之前添加拆分:
BookmarkTitle: Second Chapter
BookmarkPageNumber: 5
现在我们有了页码,我们可以用来pdftk
进行分割。这实际上涉及到cat
在特定页面上使用:
pdftk sample.pdf cat 1-4 output sample-1.pdf
pdftk sample.pdf cat 5-end output sample-2.pdf
让我们采用更通用的方法,并将其编写为名为 .pdf 的 pdf 脚本sample.pdf
。让我们在每个高级书签处拆分 PDF(过滤掉该部分)。
首先,让我们将书签标签转换为更易于解析的格式,我们可以在其中写入一些内容awk
(我将其另存为parser.awk
)
#!/bin/awk -f
BEGIN {
FS=": "
OFS=";"
}
/^BookmarkBegin/ {
if (this_level > 1) { # Only handle high-level sections
next
}
if (this_page == "" || this_title == ""){
next
}
if (last_page != "" && last_title != "") {
print last_title, last_page, this_page-1
}
last_title=this_title
last_page=this_page
this_title=this_page=this_level=""
}
/^BookmarkTitle:/ {
this_title=$2
}
/^BookmarkPageNumber:/ {
this_page=$2
}
/^BookmarkLevel:/ {
this_level=$2
}
END {
print last_title, last_page, this_page-1
print this_title, this_page, "end"
}
在这里,我假设标题不包含 a ;
,因此我使用它作为输出分隔符。该脚本输出:
- 每个部分的名称
- 该部分的首页
- 本节的最后一页。
$ pdftk sample.pdf dump_data | awk -f parser.awk
First Chapter;1;4
Second Chapter;5;10
Third Chapter;11;11
Example bookmark;12;end
现在让我们迭代每一行并pdftk
在 bash 中调用它:
#!/bin/bash
sequence=1
pdftk sample.pdf dump_data | awk -f parser.awk | \
while IFS=";" \
read -r title start end
do
pdftk sample.pdf cat "$start"-"$end" output sample-$sequence-"$title".pdf
sequence=$((sequence+1))
done
这给你留下了以下内容:
$ ls *.pdf
'sample-1-First Chapter.pdf'
'sample-2-Second Chapter.pdf'
'sample-3-Third Chapter.pdf'
'sample-4-Example bookmark.pdf'
sample.pdf
这样做的一个限制是,当同一页面上有多个书签或书签很少时,它会有点混乱。
答案2
去年我使用了 python 库py_pdf_parser
并实现了类似的目标。pdfplumber
最重要的是,我使用 MathPix API(付费但费用最低)来完成到乳胶的最终转换。
您可以在此处查看我的脚本,看看它是否有帮助:https://github.com/sekerez/linear_algebra_done_right/blob/main/problems/extract_problems_from_pdf_book.py该脚本提取了书中的所有问题,并根据练习编号和问题编号将它们整齐地组织在数据结构中。令人惊奇的是,仅使用几行代码就可以做到这一点。
您必须根据您的用例调整脚本。由于每个 PDF 都非常不同,因此机器处理 PDF 非常困难。因此,您需要根据 PDF 格式手工制作自己的脚本。
答案3
斯图尔特的回答给了我几乎所有的工具,但我对他们的解决方案做了两个重要的编辑:
- 使用相干pdf保留目录(pdftk只需将其删除),
- 使命令将文件分成两部分,而不是将文件分成与章节一样多的文件。
重新使用parser.awk
Stewarts 共享的内容,假设调用了源代码source.pdf
,并且我们要用来分割文档的章节称为“附录”,这给出了:
pdftk source.pdf dump_data | \
awk -f parser.awk | \
grep Appendix | \
{
IFS=";" ; \
read -r title start end; \
./cpdf source.pdf 1-"`expr $start - 1`" -o A.pdf; \
./cpdf source.pdf "$start"-"$end" -o B.pdf;
}
这
- 转储文件的元数据,
- 提取相关位 (
title ; page start ; page ends
), - 抓住附录的相关部分,
- 将分隔符设置
read
为;
- 将标题存储在
title
变量中,将起始页存储在 中start
,将结束页存储在 中end
, start - 1
将从 1 到(对应于附录开始之前的页面)的所有页面输出到名为 的文件中A.pdf
,- 将文档的其余部分输出到名为
B.pdf
.