首页 > 其他分享 >使用MetaWeblog api自动上传文章图片到cnblog

使用MetaWeblog api自动上传文章图片到cnblog

时间:2023-02-28 09:00:49浏览次数:49  
标签:__ MetaWeblog xmlrpc image api path cnblog

由于我日常习惯用 Typora 来写笔记和博客,文章中的图片保存在本地,在发布文章到 cnblog 之前,希望能有一个自动化工具可以自动上传文章引用的图片到 cnblog,获取图片链接,替换掉文章内容中的图片本地链接

调研了一番之后,发现主要有以下两类方法:

  1. 基于 MetaWeblog api 的方法,可参考使用MetaWeblog API实现通用博客发布 之 API测试
  2. 基于 http 请求的方法,模拟请求发送给 cnblog,可参考如何利用Python实现图片自动上传博客园/博客园图床API外链

第一种方法优势在于 cnblog 官方支持(也就是说 api 不会变化),除了 cnblog,其他大部分博客站都支持这种 api,方便未来博客迁移同步。另外可以参考的文章很多,缺点是这些文章年代久远,有很多坑。ORZ
第二种方法优势在于只需要简单模拟 http 请求,缺点在于万一哪天 cnblog 把请求字段改了,这工具就歇菜了。

最终,我决定采用第一种方法。在 python 官方文档稍微了解了下 xmlrpc 的用法之后(client文档,server文档),写了一段代码,想测试下blogger.getUsersBlogs接口:

import xmlrpc.client as xrc

if __name__ == '__main__':
    svr = xrc.ServerProxy('https://rpc.cnblogs.com/MetaWeblog/jy5380')
    usrInfo = svr.blogger.getUserBlogs('jy5380', 
                                       'jy5380', 
                                       '这里填的是MetaWeblog令牌')

    print(usrInfo[0])

但是运行之后报如下错误:

Traceback (most recent call last):
  File "C:\Users\JiangYuan\Tools\cn_blog_auto\main.py", line 17, in <module>
    usrInfo = svr.blogger.getUserBlogs('jy5380',
  File "C:\Users\JiangYuan\AppData\Local\Programs\Python\Python39\lib\xmlrpc\client.py", line 1122, in __call__
    return self.__send(self.__name, args)
  File "C:\Users\JiangYuan\AppData\Local\Programs\Python\Python39\lib\xmlrpc\client.py", line 1464, in __request
    response = self.__transport.request(
  File "C:\Users\JiangYuan\AppData\Local\Programs\Python\Python39\lib\xmlrpc\client.py", line 1166, in request
    return self.single_request(host, handler, request_body, verbose)
  File "C:\Users\JiangYuan\AppData\Local\Programs\Python\Python39\lib\xmlrpc\client.py", line 1182, in single_request
    return self.parse_response(resp)
  File "C:\Users\JiangYuan\AppData\Local\Programs\Python\Python39\lib\xmlrpc\client.py", line 1354, in parse_response
    return u.close()
  File "C:\Users\JiangYuan\AppData\Local\Programs\Python\Python39\lib\xmlrpc\client.py", line 668, in close
    raise Fault(**self._stack[0])
xmlrpc.client.Fault: <Fault 1: 'Failed to handle XmlRpcService call'>

Process finished with exit code 1

百思不得其解,苦苦查询无果,我暂时放弃这个测试。

既然 MetaWeblog api 实际上是把请求内容封装成 http 请求发送给 cnblog 后台,那么我可以在 Postman 工具中模拟这个请求,这次依然是从简单的blogger.getUsersBlogs接口入手,成功拿到了回包:

image-20230226213553834

这时候我转回去研究 python xmlrpc 请求为何失败,断点看报错是出现在 cnblog 后台的回包里面,也就是说请求本身是成功的,然后我仔细检查了下代码,发现接口处少打了一个字幕s, 给自己跪了ORZ。

getUserBlogs -> getUsersBlogs

修改后,能正确请求到信息了。

C:\Users\JiangYuan\Tools\cn_blog_auto\venv\Scripts\python.exe C:/Users/JiangYuan/Tools/cn_blog_auto/main.py
{'blogid': '*****', 'url': 'https://www.cnblogs.com/jy5380/', 'blogName': '可能会下雨'}

简单接口跑通之后,自然是试验下图片上传接口,在这里可以查到 cnblog 提供给我的所有接口,图片上传是用下边这个metaWeblog.newMediaObject

image-20230227075729106

请求参数里的file字段是一个结构体:

image-20230227075928188

依然先是用 Postman 来模拟一下请求:(需要先把图片转成 base64 字符串

image-20230227080206672

返回了一个地址,就是下边这张照片,去年在大梅沙奥特莱斯拍的。

1075155-20230227080045513-918383736

现在把这个过程写成 python:

# 输入markdown文件路径/path/to/test.md,拷贝其内容,在同一目录下生成/path/to/test_cnblog.md
# 读取/path/to/test_cnblog.md文件中的图片,上传至cnblog获得图片url,并替换图片的本地相对路径为此url
import sys
import xmlrpc.client as xrc
import os
import re

imgExt2Type = {
    '.bmp': 'image/bmp',
    '.cmx': 'image/x-cmx',
    '.cod': 'image/cis-cod',
    '.dib': 'image/bmp',
    '.gif': 'image/gif',
    '.ief': 'image/ief',
    '.ico': 'image/x-icon',
    '.jpg': 'image/jpeg',
    '.jfif': 'image/pjpeg',
    '.jpe': 'image/jpeg',
    '.jpeg': 'image/jpeg',
    '.pbm': 'image/x-portable-bitmap',
    '.ppm': 'image/x-portable-pixmap',
    '.pnm': 'image/x-portable-anymap',
    '.png': 'image/png',
    '.pgm': 'image/x-portable-graymap',
    '.rgb': 'image/x-rgb',
    '.ras': 'image/x-cmu-raster',
    '.tif': 'image/tiff',
    '.tiff': 'image/tiff',
    '.xbm': 'image/x-xbitmap',
    '.xpm': 'image/x-xpixmap',
    '.xwd': 'image/x-xwindowdump'
}


def uploadImg(imgAbsPath):
    svr = xrc.ServerProxy('https://rpc.cnblogs.com/metaweblog/jy5380')
    name = os.path.basename(imgAbsPath)
    _, ext = os.path.splitext(imgAbsPath)
    with open(imgAbsPath, 'rb') as f:
        file = {
            'bits': f.read(),
            'name': name,
            'type': imgExt2Type[ext]
        }
        resp = svr.metaWeblog.newMediaObject('jy5380',
                                             'jy5380',
                                             '这里填的是MetaWeblog令牌',
                                             file)
        return resp['url']


if __name__ == '__main__':
    argLen = len(sys.argv)
    if argLen < 2:
        print('[ERROR] no parameters found')
        exit(1)

    targetMDPath = sys.argv[1]
    if not os.path.exists(targetMDPath):
        print('[ERROR] target markdown file not exist')
        exit(1)

    with open(targetMDPath, 'r', encoding='utf-8') as md:
        article = md.read()
        images = re.findall('\\!\\[.*?\\]\\((.*?)\\)', article)

        localImg2NetImg = dict()

        # 排除掉网络图片
        images = [i for i in images if not re.match('((http(s?))|(ftp))://.*', i)]
        print(f'{len(images)} local images founded')
        print(*images, sep='\n')

        # 上传图片
        for img in images:
            imgAbsPath = os.path.join(os.path.dirname(targetMDPath), img)
            print(f'uploading img {imgAbsPath}')
            url = uploadImg(imgAbsPath)
            localImg2NetImg[img] = url
            print(f'uploading img finished. Got {url}')

        # 替换md中的图片链接
        for localImg, netImg in localImg2NetImg.items():
            article = article.replace(localImg, netImg)

        outputFile = os.path.join(os.path.dirname(targetMDPath), os.path.basename(targetMDPath) + '.cnblog')
        with open(outputFile, 'w', encoding='utf-8') as outputMD:
            outputMD.write(article)

成功替换:

image-20230228084810311

参考文章列表:

  1. MetaWebLog API — 一个多平台文章同步的思路
  2. XML-RPC 简单理解与博客园的MetaWeblog协议
  3. 博客园markdown上传文件及图片
  4. MetaWeblog API中文说明
  5. XML-RPC Specification
  6. 如何利用Python实现图片自动上传博客园/博客园图床API外链
  7. 使用metaweblog API实现通用博客发布 之 API测试

标签:__,MetaWeblog,xmlrpc,image,api,path,cnblog
From: https://www.cnblogs.com/jy5380/p/17162661.html

相关文章

  • IDEA插件Apifox,一键自动生成接口文档!
    有关Apifox软件之前写过一篇文章:接口测试神器Apifox,亲测好用!如何一键自动生成数据库文档之前也写过一篇文章:数据库界的Swagger:一键生成数据库文档!一、Apifox插件的优......
  • 百度地图的API接口
     API接口API:应用程序接口(API:ApplicationProgramInterface)python为了在团队内部形成共识、防止个人习惯差异引起的混乱,我们需要找到一种大家都觉得很好的接口实现规......
  • 【Azure 存储服务】使用REST API操作Azure Storage Table,删除数据(Delete Entity)
    问题描述使用AzureStorageTable的RESTAPI,实现根据过滤条件删除满足条件的数据,调用方法为  DeleteEntity(AzureStorage) 问题实现第一步:通过AzureStroage门......
  • api网关的使用,实现访问控制
    文章目录​​场景​​​​什么是api网关,有什么用​​​​效果​​​​接入过程​​​​如何查看哪些人订阅了​​​​其他​​​​api和应用之间的关系​​​​api网关不要......
  • 使用npm包API Promise化
             ......
  • Flow API搭建指南
    搭建FlowAPI,首先需要安装知行之桥EDI系统,注意,FlowAPI为新增功能,仅在2022版本(8336)及以后支持,如果你发现正在使用的产品没有这个功能,可以在我们官网下载最新版本或者联系我......
  • .Net Core Web API 版本控制
    原文:https://briancaos.wordpress.com/2022/04/04/c-net-core-api-versioning-with-microsoft-aspnetcore-mvc-versioning/  .NETCoreallowsyoutocontrolversio......
  • Api接口小知识
    应用程序接口API(ApplicationProgrammingInterface),是提供特定业务输出能力、连接不同系统的一种约定。这里包括外部系统与提供服务的系统(中控系统)或者后台不同的系统之间......
  • 读Java性能权威指南(第2版)笔记03_ Java SE API技巧中
    1. 缓冲I/O1.1. 对于文件和套接字,压缩和字符串编码的操作,必须适当地对I/O进行缓冲1.1.1. 两个流操作的是字节块(来自缓冲流)而不是一系列的单字节(来自ObjectOutputStre......
  • ChatGPT API使用介绍
    1.概述随着人工智能技术的不断发展,越来越多的AI产品被应用到各个领域,其中最具代表性的莫过于人工智能语言模型。语言模型是一种可以通过学习大量语言数据来预测文本或语音......