前言

之前写过一片文章,​​typora 使图床​​,用来存储 markdown 文章的图片资源文件。后来发现 typora 还可以自定义导出命令,那么也可以利用这个功能实现直接发

文章接口

主要难点就是对请求头上​​x-ca-signature​​​加了验证,参考我之前容接口的x-ca-signature签名算法研究​​。 不过有意思的是,之前验证失败的时候会直接抛出验证错误的响应,现在是直接返回为空,不显示提示信息也是一种防逆向的策略。算法和以前几乎一样,不过有一些细微的差别,例如请求类型是POST,这个请求类型也是构成 ​​x-ca-signature​​的一部分(加密前)。

cle.py

import requests
from urllib.parse import urlparse
import http.cookiejar as cookielib
import hashlib
import hmac
from base64 import b64decode,b64encode
import random
import sys
from markdown import markdown
import os
in
requests.packages.urllib3.disable_warnings()

os.chdir(os.path.dirname(os.path.abspath(__file__)))

headers = {
"user-agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36",
'Content-Type': "application/json",
"origin": "https
"referer": "httt/",
"sec-ch-ua-platform": "Windows",
}

def createUuid():
text = ""
char_list = []
for c in range(97,97+6):
char_list.append(chr(c))
for c in range(49,58):
char_list.append(chr(c))
for i in "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx":
if i == "4":
text += "4"
elif i == "-":
text += "-"
else:
text += random.choice(char_list)
return text

def get_sign(uuid,url):
s = urlparse(url)
ekey = "9znpamsyl2c7cdrr9sas0le9vbc3r6ba".encode()
to_enc = f"POST\n*/*\n\napplication/json\n\nx-ca-key:203803574\nx-ca-nonce:{uuid}\n{s.path}".encode()
sign = b64encode(hmac.new(ekey, to_enc, digestmod=hashlib.sha256).digest()).decode()
return sign


def uploadArticle(articles):
for article in articles:
url = 'httpditor/saveArticle'
uuid = createUuid()
sign = get_sign(uuid,url)
headers = {}
headers['x-ca-key'] = "203803574"
headers['x-ca-nonce'] = uuid
headers['x-ca-signature'] = sign
headers['x-ca-signature-headers'] = "x-ca-key,x-ca-nonce"
session = requests.session()
session.cookies = cookielib.LWPCookieJ
session.cookies.load()

with open(article,"r",encoding='utf8') as f:
data = f.read()
title = os.path.basename(article)[:-3]

fields = {
"title": title,
"markdowncontent": data,
"content": markdown(data),
"readType": "public",
"tags": " ",
"status": 0,
"categories": "",
"type": "original",
"original_link": "",
"authorized_status": False,
"not_auto_saved": "1",
"source": "pc_mdeditor",
"cover_images": [],
"cover_type": 0,
"is_new": 1,
"vote_id": 0,
"pubStatus": "publish"
}
data = session.post(url,headers=headers,json=fields,verify=False)
print(data.json()["msg"])

if __name__ == '__main__':
uploadArticle(sys.argv[1:])

# x-ca-nonce: 5bbec46a-fae9-45f1-ab12-40e4e92c1901
# x-ca-signature: B2tpU+fIVigDzGba3rJYW6atH/jOZf4G3Ow/K2B64F4=
# 加密算法在app.chunk.12001b99.js 20126行

登录获取cookie:

ogin.py

import requests
import http.cookiejar as cookielib
import psutil
import os
import re
os.chdir(os.path.dirname(os.path.abspath(__file__)))
requests.packages.urllib3.disable_warnings()

def is_login():
session = requests.session()
try:
session.cookies = cookielib.LWPCookieJar(filen

url = 'https://
response = session.post(url)
if response.json()['message'] == "成功":
return True
else:
return False
except Exception as e:
return False

def login():
session = requests.session()
session.cookies = cookielib.LWPCookieJar(filename='
response = session.get('https://open.weixin.qq.com/connect/qrconne
imgData = session.get(img_url).content
with open("qrcode.jpg","wb") as f:
f.write(imgData)
os.popen("qrcode.jpg")

uuid = uuid.split('/')[-1]
url = 'https://long.open.weixin.qq.com/connect/l/qrconnect?uuid='+uuid
while True:
response = session.get(url,verify=False)
code = re.findall("window.wx_code='(.*?)'",response.text)
if code != ['']:
for proc in psutil.process_iter(): # 遍历当前process
try:
if proc.name() == "dllhost.exe": # 如果你展示图片的进程不是这个,可以对此进行修改
proc.kill() # 关闭该process
except Exception as e:
pass
break
time.sleep(1)

ister/pcAuthCallBack?pcAuthType=weixin&code
session.get(url)
session.cookies.save()

if not os.path.exists(".cookie"):
os.mkdir(".cookie")
if not os.path.exists(os.path.join(".
with open(os.path.join(".coo
f.write("")

if not is_login():
login()

这里依然采用扫码登录的方式。

博客园平台

如果要使用博客园的 MetaWeblog API, 要在设置中进行简单的设置。

typora实现多平台发布文章_xml

然后才可以使用,​​接口定义​​ 很全面了,使用起来非常方便。

1. 上传图片

cnblogsImage.py

import xmlrpc.client
import ssl
import os
import json
import sys
ssl._create_default_https_context = ssl._create_unverified_context

rootPath = os.path.abspath(os.path.dirname(__file__))
with open(os.path.join(rootPath,"cnblogs.json"),"rb") as f:
config = json.loads(f.read())


def uploadImage(images):
for image in images:
with open(image,"rb") as f:
imageData = f.read()

baseName = os.path.basename(image)
suffix = baseName.split(".")[-1]
file = dict(
bits = imageData,
name = baseName,
type = f"image/{suffix}"
)
proxy = xmlrpc.client.ServerProxy(config["url"])
s = proxy.metaWeblog.newMediaObject('', config['username'], config['password'],file)
print(s["url"])

if __name__ == '__main__':
uploadImage(sys.argv[1:])

2.发布文章

cnblogsArticle.py

import xmlrpc.client
import ssl
import os
import json
import sys
ssl._create_default_https_context = ssl._create_unverified_context

rootPath = os.path.abspath(os.path.dirname(__file__))
with open(os.path.join(rootPath,"cnblogs.json"),"rb") as f:
config = json.loads(f.read())

def uploadArticle(articles):
for article in articles:
with open(article,"r",encoding="utf8") as f:
data = f.read()

title = os.path.basename(article)[:-3]
post = dict(
dateCreated = xmlrpc.client.DateTime(),
description = data,
title = title,
categories = ['[Markdown]'],
)
proxy = xmlrpc.client.ServerProxy(config["url"])
s = proxy.metaWeblog.newPost('', config['username'], config['password'],post,True)
# 输出文章连接
userName = config["url"].split("/")[-1]
print(f"ht{s}.html")

if __name__ == '__main__':
uploadArticle(sys.argv[1:])

使用

这里我使用的都是直接脚本调用,我不想进行打包,总感觉打包后执行效率变低。

如果要使用上传文章到博客圆首先要对 ​​cnblogs.json​​ 进行修改:

{
"url": "javascript:void(0)", //设置中的那个链接
"username": "Hello_wshuo", //用户名
"password": "12345678" //密码
}

配置使用typora图床:

typora实现多平台发布文章_.net_02

命令:

D:/Python36/python.exe D:/software/Typora/command/cnblogsImage.py

这里最好都使用绝对路径进行配置,否则可能会有找不到脚本的问题。


上传文章到博客园:

typora实现多平台发布文章_xml_03

命令:

D:/Python36/python.exe D:/software/Typora/command/cnblogsArticle.py ${currentPath}

​${currentPath}​​ 表示的是完整的markdown文件路径。


配置:

命令:

D:/Python36/python.exe D:/software/Typora/

文章:

typora实现多平台发布文章_xml_04

命令:

.py ${currentPath}

录(登录成功后会自动关闭窗口),登录后自动保存cookie,下次登录直接调用cookie,等到cookie过期后会重新提示扫码登录。

作者:​​Hello_wshuo​​