使用metaweblog API实现通用博客发布 之 API测试
阅读原文时间:2023年07月11日阅读:2

使用metaweblog API实现通用博客发布 之 API测试

使用博客比较少,一则是文笔有限,怕写出的东西狗屁不通,有碍观瞻, 二则是懒,很讨厌要登录到网站上写东西,也没有那么多时间(借口)。个人最喜欢用于记录的工具是Zim https://zim-wiki.org/ ,记录东西超级方便,可惜只支持PC版本, 记录的东西可以到处为MarkDown 格式,非常方便(你现在看到的这篇就是用Zim写的)。

无意间看到Vs Code上有博客园的插件,作为程序员,顺手google/百度了一下,原来通用博客都支持使用metaweblog API来访问,还支持直接发布markdown 格式,简直不要太好。 找了找2年前注册的博客源账号,用来测试一下。

发挥典型中国程序员的拿来主义精神,经过goolgle/百度一番搜索,参考以下文档进行API测试,在此表示感谢!!

https://www.cnblogs.com/caipeiyu/p/5475761.html

https://github.com/1024th/cnblogs_githook

在博客设置最的最末端,有MetaWeblog 的访问地址链接

点击进入页面,有metaweblog API 的详细说明

具体内容不赘述了。

使用python3 进行API测试,直接上代码:

    #encoding = utf-8
    #!/bin/sh python3

    import xmlrpc.client as xmlrpclib
    import json

    '''
    配置字典:
    type | description(example)
    str  | metaWeblog url, 博客设置中有('https://rpc.cnblogs.com/metaweblog/1024th')
    str  | appkey, Blog地址名('1024th')
    str  | blogid, 这个无需手动输入,通过getUsersBlogs得到
    str  | usr, 登录用户名
    str  | passwd, 登录密码
    str  | rootpath, 博文存放根路径(添加git管理)
    '''

    '''
    POST:
    dateTime    dateCreated - Required when posting.
    string  description - Required when posting.
    string  title - Required when posting.
    array of string categories (optional)
    struct Enclosure    enclosure (optional)
    string  link (optional)
    string  permalink (optional)
    any postid (optional)
    struct Source   source (optional)
    string  userid (optional)
    any mt_allow_comments (optional)
    any mt_allow_pings (optional)
    any mt_convert_breaks (optional)
    string  mt_text_more (optional)
    string  mt_excerpt (optional)
    string  mt_keywords (optional)
    string  wp_slug (optional)
    '''

    class MetablogClient():
      def __init__(self, configpath):
        '''
        @configpath: 指定配置文件路径
        '''
        self._configpath = configpath
        self._config = None
        self._server = None
        self._mwb = None

      def createConfig(self):
        '''
        创建配置
        '''
        while True:
            cfg = {}
            for item in [("url", "metaWeblog url, 博客设置中有\
                ('https://rpc.cnblogs.com/metaweblog/blogaddress')"),
                         ("appkey", "Blog地址名('blogaddress')"),
                         ("usr", "登录用户名"),
                         ("passwd", "登录密码"),
                         ("rootpath", "博文本地存储根路径")]:
                cfg[item[0]] = input("输入"+item[1])
            try:
                server = xmlrpclib.ServerProxy(cfg["url"])
                userInfo = server.blogger.getUsersBlogs(
                    cfg["appkey"], cfg["usr"], cfg["passwd"])
                print(userInfo[0])
                # {'blogid': 'xxx', 'url': 'xxx', 'blogName': 'xxx'}
                cfg["blogid"] = userInfo[0]["blogid"]
                break
            except:
                print("发生错误!")
        with open(self._configpath, "w", encoding="utf-8") as f:
            json.dump(cfg, f, indent=4, ensure_ascii=False)

      def existConfig(self):
        '''
        返回配置是否存在
        '''
        try:
            with open(self._configpath, "r", encoding="utf-8") as f:
                try:
                    cfg = json.load(f)
                    if cfg == {}:
                        return False
                    else:
                        return True
                except json.decoder.JSONDecodeError:  # 文件为空
                    return False
        except:
            with open(self._configpath, "w", encoding="utf-8") as f:
                json.dump({}, f)
                return False

      def readConfig(self):
        '''
        读取配置
        '''
        if not self.existConfig():
          self.createConfig()

        with open(self._configpath, "r", encoding="utf-8") as f:
          self._config = json.load(f)
          self._server = xmlrpclib.ServerProxy(self._config["url"])
          self._mwb = self._server.metaWeblog

      def getUsersBlogs(self):
        '''
        获取博客信息
        @return: {
          string  blogid
          string    url
          string    blogName
        }
        '''
        userInfo = self._server.blogger.getUsersBlogs(self._config["appkey"], self._config["usr"], self._config["passwd"])
        return userInfo

      def getRecentPosts(self, num):
        '''
        读取最近的博文信息
        '''
        return self._mwb.getRecentPosts(self._config["blogid"], self._config["usr"], self._config["passwd"], num)

      def newPost(self, post, publish):
        '''
        发布新博文
        @post: 发布内容
        @publish: 是否公开
        '''
        while True:
          try:
              postid = self._mwb.newPost(self._config['blogid'], self._config['usr'], self._config['passwd'], post, publish)
              break
          except:
              time.sleep(5)
        return postid

      def editPost(self, postid, post, publish):
        '''
        更新已存在的博文
        @postid: 已存在博文ID
        @post: 发布内容
        @publish: 是否公开发布
        '''
        self._mwb.editPost(postid, self._config['usr'], self._config['passwd'], post, publish)

      def deletePost(self, postid, publish):
        '''
        删除博文
        '''
        self._mwb.deletePost(self._config['appkey'], postid, self._config['usr'], self._config['passwd'], post, publish)

      def getCategories(self):
        '''
        获取博文分类
        '''
        return self._mwb.getCategories(self._config['blogid'], self._config['usr'], self._config['passwd'])

      def getPost(self, postid):
        '''
        读取博文信息
        @postid: 博文ID
        @return: POST
        '''
        return self._mwb.getPost(postid, self._config['usr'], self._config['passwd'])

      def newMediaObject(self, file):
        '''
        资源文件(图片,音频,视频...)上传
        @file: {
          base64    bits
          string    name
          string    type
        }
        @return: URL
        '''
        return self._mwb.newMediaObject(self._config['blogid'], self._config['usr'], self._config['passwd'], file)

      def newCategory(self, categoray):
        '''
        新建分类
        @categoray: {
          string    name
          string    slug (optional)
          integer   parent_id
          string    description (optional)
        }
        @return : categorayid
        '''
        return self._server.wp.newCategory(self._config['blogid'], self._config['usr'], self._config['passwd'], categoray)
    ```

以上是对API的简单封装,万事具备,开始测试

### 2.1 获取分类
```python
    import core.metablogclient as blogclient

    client = blogclient.MetablogClient('blog_config.json')
    client.readConfig()
    catLst = client.getCategories()
    print(catLst)


    [{'description': '[发布至博客园首页]', 'htmlUrl': '', 'rssUrl': '', 'title': '[发布至博客园首页]', 'categoryid': '0'},
    {'description': '[Markdown]', 'htmlUrl': '', 'rssUrl': '', 'title': '[Markdown]', 'categoryid': '-5'}...]

获取了所有的分类信息,其中我在网站上自建了一个随笔分类,也可以获取到

2.2 新建分类

    import core.metablogclient as blogclient

    client = blogclient.MetablogClient('blog_config.json')
    client.readConfig()
    catid = client.newCategory({
    "name": "[随笔分类]测试分类",
    "slug": "",
    "parent_id": 0,
    "description": "测试建立一个随笔子分类"
    })
    print("新建分类:", catid)


    新建分类: 1536823

但是在博客园网站上无法看到这个分类,使用获取分类再次测试,也无法获取到该分类,使用该分类发布博客,也是无

效的,所以我想__根据年月自动分类__的想法就泡汤啦

2.3 拉取现有博文

    import core.metablogclient as blogclient

    client = blogclient.MetablogClient('blog_config.json')
    client.readConfig()
    posts = client.getRecentPosts(9999)
    print(posts)


    [{'dateCreated': <DateTime '20190829T11:21:00' at 0x2a80990>, 'description': '<p>测试</p>', 'title': '测试', 'enclosure': {'length': 0},
    'link': 'https://www.cnblogs.com/robert-9/p/11428668.html', 'permalink': 'https://www.cnblogs.com/robert-9/p/11428668.html',
    'postid': '11428668', 'source': {}, 'userid': '-2'}]

正确拉取现有博文,通过API文档,发现无法获取博文是否处于发布状态,这是一个遗憾

2.4 发布博文

    import core.metablogclient as blogclient
    import datetime

    client = blogclient.MetablogClient('blog_config.json')
    client.readConfig()
    postid = client.newPost({
      "time": datetime.datetime.now(),
      "title": "metaweblog API随笔发布",
      "description": "##metaweblog API随笔发布\n测试\n",
      "categories": ["[Markdown]"],
      "mt_keywords": "metaweblog;python"
    }, False)
    print('发布随笔:', postid)

测试发布成功,并能在网站上看到该随笔, 如果想发布为文章,日志或新闻,加入必要的分类即可。

2.5 上传图片

    import datetime
    import base64
    import core.metablogclient as blogclient

    client = blogclient.MetablogClient('blog_config.json')
    client.readConfig()
    with open('abc.png', 'rb') as f:
      bs64_str = base64.b64encode(f.read())
      url = client.newMediaObject({
          "bits": bs64_str,
          "name": "abc.png",
          "type": "image/png"
      })
      print(url)


    {'url': 'https://img2018.cnblogs.com/blog/1211514/201908/1211514-20190829114435333-814710358.png'}

测试成功, 这样就可以在上传Markdown 格式之前,自动将本地的图片上传到服务器上了。