[TOC]

引言

typecho网站后台里可以撰写并发布markdown格式的文章,但是我大部分笔记是在本地typora里写的。直接复制到后台里发布是一种可行的方式,但是markdown里的图片比较难处理,要手动上传为附件,还要替换链接。我检索了typecho上传文章的方式,其中搞定 Obsidian 笔记一键发布到 Typecho 博客的方案是MetaWeblog API(基于 XML-RPC 的标准化接口规范,定义了文章、分类、标签等核心资源的 CRUD(增删改查)方法,使外部工具能以统一方式管理多平台博客)。我没有选择MetaWeblog API,因为在我实现我的思路模拟登录+post并写这篇博客之前还没有详细了解它,稍微了解它之后我认为MetaWeblog API应该比我的方案容易实现。相比之下,我的方案像是钻木取火。

目前我的方案成效差强人意,有空再尝试MetaWeblog API

我的方案主要分为两部分,首先是对文章里图片的处理,一般是托管到图床上,但是找价格合适的图床有点浪费时间,我决定直接将提取文章里的图片路径,然后上传到服务器上,上传文章前替换图片路径,上传图片时,我顺便把markdown原文也上传了,作为备份,同步到github仓库。

第二部分是如何登录并发布,我发现原来在浏览器里登录的链接并不是实际post的目标链接,这一点困住我好久,以及post以后链接的重定向,我在查看服务器nginx日志时才意识到链接重定向,需要在post时允许重定向。

上传图片

测试路径

首先用scp测试一下 ssh免密登录以及读写权限有没有配置好

scp -i D:\.ssh\id_rsa E:\2025\暑期学校报名\assets\image-20250630175256175.png hh@strangeloop.fun:/var/www/typecho/assets/test3.png  # hh用户对该目录没有权限
ssh -i D:\.ssh\id_rsa hh@strangeloop.fun

原本打算直接将图片上传到网站根目录,但是我用来上传图片的用户没有读写该位置的权限。安全起见,我不想直接用root用户上传或者修改目录权限,我选择将图片上传到当前用户(hh)有权限的目录,然后再通过软链接(symbolic link)暴露到网页服务目录中。如下:

mkdir /home/hh/blog && cd blog
mkdir assets
ln -s /home/hh/blog/assets /var/www/typecho/assets  # 软链接
scp -i D:\.ssh\id_rsa E:\2025\暑期学校报名\assets\image-20250630175256175.png hh@strangeloop.fun:/home/hh/blog/assets/test.png
#  blog用来备份博客
# strangeloop.fun/assets/test.png

image-20250706145859046

链接成功,访问网址,能访问图片,配置成功。正常情况下链接应该是绿色与蓝色,如果链接显示为红色,大概率是目标地址不存在,链接失败。

图片提取

这里直接用正则表达式匹配![图片描述](路径),typora里我设置图片存储路径为./assets/xxx.jpg,提取图片路径的正则表达式:

pattern =r'!\[.*?\]\(\.\/(assets/.*?)\)|<img\s+[^>]*src="\.\/(assets[^"]+)"'  
# 匹配 ![图片描述](https://strangeloop.fun/assets/图片路径) 的正则表达式  输出 assets/2023-10-01-1.png 这种格式

AI写的正则表达式总是离需求差一点点,所以我不得不回忆一下正则表达式。🐿️😑

最初我只提取了markdown语法的图片格式,但是后来我发现typora里的图片插入有两种语法:md和html

![alt](src)
<img src="src" alt="alt" style="zoom:xx%; float:left;"/>

html图片语法支持更多的图片操作,如缩放、调整位置。所以在代码里加入了对html语法图片的提取。

  • re.findall(pattern, string, flags=0):在字符串中查找所有与正则表达式匹配的非重叠子串,返回列表
  • re.sub(pattern, repl, string, count=0, flags=0):查找匹配正则表达式的子串,用指定内容替换

上传图片与文件

paramiko库,创建ssh连接

ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    ssh.connect(REMOTE_HOST, username=REMOTE_USER, key_filename=os.path.expanduser(SSH_KEY_PATH))
    sftp = ssh.open_sftp()

这一部分比较令人头疼的是文件路径处理,程序在windows上运行,上传图片到linux服务器上,但也就是调不同的库

# 文件路径
file_name = Path(local_md).name
remote_md_path = posixpath.join(REMOTE_BLOG_PATH, file_name)

图片链接替换

这里主要也是正则表达式,替换图片路径之后的md用于后续的上传

    content = re.sub(html_pattern, replace_html, md_content)
    content = re.sub(markdown_pattern, replace_markdown, content)

模拟登录

这里和后面的发布差不多,get登录时浏览器显示的链接,提取实际的登录链接,然后post

发布文章

image-20250705214442228

提取该链接

def extract_post_action_url(html):
    soup = BeautifulSoup(html, "html.parser")
    form = soup.find("form", {"name": "write_post"})
    if not form:
        raise Exception("❌ 未找到登录表单")
    return form.get("action")

测试

python .\publish2typecho.py --md E:\2025\博客\typecho设置.md --tags xx,xx,xx --category 折腾

image-20250707000702247

发布成功

思考

typecho里的markdown不支持文章目录,我尝试了加入tocbot ,效果一般而且难看,我不太了解前端。然后我发现两点:

  • typora能带格式导出html,并且支持目录和侧边栏
  • typora导出里可以设置运行自定义命令

所以显然我可以设置自定义命令为运行typecho自动发布的程序,这样导出的同时可以直接发布,甚至不用我手动执行脚本。实现这一点我需要做的是:读取html,上传图片,更换图片路径,发布(通过MetaWeblog API 实现)。等我有空再做。🐿️🤖

标签: python, typecho, 模拟登录

添加新评论