代码已开源:https://github.com/nefu-ljw/python-markdown-to-wordpress

具体使用方法见github仓库上的README.md。

1. 熟悉安装和使用python-wordpress-xmlrpc

参考:http://www.snailtoday.com/archives/10725

python-wordpress-xmlrpc,这个其实就是别人写好的包,直接调用了 WordPress 的 xmlrpc 接口发布文章。

首先安装这个包,对于python3,用 pip3 install python-wordpress-xmlrpc 进行安装。

然后写个简单的程序,测试WordPress发文章:

from wordpress_xmlrpc import Client, WordPressPost
from wordpress_xmlrpc.methods.posts import NewPost

post = WordPressPost()  # 初始化post,我们要发表的文章就是post

# post的一些属性
post.title = "Test: This is the title"  # 标题
post.content = "Test: This is the content"  # 内容
post.post_status = 'publish'  # 类型(publish发布、draft草稿、private隐私)
post.terms_names = {
    'post_tag': ['test-tag1', 'test-tag2'],  # 标签(可以写多个)
    'category': ['test-category']  # 分类(可以写多个)
}  # 如果标签、分类没有的话会自动创建,有的话也不影响
post.comment_status = 'open'  # 开启评论

# 客户端
client = Client('https://jwblog.xyz/xmlrpc.php', '账号', '密码')  # 改成自己的账号密码,jwblog.xyz改成你自己的域名
client.call(NewPost(post))

这个包的使用文档:https://python-wordpress-xmlrpc.readthedocs.io/en/latest/overview.html

2.编写自己的代码实现

参考:http://www.95408.com/blog/3552.html

所使用的 python 模块:

  • python-frontmatter:通过python-frontmatter库获取文章信息,标题、分类、标签、正文内容等
  • markdown:通过markdown库将正文内容转换成HTML格式
  • python-xmlrpc-wordpress:最后将这些信息通过python-wordpress-xmlrpc库发布到网站上

我用的python 3.7,用pip3安装模块。注意pip3 install要把代理关了,否则报错。

我的代码会放在后面,注意拿来还不能直接用,先要装几个模块:

pip3 install python-frontmatter
pip3 install markdown
pip3 install python-wordpress-xmlrpc

然后代码还要改几个地方:

  • post_metadata = {'category': ['CSDN博客存档'], 'tag': ['CSDN博客存档'], 'status': 'publish'}
  • category是文章目录,tag是文章标签,status是文章状态(publish表示发布,这个可以不改)。

  • filepaths = get_filepaths('D:\\PythonCode\\post-wordpress-with-markdown\\doc')

  • 你要上传的目录路径或者单个文件路径(注意是绝对路径,Windows的路径用两个反斜杠分开)。
  • push_post(post, 'https://jwblog.xyz', '账号', '密码')
  • https://jwblog.xyz改成你自己的域名,注意域名前面要加上https://或者https:/
  • 改成你自己登录WordPress的管理员的账号密码。

支持上传markdown类型的文件,即.md后缀的文件。其他类型暂不支持。

我的python代码:

# -*- coding: utf-8 -*-
# @Time : 2021/11/19 0:50 
# @Author : nefu-ljw
# @File : upload-markdown-to-wordpress.py
# @Function: Upload new posts in WordPress with local Markdown files
# @Software: PyCharm
# @Reference: original

import os  # 用来遍历文件路径
import sys

# 1 导入frontmatter模块
import frontmatter

# 2 导入markdown模块
import markdown

# 3 导入wordpress_xmlrpc模块
from wordpress_xmlrpc import Client, WordPressPost
from wordpress_xmlrpc.methods.posts import NewPost

def make_post(filepath, metadata):
    """
    make a WordPressPost for Client call
    :param filepath: 要发布的文件路径
    :param metadata: 字典类型
             包括 metadata['category']: 文章分类
                  metadata['tag']: 文章标签
                  metadata['status']: 有publish发布、draft草稿、private隐私状态可选
    :return WordPressPost: if success
            None: if failure
    """
    # 1 通过frontmatter.load函数加载读取文档里的信息,包括元数据
    post_from_file = frontmatter.load(filepath)

    # 2 markdown库导入内容
    post_content_html = markdown.markdown(post_from_file.content, extensions=['markdown.extensions.fenced_code'])
    post_content_html = post_content_html.encode("utf-8")

    # 3 将本地post的元数据暂存到metadata中
    filename = os.path.basename(filepath)  # 例如:test(2021.11.19).md
    filename_suffix = filename.split('.')[-1]  # 例如:md
    filename_prefix = filename.replace('.' + filename_suffix, '')  # 例如:test(2021.11.19);注意:这种替换方法要求文件名中只有一个".md"

    # 目前只支持 .md 后缀的文件
    if filename_suffix != 'md':
        return None

    metadata['title'] = filename_prefix  # 将文件名去掉.md后缀,作为标题
    # metadata['slug'] = metadata['title']  # 别名
    metadata_keys = metadata.keys()
    # 如果post_from_file.metadata中的属性key存在,那么就将metadata[key]替换为它
    for key in metadata_keys:
        if key in post_from_file.metadata:  # 若md文件中没有元数据'category',则无法调用post.metadata['category']
            metadata[key] = post_from_file.metadata[key]

    # 4 将metadata中的属性赋值给post的对应属性
    post = WordPressPost()  # 要返回的post
    post.content = post_content_html
    post.title = metadata['title']
    # post.slug = metadata['slug']
    post.post_status = metadata['status']
    post.terms_names = {
        'category': metadata['category'],
        'post_tag': metadata['tag']
    }
    post.comment_status = 'open'  # 开启评论
    return post

def push_post(post, client):
    """
    上传post到WordPress网站
    :param post: 要发布的文章(WordPressPost类型),由make_post函数得到
    :param client: 客户端
    :return True: if success
    """
    return client.call(NewPost(post))

def get_filepaths(path):
    """
    如果path是目录路径,递归遍历path目录下的所有文件,将所有文件路径存入filepaths
    如果path是文件路径,直接将单个文件路径存入filepaths
    :param path: 你要上传的目录路径或文件路径(绝对路径)
    :return filepaths: 该目录下的所有子文件或单个文件的绝对路径
            None: wrong path
    """
    filepaths = []
    if os.path.isdir(path):  # 当前路径是目录
        for now_dirpath, child_dirnames, child_filenames in os.walk(path):
            for filename in child_filenames:
                filepath = os.path.join(now_dirpath, filename)
                filepaths.append(filepath)
        return filepaths
    elif os.path.isfile(path):  # 当前路径是文件
        return [path]
    else:  # wrong path
        return None

if __name__ == '__main__':
    # User Configuration
    path = 'your directory path or file path which store your Markdown files'  # e.g. D:/PythonCode/post-wordpress-with-markdown/doc
    domain = 'https://xxx.com'  # e.g. https://jwblog.xyz(配置了SSL证书就用https,否则用http)
    username = 'your username'
    password = 'your password'

    # Optional Configuration
    post_metadata = {
        'category': ['博客存档'],  # 文章分类
        'tag': ['博客存档'],  # 文章标签
        'status': 'publish'  # 可选publish发布、draft草稿、private隐私状态
    }

    # Start Work
    print('----------------------------------------------START----------------------------------------------')
    filepaths = get_filepaths(path)
    if filepaths is None:
        print('FAILURE: wrong path')
        sys.exit(1)

    client = Client(domain + '/xmlrpc.php', username, password)  # 客户端

    md_cnt = 0
    all_cnt = len(filepaths)
    process_number = 0
    failpaths = []  # 存储上传失败的文件路径
    for filepath in filepaths:
        process_number = process_number + 1
        post = make_post(filepath, post_metadata)
        filename = os.path.basename(filepath)
        if post is not None:
            push_post(post, client)
            md_cnt = md_cnt + 1
            print('Process number: %d/%d  SUCCESS: Push "%s" completed!' % (process_number, all_cnt, filename))
        else:
            failpaths.append(filepath)
            print('Process number: %d/%d  WARNING: Can\'t push "%s" because it\'s not Markdown file.' % (process_number, all_cnt, filename))
    print('-----------------------------------------------END-----------------------------------------------')
    print('SUCCESS: %d files have been pushed to your WordPress.' % md_cnt)

    if len(failpaths) > 0:
        print('WARNING: %d files haven\'t been pushed to your WordPress.' % len(failpaths))
        print('\nFailure to push these file paths:')
        for failpath in failpaths:
            print(failpath)

从今天凌晨0:50创建的代码文件,差不多花了一天写完...(大家要支持原创呀!)

批量导入markdown文件,大功告成!