发布自己的Python包 - ohHTMLToMarkdown

背景

之前一直说要自己写个Python库,本来想写个简单的,比如说自动排序Python文件头的import语句,后来发现已经有现成的了,名为isort。最终实现了一个略微复杂一点的HTML转Markdown的库,名为ohHTMLToMarkdown。

为了学习一下如何发布一个Python包,我又厚颜无耻的把它传到了PyPI上。

实现思路

目前支持的HTML标签有:h1~h6, p, a, img, del, b, strong, i, em, hr, br, ul, ol, table, blockquote, code, pre, span, title, time, iframe, section, div, html, body, head

处理主要靠的是BeautifulSouphtml.parser解析器和.descendants对象。前者可以把html文档解析成一个树状模型,访问.contents可以访问到当前层级的所有子树的根节点;后者可以返回一个生成器,它包含了当前子树的所有节点(包含本身)。

通过判断descendants的长度可以知道该子树有没有子节点,之后根据当前tag的类型,可以选择继续进行深度遍历还是将它转换为Markdown的语义。

一个问题

>>> from bs4 import BeautifulSoup
>>> soup = BeautifulSoup("

a

", 'html.parser') >>> print (tuple(soup.descendants)) (

a

, 'a') >>> print (soup)

a

这里可是看出descendants其实是包含其本身的,并且最底层的文字也会作为后代之一。这个问题在处理类似于

h1

的时候不会有问题,但是在处理boldita就会有问题,我用了一个叫__special()的方法解决了这个问题,但是看起来有点蠢。

测试

使用unittest库写了19个测试用例,包含一些基本的功能测试。同时还从我的博客、、知乎上抓取了一些文章进行转换,总体效果还不错。

但是同样也有问题,就是每个网站在使用HTML时可能习惯不一样,比如说我的博客在渲染Markdown时,如果需要带行号显示,那么这块代码会被渲染成没有theadtable,而不是pre;而在中我见到了类似


的代码。后者在处理的时候没问题,而前者会多出一大堆行号。

后来我就想这里其实可以定制一些子类,用来专门处理特定网站的特定标签格式,这些类继承Parser类。

TODO

  • 扩展子块用于解析特性网站的特定标签
  • Nested列表(当前版本可以识别这种列表,但是无法输出正确格式的markdown,不会计算缩进)
  • 其他未涉及的HTML标签
  • 命令行工具
  • 其他需要修改的问题

发布

如果想要把你的库发布到PyPI上,你至少需要一个PyPI账号。

这里还有一些其他步骤,我不确定这些是不是都是必须的,但是通过这些步骤,我上传成功了。有个详细的文档:

Python-OpenSource-Project-Developer-Guide’s documentation。

这里想提一句的是,PyPI似乎更新和简化了其项目发布的步骤,很多网上能搜到的教程都是老版的教程,我自己没试过。我这里所述的是我自己结合官方文档和同行项目之后,得到的精简步骤。

文件结构

因为我这个库只有一个py文件,只要把它放在同名目录下即可,同时可以新建其他三个文件setup.pyREADME.mdLICENSE。其中后两者也不是必须的,但是一般都会有。如图:

>>> tree ohHtmlToMarkdown /F
D:\ONEDRIVE\DOCUMENTS\PYTHON和数据挖掘\CODE\OHHTMLTOMARKDOWN
    LICENSE
    ohHtmlToMarkdown.py
    README.md
    setup.py

这里提一句,虽然官方说模块名字最好用全小写,但其实带大写也不会有什么问题。

setup.py

一个setup的模板:

import setuptools

with open('README.md', 'r',encoding='utf-8') as fh:
    long_description = fh.read()

setuptools.setup(
    name="ohHtmlToMarkdown",
    version="1.0.0",
    description="A Python Library for converting HTML to Markdown.",
    long_description=long_description,
    long_description_content_type="text/markdown",
    author="Ethan Huang",
    author_email="[email protected]",
    url='https://github.com/wfgydbu/ohHTML2Markdown',
    packages=setuptools.find_packages(),
    license='GNU GPL 3',
    classifiers=[
        'Development Status :: 5 - Production/Stable',
        'Intended Audience :: Developers',
        'License :: OSI Approved :: GNU General Public License (GPL)',
        'Programming Language :: Python :: 3.6',
        "Operating System :: OS Independent"
    ],
    install_requires=['beautifulsoup4==4.6.0'],
    py_modules=['ohHtmlToMarkdown'],
    include_package_data=True,
    zip_safe=False,
)
  • 关于classifiers的选择,可以参考https://pypi.org/pypi?%3Aaction=list_classifiers。
  • 关于version的填写,格式为major.minor[.patch[.sub]].
  • 注意py_modules的使用,如果你的模块文件有点多,你可能会需要在根目录下在新建若干子目录,一般来说每个目录都会被认为是一个模块,通过modules.sub_module调用,同时也要编写合适的__init__.py文件。
    • __init__.py文件的作用是将文件夹变为一个Python模块,你可以把它当作模块的入口。

我这个setup.py的模板是经过我反复锤炼过的(参考官方文档和同行的项目),它可以最小化的减少代码结构的调整。

LICENSE

假装会有人使用这个库,我这里选择了的License是GNU General Public License (GPL)。关于LICENSE的选择可以参考choose licenses。

README.md

这个就不多说了,注意如果用的是MD的话,需要在setup.py中配置,不然到时候显示的是MD的源码。

发布到PyPI

规范的发布过程在这里:Packaging Python Projects。但是它这里面的例子发布了一个没有实际代码的项目,导致少了一部分配置项,恰好这些配置项也是必要的。

PyPI会根据你在setup()中定义的配置项生成该项目在PyPI上的主页面,这是我发布的0.1版截图。

pypi-homepage.jpg

可以看到缺少项目描述,因为我的配置项的long_description写错了。改好之后,我发现我的描述是用中文写的。感觉把路走窄了。

指令

setup.py的同级目录下,执行:

# 安装twine
pip install --user --upgrade twine

# 打包
python setup.py sdist bdist_wheel

# 发布到测试服
twine upload --repository-url https://test.pypi.org/legacy/ dist/*

# 发布到正式服
twine upload dist/*

执行完安装指令后,目录结构是这样的,我是在windows下做的:

D:\ONEDRIVE\DOCUMENTS\PYTHON和数据挖掘\CODE\OHHTMLTOMARKDOWN
│  LICENSE
│  ohHtmlToMarkdown.py
│  README.md
│  setup.py
│
├─build
│  ├─bdist.win-amd64
│  └─lib
│          ohHtmlToMarkdown.py
│
├─dist
│      ohHtmlToMarkdown-0.5.0-py3-none-any.whl
│      ohHtmlToMarkdown-0.5.0.tar.gz
│
└─ohHtmlToMarkdown.egg-info
        dependency_links.txt
        not-zip-safe
        PKG-INFO
        requires.txt
        SOURCES.txt
        top_level.txt

重要的补充

强烈建议在发布正式版本之前在测试服务器上试验一下,实际上,当生成了whl文件之后,就可以直接使用pip install *.whl安装这个包到本地了, 方便测试。

安装成功后,相关的代码和egg文件会被拷贝到${PATH}/Lib/site-packages下(包括子目录),因此不管是模块名字还是子目录的名字,在世界范围内都应该是唯一的。

调用site-packages下的py模块可以直接使用import module,其他则是用.连接,比如:import module.sub_module

你可能感兴趣的:(发布自己的Python包 - ohHTMLToMarkdown)