侃遍天下无二人 发表于 2023-4-6 20:59

如何将保存的微信文章连同评论优雅地转为电子书

本帖最后由 侃遍天下无二人 于 2023-4-6 21:12 编辑

这段时间因为各种需要和电子书相关的处理工具打交道比较多,恰好最近也更新了微信文章下载器,但下载器下下来的文章并不适合直接用pandoc转为电子书,因为里面有许多多余的层级结构,可能会导致排版出问题。我先前的做法是把需要制成电子书的文章复制粘贴到 typora 中,这样它就被规范成md格式了,然后再用pandoc将md转为epub。
但现在想来,这样搞存在大量需要手工处理的点,效率太低,于是这两天我基于这段时间积累的经验,稍微研究了一下要如何处理下载下来的微信文章,使之能被pandoc很好地从html直接转成epub格式,并尽量减少后续的处理步骤。研究成果与大家分享一下:

首先,我们不妨以吾爱破解的公众号为例(主要是放其他公众号有推广嫌疑{:301_998:}),下载其中推送的 10 篇原创文章:

然后用pandoc将其中一篇直接转为epub,发现阅读体验非常差,甚至根本就读不到东西:


显然我们应该尽量简化写入html的样式结构,才能提升转换的质量。
我们打开调试工具,可以定位到一个恰好覆盖了整篇文章的节点,节点的id为 js_content :

另外,对于已经保存到本地的留言,它总是被包裹在<!--cmt_start-->和<!--cmt_end-->之间,可以直接用正则表达式提取,此外,留言的样式也很简单,只有如下几条,可以将其写入一个css文件让pandoc使用:
.avatar{width:32px;height:32px;margin-right:12px;border-radius:3px;margin-top:4px}.nickname_wrp{margin-top:5px;margin-bottom:5px;color:rgba(0,0,0,.5)}.reply_result.js_reply_item{border-left:5px solid #aaa;padding-left:15px}

这样,就可以将文章重组成较为精简的样式,从而提升转换质量。

https://static.52pojie.cn/static/image/hrline/1.gif


具体要如何转换呢?下面就以golang为例,进行说明:

首先,我们需要将html文件全部读入内存,并转为字符串形式方便后续处理(代码略)。

接下来,我们要对字符串进行解析,这样才能执行dom操作,解析会用到 "golang.org/x/net/html" 包,代码如下:
doc, _ := html.Parse(strings.NewReader(content))

解析的目的是便于取出文章节点,并将其子节点全部转为字符串,我们编写一个findElementById函数实现:
func findElementById(n *html.Node, id string) *html.Node {
      if n.Type == html.ElementNode && n.Attr != nil {
                for _, attr := range n.Attr {
                        if attr.Key == "id" && attr.Val == id {
                              return n
                        }
                }
      }
      for c := n.FirstChild; c != nil; c = c.NextSibling {
                if result := findElementById(c, id); result != nil {
                        return result
                }
      }
      return nil
}
虽然函数看上去有点啰嗦,但调用起来很简单:
imgContent := findElementById(doc, "js_content")

取得这个节点后,我们要将其子节点全部转为字符串,以便后续重新写入文件:
innerHtml := extractInnerHTML(imgContent)

函数实现如下:
// 提取节点的innerHTML
func extractInnerHTML(n *html.Node) string {
      var h string
      for c := n.FirstChild; c != nil; c = c.NextSibling {
                h += renderNode(c)
      }
      return h
}

// 将节点渲染为HTML字符串
func renderNode(n *html.Node) string {
      var h string
      switch n.Type {
      case html.ErrorNode:
                h = fmt.Sprintf("<!--%s-->", n.Data)
      case html.TextNode:
                h = n.Data
      case html.DocumentNode, html.ElementNode:
                h = fmt.Sprintf("<%s", n.Data)
                for _, a := range n.Attr {
                        h += fmt.Sprintf(` %s="%s"`, a.Key, a.Val)
                }
                if n.Type == html.ElementNode {
                        h += ">"
                }
                for c := n.FirstChild; c != nil; c = c.NextSibling {
                        h += renderNode(c)
                }
                if n.Type == html.ElementNode {
                        h += fmt.Sprintf("</%s>", n.Data)
                }
      case html.CommentNode:
                h = fmt.Sprintf("<!--%s-->", n.Data)
      }
      return h
}
当然,既然是innerHTML,取得的内容是不包含节点本身的,我们用字符串拼接给它补上:
innerHtml = "<div class=\"rich_media_content js_underline_content autoTypeSetting24psection\" id=\"js_content\" style=\"visibility: visible;\" deep=\"5\">" + innerHtml + "</div>"

文章标题也需要统一包上h2样式,方便pandoc处理,这个可以从文件名或者html的元数据中直接获取:
title = "<h2 class=\"rich_media_title \" id=\"activity-name\">" + title + "</h2>"

最后就是评论区的内容,这个直接用正则表达式找出来就好了
var REG_CMT = regexp.MustCompile("(?s)<!--cmt_start-->.*<!--cmt_end-->")

做完这些,我们就可以直接把处理结果返回了
submatch := REG_CMT.FindAllStringSubmatch(content, 1)
      if len(submatch) == 1 {
                return title + innerHtml + submatch
      } else {
                return title + innerHtml
      }

如下图,这就是处理后的html直接转为epub的效果,虽然浏览器上的阅读体验变差了,但转格式后的阅读体验有所提升:


当有多篇文章同时存在时,可以先将这些文章用二进制合并拼接成一个文件,再用pandoc转格式,最后用calibre编辑一下,并根据标题重新生成目录,就能得到一本效果还算不错的电子书了

转换并简单处理后的成品已上传,可以看看效果,祝大家玩得开心!
顺便说一下,这个功能后续会加入下载器中,期待的话请多多为我投票吧~
https://th.bing.com/th/id/OIP.fDD_R0RsONO4nc6DRExdbAHaEK?pid=ImgDet&rs=1

52pojie.epub - 蓝奏云
https://wwpv.lanzoue.com/iGIjw0s9nn5e

侃遍天下无二人 发表于 2024-7-22 00:16

lemonorange 发表于 2024-7-21 16:33
老大,到开源地址里下载好了文件,webDownloader-master,请问接下来怎么操作呢,输入还是同样的提示

源码是让你自己编译的,毕竟我买不起流水线。
我第二个帖子里放了网盘地址的,不是这里,地址直接给你好了

https://wwd.lanzouw.com/b00oqpc8b 密码:cojt

落曌乾坤 发表于 2023-10-19 17:25

本帖最后由 落曌乾坤 于 2023-10-19 18:01 编辑

侃遍天下无二人 发表于 2023-10-19 13:55
你确定这个不是开了暗黑模式吗,用手机打开网页试试,我也装个最新的Chrome验证下
可能是。
Edge和Firefox设置成默认或自动,背景都是黑色,只有设置成light才行,Chrome没找到设置的地方,把Auto Dark Mode for Web Contents设置成disable是不行的。

只有微信公众号的文章用chrome打开会出现这种情况,论坛界面不会,还是白色背景的。

wyl7956851 发表于 2023-4-6 21:04

学习了,谢谢

tom350 发表于 2023-4-6 21:18

感谢分享,学到了

coverme 发表于 2023-4-6 21:25

感谢研究,这信息孤岛,敏感和谐

Lingem 发表于 2023-4-6 21:30

深度好文

lqwlzc 发表于 2023-4-6 21:37

解决了燃眉之急

tingxiazrl 发表于 2023-4-6 21:39

感谢分享!先去试试

Eixxon 发表于 2023-4-6 21:44

很有用有空试试谢谢

cpteling 发表于 2023-4-6 21:57

版主威武

adamfh 发表于 2023-4-6 22:01

正需要,感谢分享。
页: [1] 2 3 4 5 6
查看完整版本: 如何将保存的微信文章连同评论优雅地转为电子书