python使用html2text库实现从HTML转markdown的方法详解


Posted in Python onFebruary 21, 2020

如果PyPi上搜html2text的话,找到的是另外一个库:Alir3z4/html2text。这个库是从aaronsw/html2text fork过来,并在此基础上对功能进行了扩展。因此是直接用pip安装的,因此本文主要来讲讲这个库。

首先,进行安装:

pip install html2text

命令行方式使用html2text

安装完后,就可以通过命令html2text进行一系列的操作了。

html2text命令使用方式为:html2text [(filename|url) [encoding]]。通过html2text -h,我们可以查看该命令支持的选项:

选项 描述
--version 显示程序版本号并退出
-h, --help 显示帮助信息并退出
--no-wrap-links 转换期间包装链接
--ignore-emphasis 对于强调,不包含任何格式
--reference-links 使用参考样式的链接,而不是内联链接
--ignore-links 对于链接,不包含任何格式
--protect-links 保护链接不换行,并用尖角括号将其围起来
--ignore-images 对于图像,不包含任何格式
--images-to-alt 丢弃图像数据,只保留替换文本
--images-with-size 将图像标签作为原生html,并带height和width属性,以保留维度
-g, --google-doc 转换一个被导出为html的谷歌文档
-d, --dash-unordered-list 对于无序列表,使用破折号而不是星号
-e, --asterisk-emphasis 对于被强调文本,使用星号而不是下划线
-b BODY_WIDTH, --body-width=BODY_WIDTH 每个输出行的字符数,0表示不自动换行
-i LIST_INDENT, --google-list-indent=LIST_INDENT Google缩进嵌套列表的像素数
-s, --hide-strikethrough 隐藏带删除线文本。只有当也指定-g的时候才有用
--escape-all 转义所有特殊字符。输出较为不可读,但是会避免极端情况下的格式化问题。
--bypass-tables 以HTML格式格式化表单,而不是Markdown语法。
--single-line-break 在一个块元素后使用单个换行符,而不是两个换行符。注意:要求?body-width=0
--unicode-snob 整个文档中都使用unicode
--no-automatic-links 在任何适用情况下,不要使用自动链接
--no-skip-internal-links 不要跳过内部链接
--links-after-para 将链接置于每段之后而不是文档之后
--mark-code 用 …将代码块标记出来
--decode-errors=DECODE_ERRORS 如何处理decode错误。接受值为'ignore', ‘strict'和'replace'

具体使用如下:

# 传递url
html2text http://eepurl.com/cK06Gn

# 传递文件名,编码方式设置为utf-8
html2text test.html utf-8

脚本中使用html2text

除了直接通过命令行使用html2text外,我们还可以在脚本中将其作为库导入。

我们以以下html文本为例

html_content = """
<span style="font-size:14px"><a href="http://blog.yhat.com/posts/visualize-nba-pipelines.html" rel="external nofollow" target="_blank" style="color: #1173C7;text-decoration: underline;font-weight: bold;">Data Wrangling 101: Using Python to Fetch, Manipulate & Visualize NBA Data</a></span><br>
A tutorial using pandas and a few other packages to build a simple datapipe for getting NBA data. Even though this tutorial is done using NBA data, you don't need to be an NBA fan to follow along. The same concepts and techniques can be applied to any project of your choosing.<br>
"""

一句话转换html文本为Markdown格式的文本:

import html2text
print html2text.html2text(html_content)

输出如下:

[Data Wrangling 101: Using Python to Fetch, Manipulate & Visualize NBA

Data](http://blog.yhat.com/posts/visualize-nba-pipelines.html)  

A tutorial using pandas and a few other packages to build a simple datapipe

for getting NBA data. Even though this tutorial is done using NBA data, you

don't need to be an NBA fan to follow along. The same concepts and techniques

can be applied to any project of your choosing.

另外,还可以使用上面的配置项:

import html2text
h = html2text.HTML2Text()
print h.handle(html_content) # 输出同上

注意:下面仅展示使用某个配置项时的输出,不使用某个配置项时使用默认值的输出(如无特殊说明)同上。

--ignore-emphasis

指定选项?ignore-emphasis

h.ignore_emphasis = True
print h.handle("<p>hello, this is <em>Ele</em></p>")

输出为:

hello, this is Ele

不指定选项?ignore-emphasis

h.ignore_emphasis = False # 默认值
print h.handle("<p>hello, this is <em>Ele</em></p>")

输出为:

hello, this is _Ele_

--reference-links

h.inline_links = False
print h.handle(html_content)

输出为:

[Data Wrangling 101: Using Python to Fetch, Manipulate & Visualize NBA

Data][16]  

A tutorial using pandas and a few other packages to build a simple datapipe

for getting NBA data. Even though this tutorial is done using NBA data, you

don't need to be an NBA fan to follow along. The same concepts and techniques

can be applied to any project of your choosing.  

   [16]: http://blog.yhat.com/posts/visualize-nba-pipelines.html

--ignore-links

h.ignore_links = True
print h.handle(html_content)

输出为:

Data Wrangling 101: Using Python to Fetch, Manipulate & Visualize NBA Data  

A tutorial using pandas and a few other packages to build a simple datapipe

for getting NBA data. Even though this tutorial is done using NBA data, you

don't need to be an NBA fan to follow along. The same concepts and techniques

can be applied to any project of your choosing.

--protect-links

h.protect_links = True
print h.handle(html_content)

输出为:

[Data Wrangling 101: Using Python to Fetch, Manipulate & Visualize NBA

Data](<http://blog.yhat.com/posts/visualize-nba-pipelines.html>)  

A tutorial using pandas and a few other packages to build a simple datapipe

for getting NBA data. Even though this tutorial is done using NBA data, you

don't need to be an NBA fan to follow along. The same concepts and techniques

can be applied to any project of your choosing.

--ignore-images

h.ignore_images = True
print h.handle('<p>This is a img: <img src="https://my.oschina.net/img/hot3.png" style="max-height: 32px; max-width: 32px;" alt="hot3"> ending ...</p>')

输出为:

This is a img:  ending ...

--images-to-alt

h.images_to_alt = True
print h.handle('<p>This is a img: <img src="https://my.oschina.net/img/hot3.png" style="max-height: 32px; max-width: 32px;" alt="hot3"> ending ...</p>')

输出为:

This is a img: hot3 ending ...

--images-with-size

h.images_with_size = True
print h.handle('<p>This is a img: <img src="https://my.oschina.net/img/hot3.png" height=32px width=32px alt="hot3"> ending ...</p>')

输出为:

This is a img: <img src='https://my.oschina.net/img/hot3.png' width='32px'

height='32px' alt='hot3' /> ending ...

--body-width

h.body_width=0
print h.handle(html_content)

输出为:

[Data Wrangling 101: Using Python to Fetch, Manipulate & Visualize NBA Data](http://blog.yhat.com/posts/visualize-nba-pipelines.html)  

A tutorial using pandas and a few other packages to build a simple datapipe for getting NBA data. Even though this tutorial is done using NBA data, you don't need to be an NBA fan to follow along. The same concepts and techniques can be applied to any project of your choosing.

--mark-code

h.mark_code=True
print h.handle('<pre class="hljs css"><code class="hljs css">    <span class="hljs-selector-tag"><span class="hljs-selector-tag">rpm</span></span> <span class="hljs-selector-tag"><span class="hljs-selector-tag">-Uvh</span></span> <span class="hljs-selector-tag"><span class="hljs-selector-tag">erlang-solutions-1</span></span><span class="hljs-selector-class"><span class="hljs-selector-class">.0-1</span></span><span class="hljs-selector-class"><span class="hljs-selector-class">.noarch</span></span><span class="hljs-selector-class"><span class="hljs-selector-class">.rpm</span></span></code></pre>')

输出为:

        rpm -Uvh erlang-solutions-1.0-1.noarch.rpm

通过这种方式,就可以以脚本的形式自定义HTML -> MARKDOWN的自动化过程了。例子可参考下面的例子

#-*- coding: utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8') 
import re
import requests
from lxml import etree
import html2text


# 获取第一个issue
def get_first_issue(url):
  resp = requests.get(url)
  page = etree.HTML(resp.text)
  issue_list = page.xpath("//ul[@id='archive-list']/div[@class='display_archive']/li/a")
  fst_issue = issue_list[0].attrib
  fst_issue["text"] = issue_list[0].text
  return fst_issue


# 获取issue的内容,并转成markdown
def get_issue_md(url):
  resp = requests.get(url)
  page = etree.HTML(resp.text)
  content = page.xpath("//table[@id='templateBody']")[0]#'//table[@class="bodyTable"]')[0]
  h = html2text.HTML2Text()
  h.body_width=0 # 不自动换行
  return h.handle(etree.tostring(content))

subtitle_mapping = {
  '**From Our Sponsor**': '# 来自赞助商',
  '**News**': '# 新闻',
  '**Articles**,** Tutorials and Talks**': '# 文章,教程和讲座',
  '**Books**': '# 书籍',
  '**Interesting Projects, Tools and Libraries**': '# 好玩的项目,工具和库',
  '**Python Jobs of the Week**': '# 本周的Python工作',
  '**New Releases**': '# 最新发布',
  '**Upcoming Events and Webinars**': '# 近期活动和网络研讨会',
}
def clean_issue(content):
  # 去除‘Share Python Weekly'及后面部分
  content = re.sub('\*\*Share Python Weekly.*', '', content, flags=re.IGNORECASE)
  # 预处理标题
  for k, v in subtitle_mapping.items():
    content = content.replace(k, v)
  return content

tpl_str = """原文:[{title}]({url})
---
{content}
"""
def run():
  issue_list_url = "https://us2.campaign-archive.com/home/?u=e2e180baf855ac797ef407fc7&id=9e26887fc5"
  print "开始获取最新的issue……"
  fst = get_first_issue(issue_list_url)
  #fst = {'href': 'http://eepurl.com/dqpDyL', 'title': 'Python Weekly - Issue 341'}
  print "获取完毕。开始截取最新的issue内容并将其转换成markdown格式"
  content = get_issue_md(fst['href'])
  print "开始清理issue内容"
  content = clean_issue(content)

  print "清理完毕,准备将", fst['title'], "写入文件"
  title = fst['title'].replace('- ', '').replace(' ', '_')
  with open(title.strip()+'.md', "wb") as f:
    f.write(tpl_str.format(title=fst['title'], url=fst['href'], content=content))
  print "恭喜,完成啦。文件保存至%s.md" % title

if __name__ == '__main__':
  run()

这是一个每周跑一次的python weekly转markdown的脚本。

好啦,html2text就介绍到这里了。如果觉得它还不能满足你的要求,或者想添加更多的功能,可以fork并自行修改。

Python 相关文章推荐
Python标准库urllib2的一些使用细节总结
Mar 16 Python
Python二分法搜索算法实例分析
May 11 Python
创建pycharm的自定义python模板方法
May 23 Python
python中利用h5py模块读取h5文件中的主键方法
Jun 05 Python
面向初学者的Python编辑器Mu
Oct 08 Python
python 实现提取某个索引中某个时间段的数据方法
Feb 01 Python
Python面向对象之类和实例用法分析
Jun 08 Python
弄懂这56个Python使用技巧(轻松掌握Python高效开发)
Sep 18 Python
Django使用消息提示简单的弹出个对话框实例
Nov 15 Python
python 截取XML中bndbox的坐标中的图像,另存为jpg的实例
Mar 10 Python
详解KMP算法以及python如何实现
Sep 18 Python
python 用opencv实现霍夫线变换
Nov 27 Python
python-sys.stdout作为默认函数参数的实现
Feb 21 #Python
pycharm运行程序时看不到任何结果显示的解决
Feb 21 #Python
Python 安装 virturalenv 虚拟环境的教程详解
Feb 21 #Python
python ffmpeg任意提取视频帧的方法
Feb 21 #Python
Python实现自动访问网页的例子
Feb 21 #Python
解决Python pip 自动更新升级失败的问题
Feb 21 #Python
python利用百度云接口实现车牌识别的示例
Feb 21 #Python
You might like
php代码中使用换行及(\n或\r\n和br)的应用
2013/02/02 PHP
无刷新动态加载数据 滚动条加载适合评论等页面
2013/10/16 PHP
php利用腾讯ip分享计划获取地理位置示例分享
2014/01/20 PHP
php实现兼容2038年后Unix时间戳转换函数
2015/03/18 PHP
nodejs的require模块(文件模块/核心模块)及路径介绍
2013/01/14 NodeJs
Function.prototype.bind用法示例
2013/09/16 Javascript
使用Js让Html中特殊字符不被转义
2013/11/05 Javascript
JavaScript设计模式之原型模式(Object.create与prototype)介绍
2014/12/28 Javascript
node-http-proxy修改响应结果实例代码
2016/06/06 Javascript
JS代码实现百度地图 画圆 删除标注
2016/10/12 Javascript
基于百度地图实现产品销售的单位位置查看功能设计与实现
2016/10/21 Javascript
自带气泡提示的vue校验插件(vue-verify-pop)
2017/04/07 Javascript
Vue非父子组件通信详解
2017/06/12 Javascript
vue组件中使用props传递数据的实例详解
2018/04/08 Javascript
微信小程序开发之改变data中数组或对象的某一属性值
2018/07/05 Javascript
JS判断数组里是否有重复元素的方法小结
2019/05/21 Javascript
koa2+vue实现登陆及登录状态判断
2019/08/15 Javascript
微信小程序自定义tabBar在uni-app的适配详解
2019/09/30 Javascript
简单了解JavaScript sort方法
2019/11/25 Javascript
详解vuejs中执行npm run dev出现页面cannot GET/问题
2020/04/26 Javascript
python笔记(2)
2012/10/24 Python
python生成式的send()方法(详解)
2017/05/08 Python
Python测试人员需要掌握的知识
2018/02/08 Python
tensorflow 获取模型所有参数总和数量的方法
2018/06/14 Python
Python实现将Excel转换成xml的方法示例
2018/08/25 Python
python 图像平移和旋转的实例
2019/01/10 Python
基于Django统计博客文章阅读量
2019/10/29 Python
python base64库给用户名或密码加密的流程
2020/01/02 Python
用Python绘制漫步图实例讲解
2020/02/26 Python
基于Python绘制美观动态圆环图、饼图
2020/06/03 Python
python文件操作seek()偏移量,读取指正到指定位置操作
2020/07/05 Python
opencv python 对指针仪表读数识别的两种方式
2021/01/14 Python
欧舒丹澳洲版:L’OCCITANE
2017/07/17 全球购物
New Era英国官网:美国棒球帽品牌
2018/03/21 全球购物
学生周末长期请假条
2014/02/15 职场文书
2015年小学辅导员工作总结
2015/05/27 职场文书