Elastic进阶教程:生成离线pdf文档

2022-11-21 10:41:02 浏览数 (1)

前言

之前写过一篇如何生成离线官方文档的文章,但也有社区伙伴反馈说,是不是能够导出一个pdf格式的离线文档。

将html转换成pdf,网上有非常多的工具。但这个事情最大的难点在于:一份官方文档是以book的形式组织的。包含多个子页面,通过目录和链接进行跳转。而现有的工具只能将单页的html转换为pdf。

以elasticsearch的官方文档为例,里面包含了7000多个子页面,根据目录,通过rul进行跳转的方式。

es_toc.gifes_toc.gif

因此,要想将所有内容都导出到一个pdf文件中,需要解决核心的问题是把原先文档的book的组织形式,变成一个“大宽表” —— 把内容都组织在一个页面上,才能够利用工具将其转换。

因此,整个任务拆分三个部分:

  • 生成单页的官方文档
  • 确保单页文档的格式和内容的正确
  • 将单页文档变成Pdf

生成单页的官方文档

Elastic的文档团队通过build_docs工具进行文档的构建:

代码语言:txt复制
git clone https://github.com/elastic/docs.git

可以通过阅读README.md了解该怎么使用这个软件。

HTML格式文档的构建方法:

Elastic Stack中,不同的软件、不同的版本,其文档的路径和依赖的资源有不同,因此,调用的命令也不一样。

关于各个产品文档的构建方式,可以参考项目里提供的这个构建脚本:https://github.com/elastic/docs/blob/master/doc_build_aliases.sh。了解不同文档的构建方法,以elasticsearch为例:

代码语言:txt复制
#    export GIT_HOME="/<fullPathTYourRepos>"
#    source $GIT_HOME/docs/doc_build_aliases.sh
#

# Elasticsearch
alias docbldesx='$GIT_HOME/docs/build_docs --doc $GIT_HOME/elasticsearch/docs/reference/index.asciidoc --resource=$GIT_HOME/elasticsearch/x-pack/docs/ --chunk 1'

alias docbldes=docbldesx

# Elasticsearch 6.2 and earlier

alias docbldesold='$GIT_HOME/docs/build_docs --doc $GIT_HOME/elasticsearch/docs/reference/index.x.asciidoc --resource=$GIT_HOME/elasticsearch-extra/x-pack-elasticsearch/docs/ --chunk 1'

在这里,要正确构建elasticsearch,需要提供--resource参数来指向一些存储于其他目录的资源,比如这里的x-pack目录。而6.2及之前的版本,由于目录组织形式,以及文件的差异,命令上有细微的差异。这里的--chunk,表示的以多细的颗粒度进行html页面的拆分,1 表示以章节为单位进行拆分。

我们可以通过帮助命令得知:

代码语言:txt复制
INFO:build_docs:    Build local docs:
INFO:build_docs:
INFO:build_docs:        build_docs --doc path/to/index.asciidoc [opts]
INFO:build_docs:
INFO:build_docs:        Opts:
INFO:build_docs:          --chunk 1         Also chunk sections into separate files
INFO:build_docs:          --alternatives <source_lang>:<alternative_lang>:<dir>
INFO:build_docs:                            Examples in alternative languages.
INFO:build_docs:          --lang            Defaults to 'en'
INFO:build_docs:          --lenient         Ignore linking errors
INFO:build_docs:          --out dest/dir/   Defaults to ./html_docs.
INFO:build_docs:          --resource        Path to image dir - may be repeated
INFO:build_docs:          --respect_edit_url_overrides
INFO:build_docs:                            Respects `:edit_url:` overrides in the book.
INFO:build_docs:          --single          Generate a single HTML page, instead of
INFO:build_docs:                            a chunking into a file per chapter
INFO:build_docs:          --suppress_migration_warnings
INFO:build_docs:                            Suppress warnings about Asciidoctor migration
INFO:build_docs:                            issues. Use this when building "old" branches.
INFO:build_docs:          --toc             Include a TOC at the beginning of the page.
INFO:build_docs:          --private         Indicate that the github repo is private.
INFO:build_docs:        WARNING: Anything in the `out` dir will be deleted!
INFO:build_docs:
INFO:build_docs:    Build docs from all repos in conf.yaml:
INFO:build_docs:
INFO:build_docs:        build_docs --all [opts]
INFO:build_docs:
INFO:build_docs:        Opts:
INFO:build_docs:          --keep_hash       Build docs from the same commit hash as last time
INFO:build_docs:          --linkcheckonly   Skips the documentation builds. Checks links only.
INFO:build_docs:          --push            Commit the updated docs and push to origin
INFO:build_docs:          --announce_preview <host>
INFO:build_docs:                            Causes the build to log a line about where to find
INFO:build_docs:                            a preview of the build if anything is pushed.
INFO:build_docs:          --rebuild         Rebuild all branches of every book regardless of
INFO:build_docs:                            what has changed
INFO:build_docs:          --reference       Directory of `--mirror` clones to use as a
INFO:build_docs:                            local cache
INFO:build_docs:          --repos_cache     Directory to which working repositories are cloned.
INFO:build_docs:                            Defaults to `<script_dir>/.repos`.
INFO:build_docs:          --skiplinkcheck   Omit the step that checks for broken links
INFO:build_docs:          --sub_dir         Use a directory as a branch of some repo
INFO:build_docs:                            (eg --sub_dir elasticsearch:master:~/Code/elasticsearch)
INFO:build_docs:          --target_repo     Repository to which to commit docs
INFO:build_docs:          --target_branch   Branch to which to commit docs
INFO:build_docs:          --user            Specify which GitHub user to use, if not your own
INFO:build_docs:
INFO:build_docs:    General Opts:
INFO:build_docs:          --asciidoctor     Emit a happy message.
INFO:build_docs:          --conf <ymlfile>  Use your own configuration file, defaults to the
INFO:build_docs:                            bundled conf.yaml
INFO:build_docs:          --direct_html     Emit a happy message.
INFO:build_docs:          --in_standard_docker
INFO:build_docs:                            Specified by build_docs when running in
INFO:build_docs:                            its container
INFO:build_docs:          --open            Open the docs in a browser once built.
INFO:build_docs:          --procs           Number of processes to run in parallel, defaults
INFO:build_docs:                            to 3
INFO:build_docs:          --verbose         Output more logs

增加--single参数,我们可以将整个文档打包到单一的HTML文件当中。接下来我们将elasticsearch文档为例,选择性的生成一个7.10的文档

获取官方文档原文

而我们需要编译的文档存在于各个项目中。

以elasticsearch为例:

  • 地址:https://github.com/elastic/elasticsearch.git
  • 路径:elasticsearch/docs/reference/

获取特定版本的官方文档

通过以下命令,获取elasticsearch的源码:

代码语言:txt复制
git clone https://github.com/elastic/elasticsearch.git
cd elasticsearch
# 获取正确的tag名称
git branch -a 
git checkout -b test remotes/origin/7.10

构建单页文档

通过以下命令构建:

代码语言:txt复制
./build_docs --doc /apps/elasticsearch/docs/reference/index.asciidoc --resource=/apps/elasticsearch/x-pack/docs/ --single --open

构建完成后,默认将在html_docs目录下生成html文件。如下,只有一个index.html文件:

代码语言:txt复制
/apps/docs/html_docs$ tree -L 2
.
└── raw
    ├── images
    ├── index.html
    ├── monitoring
    ├── security
    ├── setup
    └── snippets

该index.html文件有13M大小,包含了所有的页面,而对于图片和代码片段的一些引用,则分布在其他文件夹中:

代码语言:txt复制
drwxr-xr-x 15 lex lex 4.0K Aug 16 00:26 images
-rw-r--r--  1 lex lex  13M Aug 16 00:26 index.html
drwxr-xr-x  3 lex lex 4.0K Aug 16 00:26 monitoring
drwxr-xr-x  4 lex lex 4.0K Aug 16 00:26 security
drwxr-xr-x  3 lex lex 4.0K Aug 16 00:26 setup
drwxr-xr-x  2 lex lex  68K Aug 16 00:26 snippets

直接在浏览器中打开该文件,我们会发现文档是合并了,但缺失了格式:

image.pngimage.png

因此,在转换成pdf之前,我们还需要解决格式的问题

确保单页文档的格式和内容的正确

build_doc生成的这个单页的HTML的源码是这样的:

代码语言:html复制
<!DOCTYPE html>
<html>
  <head>    
    <meta charset="UTF-8">
    <title>Elasticsearch Guide [7.10] | Elastic</title>
    <link rel="home" href="index.html" title="Elasticsearch Guide [7.10]"/>
    <link rel="next" href="elasticsearch-intro.html" title="What is Elasticsearch?"/>
    <meta name="DC.type" content="Learn/Docs/Elasticsearch/Reference/7.10"/>
    <meta name="DC.subject" content="Elasticsearch"/>
    <meta name="DC.identifier" content="7.10"/>
    <meta name="robots" content="noindex,nofollow"/>
  </head>
<body>
<div class="book" lang="en" id="content">
<div class="titlepage">
<div class="breadcrumbs" id="title-page-breadcrumb">
<span class="breadcrumb-link"><a href="/guide/">Elastic Docs</a></span>
</div>
<div>
<div><h1 class="title"><a id="elasticsearch-reference"></a>Elasticsearch Guide</h1></div>
</div>
<hr>
<!--EXTRA-->
</div>
<div id="content">
<div class="chapter">
<div class="titlepage"><div><div>
<h1 class="title"><a id="elasticsearch-intro"></a>What is Elasticsearch?</h1>

可以看到,在<head>中并没有css。第一步,我们需要添加对应的css文件。我们可以用原先的命令,去掉--single参数,重新生成一个多页的文档:

代码语言:txt复制
./build_docs --doc /apps/elasticsearch/docs/reference/index.asciidoc --resource=/apps/elasticsearch/x-pack/docs/ --open

参考文件里的内容,添加ccs:

代码语言:html复制
<link rel="stylesheet" type="text/css" href="/guide/static/styles.css" />

而ccs,可以直接从打开的网站上提取资源,也可以在这个网址:https://github.com/elastic/built-docs/tree/master/html/static获取

但是光添加css是不够的,还需要有一个正确的渲染映射:

代码语言:html复制
  <body>
<div class="book" lang="en" id="content">
<div class="titlepage">
<div class="breadcrumbs" id="title-page-breadcrumb">
<span class="breadcrumb-link"><a href="/guide/">Elastic Docs</a></span>
</div>
<div>
<div><h1 class="title"><a id="elasticsearch-reference"></a>Elasticsearch Guide</h1></div>
</div>
<hr>
<!--EXTRA-->
</div>
<div id="content">
<div class="chapter">
<div class="titlepage"><div><div>

在body里面,为了能够正确渲染,需要在<div id="content">之前, 加入如下代码:

代码语言:txt复制
    <div class="main-container">
      <section id="content" >
        <div class="content-wrapper">

          <section id="guide" lang="en">
            <div class="container">

单页html将正确应用和官网一样格式:

es_one_page.gifes_one_page.gif

将单页文档变成Pdf

到这里,我们已经完成了将近80%的工作。将单页html转换成pdf,我们可以使用很多现成的工具。但由于文档过大(十多M),我们很难使用在线工具转换(而且在线工具仅支持url的方式加载html,意味着我们还得部署一个网站了承载这个单页的文档)。所以我们得选择一个离线的工具。

这里推荐的是wkhtmltopdf, 该工具可以从 https://wkhtmltopdf.org/ 下载。

该工具使用方式简单,只需要填入sourcedest即可:

代码语言:txt复制
wkhtmltopdf http://google.com google.pdf

我们可以在本地单页html所在的目录,启动一个web服务器(python3 -m http.server 8080 | python -m SimpleHTTPServer 8080

然后进行转换:

代码语言:txt复制
wkhtmltopdf http://localhost:8080 elasticsearch-guide.pdf

这时,你可能会遇到ContentNotFoundError问题。

其主要原因是wkhtmltopdf无法下载html中的链接资源,主要是:

代码语言:html复制
`<link rel="stylesheet" type="text/css" href="/guide/static/styles.css" />`

中指向的资源目录wkhtmltopdf无法定位。

因此,这里需要改为:

代码语言:html复制
<link rel="stylesheet" type="text/css" href="http://localhost:8080/static/styles.css" />

最终命令执行结果为:

代码语言:txt复制
wkhtmltopdf http://localhost:8080 elasticsearch-guide.pdf
Loading pages (1/6)
Counting pages (2/6)                                               
Resolving links (4/6)                                                       
Loading headers and footers (5/6)                                           
Printing pages (6/6)
Done                   

生成之后的pdf如下:

es_one_page_pdf.gifes_one_page_pdf.gif

总结

该方法不仅可以用于生成elastic官方文档的pdf版本,原则上,适用于所有以asciidoc方式编码的文档,对于pdf文档有需求的朋友,可以尝试以此方式为book形式的web内容生成pdf。

0 人点赞