【玩转掘金】掘金专栏文章正生成pdf文档 |Python 主

本文正在参加「Python主题月」,详情查看 活动链接

前言

掘金有在看各位的很多优秀的专栏,我一直在思考,如何把这些专栏的文章内容整合在一起呢?

对,生成PDF文件,数据聚合,方便你我她他它。

Don’t worry! 实现的方法方式都很简单,一共不到200行代码。

源码:JueJinColToPdf

在线预览:
我的掘金前端周栏.pdf

效果演示

代码执行

cmd.gif

PDF文档效果

pdf.gif

基本思路

  1. 收集API信息和关联
  2. 下载专栏数据
  3. 生成html代码 (markdown转html)
  4. 生成pdf文件

收集API信息和关联

数据是一切的根源,所以先分析如何获取掘金专栏数据。

其实三个API就满足需求:

  1. 专栏摘要信息

作用: 获取专栏的摘要信息,主要是专栏ID和专栏名称

API地址: api.juejin.cn/content_api…
2. 专栏文章列表

作用: 获取专栏文章列表,主要是文章ID,一个中间商罢了。

API地址: api.juejin.cn/content_api…
3. 文章详情

作用: 获取文章详情,主要是文章标题和MarkDown格式的文章内容

API地址api.juejin.cn/content_api…

整体流程如下:

image.png

获取专栏信息

API地址: api.juejin.cn/content_api…]

请求参数

QueryString

  1. column_id 专栏ID

数据结构

有用的就是 title字段,生成html和pdf时需要。

1
2
3
4
5
6
7
8
json复制代码{
column_id:""6979380367216082957"
data: {
"column_version": {
"title": "前端基础进阶“ // 专栏标题
}
}
}

获取专栏文章列表

API 地址
https://api.juejin.cn/content_api/v1/column/articles_cursor

请求参数

1
2
3
4
5
6
json复制代码{
"column_id":"6979380367216082957", // 专栏ID
"cursor":"0", // 当前下标
"limit":20, // 一页大小
"sort":0 // 0 发布事件从近到远,反之从远到近
}

数据结构
有用的其实就 artcile_id

1
2
3
4
5
6
7
8
9
10
11
12
13
14
json复制代码{
"err_no": 0,
"err_msg": "success",
"cursor": "2",
"count": 5,
"has_more": false,
"data": [
{
"article_id": "6989391487200919566",
.....................

}
]
}

获取文章详情

API地址:

https://api.juejin.cn/content_api/v1/article/detail

请求参数:

1
2
3
json复制代码{
"article_id": "6989391487200919566" // 文章ID
}

返回结果:

data属性中的mark_content字段就是markdown语法的原始内容。

1
2
3
4
5
6
7
8
9
10
json复制代码{
"data": {
"article_id": "6989391487200919566",
"article_info": {
"mark_content": "---\ntheme: channing-cyan\nhighlight: a11y-dark\n---\n\n\n## 前言\n\n本文收录在 **[前端基础进阶](https://juejin.cn/column/6979380367216082957)** 专栏"
}
},
"err_no": 0,
"err_msg": "success",
}

下载专栏数据

我们选择Python里面比较有名的requests库,虽然不支持异步,不过问题不大。

基本顺序:

  1. 下载专栏信息
  2. 下载专栏文章列表信息
  3. 下载单篇文章信息

注意点:

  1. 我们会按照专栏ID创建文件夹,把下载下来的JSON格式的文件都放到下面

至于为什么? 21世纪什么最重要, 数据!!

有了数据,你可以自己生成网页,做成word, pdf,亦或其他,无线的选择。

本着本文为Python类别,还是贴一段主流程代码:
更多细节查看源码 JueJinColToPdf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
python复制代码def downloadColumn(cid):

column = getColumn(cid);
print("获取专栏信息成功,专栏名称:", column["data"]["column_version"]["title"]);
saveColumn(cid, json.dumps(column["data"]))

articleList = getArticleList(cid)
saveArticleList(cid, json.dumps(articleList["data"]))

articleIds = list(map(lambda item: item["article_id"], articleList["data"]))
print("获取专栏文章列表成功:", articleIds)

for artId in articleIds:
artContent = getArticleContent(artId)
saveArticleContent(cid, artId, json.dumps(artContent["data"]))
print("文章ID为 %s 的文章下载完毕" % artId)

生成Html代码

直接说一些问题

如何把markdown格式转为html代码

巨人的肩上markdown

1
2
python复制代码 html += markdown.markdown(
removeScheme(article["article_info"]["mark_content"]), extensions=extensions)

如何高亮代码

Pygments库,

1
js复制代码pygmentize -S default -f html -a .codehilite > code.css

然后设置一个markdown库的extensions

1
2
3
4
5
6
7
8
9
10
python复制代码extensions = [  # 根据不同教程加上的扩展
'markdown.extensions.extra',
'markdown.extensions.codehilite', # 代码高亮扩展
'markdown.extensions.toc',
'markdown.extensions.tables',
'markdown.extensions.fenced_code',
]

html += markdown.markdown(
removeScheme(article["article_info"]["mark_content"]), extensions=extensions)

去掉掘金主题和代码风格

如果你选择了主题或者代码高亮,markdown头部会多出如下的内容。

1
2
3
4
markdown复制代码---
theme: github
highlight: a11y-light
---

方案:正则替换或者字符串截取

如何自定义样式

新建一个 extend.css

1
2
3
4
5
6
7
8
css复制代码* {
font-size: 30px; // 默认字体
}

img{
display: block;
min-width: 50%; // 图片至少50%
}

如何生成一个大的html文件

  1. 创建一个html文件,
  2. core.cssextend.css文件写入html的style标签里面
  3. 写入头部的html,
  4. 写入markdown转换后的html,
  5. 最后写入尾部的html。

如果文章太多,怎么办

以一定文章数量分割,比如20篇

以一定文字数量分割,比如5万字

在笔者的代码中是未实现的,不过问题不大,我之前有用html生成400多页的pdf也妥妥的。

转为pdf文件

借助 wkhtmltopdf.exe, 这款神奇可以把网络地址或者本地html文件直接转换成为pdf文件。

最重要的是其完美的支持目录。

从官方下载安装,然后配置一下环境变量就可以,代码嘛就下面这点。

1
2
3
4
5
6
7
8
9
python复制代码def genPdf(title):
# TODO:: 需要配置全局路径
exePath = "wkhtmltopdf.exe"
sourcePath = "./htmls/%s.html" % title
targetPath = "./pdfs/%s.pdf" % title
cmd = '"%s" --outline-depth 2 --footer-center [page] "%s" "%s"' % (
exePath, sourcePath, targetPath)
print(cmd)
subprocess.call(cmd)

写在最后

写作不易,你的一赞一评,就是我最大的动力。

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%