【Python】自动解析markdown中的图片并保存

news/2025/1/22 5:52:32/

python自动化下载/上传md中图片实在是太方便了

1.起因

为什么需要python来下载md里面的图片?原因很简单,那就是需要把图片保存下来,上传到第二个图床(迁移)

对于阿里云OSS来说,有两种迁移办法

  • 使用官方的数据导出功能
  • 使用api接口遍历oss目录下载所有图片

这两种办法都不是那么方便,所以我选择了第三种

  • 解析本地md文件中的img url,下载图片并保存到本地

那要怎么做呢?👇

2.教程

我在github找到了这个项目 👉 Deali-Axy/Markdown-Image-Parser

作者的代码写的很棒,但是README里面却少了一个重要的启动教程,那就是你需要在当前目录下创建一个files文件夹(md文件放到这里面),对应启动项里面开启的根目录

if __name__ == '__main__':files_list = get_files_list(os.path.abspath(os.path.join('.', 'files')))

随后,执行python spider.py,开始运行,脚本会自动将md转成html并下载图片

我将作者的代码进一步细化,并修改了一部分bug👇建议使用我fork的版本

https://github.com/musnows/Markdown-Image-Parser

2.1 UnicodeDecodeError

在启动的时候,你可能会遇到这个报错

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xbc in position 2: invalid start byt

解决办法参考 👉 点我

解决办法是将打开文件编码的utf-8 修改成ISO-8859-1

 with open(file, encoding='ISO-8859-1') as f:md_content = f.read()

2.2 request failed

因为作者并没有写判断,此时就会出现一个严重问题:本地图片也会进行requests请求

比如我的md里面就有一些图片是本地的img/图片文件名,这个代码依旧对这个路径当做网络路径进行请求,于是就出现了报错

所以就需要在download_pics函数中对url进行判断,这里可以写成下面的格式(因为我知道我的阿里云OSS链接里面不包含img文件夹,所以img/的图片是本地文件

def download_pics(url, file,MDfilename):if 'img/' in url:print('不处理本地图片: ', url)return

但是这样其实还是有点呆呆的,我们直接判断http在不在里面不就知道是不是网络图片了😂

def download_pics(url, file,MDfilename):if 'http' not in url:print('不处理本地图片: ', url)return

2.3 图片保存路径

默认情况下,图片会保存到子文件夹下的markdown文件名目录

    targer_dir = os.path.join(dirname,assert_dir)if not os.path.exists(targer_dir):os.mkdir(targer_dir)

这样其实非常非常不方便管理,有几个md文档就有几个md图片路径,可太难受了

所以我们需要注释掉这部分代码,直接选择一个根目录进行图片的保存

targer_dir ='./files/img/' # 所有图片都保存到 ./files/img/ 文件夹里面

2.4 try/except

作者代码里面的最最最大漏洞,那就是没有对for循环里面的请求进行try/except

这样就会导致,如果有一个图片请求失败,整个进程会直接终止

那么问题就来了,即便这个程序会在遍历的时候打印当前处理的文件名字,但这需要用户去翻命令行输出,再找到到底是哪一个图片发生错误,非常非常非常难受!

如果重新执行,那就相当与把已经下好的图片又重下一遍,浪费OSS的流量。

所以我们必须要给for循环内部添加上异常捕获,如果遇到错误,就将这个图片的url存下来,继续往后执行!

    for file in files_list:print(f'正在处理:{file}')with open(file, encoding='ISO-8859-1') as f:md_content = f.read()pics_list = get_pics_list(md_content)print(f'发现图片 {len(pics_list)} 张')for index, pic in enumerate(pics_list):try:print(f'正在下载第 {index + 1} 张图片...')MDfilename = os.path.basename(file) # 当前处理的md文件的名字download_pics(pic, file,MDfilename)time.sleep(0.5) # 避免下载超速except KeyboardInterrupt:os.abort()except:print(traceback.format_exc())if MDfilename not in err_img:err_img[MDfilename]=[]# 添加图片err_img[MDfilename].append(pic)print("图片获取错误:",pic)time.sleep(1)print(f'处理完成。')write_file('err.json',err_img)print(f'写入err完成')

完整代码见我的github仓库

2.5 上传到lsky图床

现在我要迁移的图床是lsky,所以为了方便,可以在将图片保存到本地的同时,将图片上传到lsky图床

注意,上传之前,请在用户组将图片上传的格式改为原始文件命名,否则重命名了那就什么都没了!

image-20230204083922313

还发现了一个离谱的问题,那就是一些图片上传了之后,lsky还是会给他改名字!!!

image-20230204084005425

比如这个gif,他的alt里面是原始名字,但是url并不是!!!你说这离谱不

解决方法那就是把本地的图片打一个压缩包,传到云服务器后台存储路径中覆盖一遍,把没有的图片给添加上

unzip -o ~/docker/img.zip -d ~/docker/lsky/storage/app/uploads/23/02

上传之前,先获取token

def lsky():url = "服务器地址/api/v1/tokens"params = {'email':'账户邮箱','password':'密码'}res = requests.post(url,  params=params)  # 请求apireturn res.json()

结果如下

{'status': True, 'message': 'success', 'data': {'token': '这里会返回token'}}

随后是上传的代码,注意兰空必须要用open 'rb'重新打开一边图片,所以参数给img_path也就是图片的路径即可

# 兰空图床
def lsky_upload(img_path:str):url = "你的兰空图床服务器/api/v1/upload"header = {"Authorization": "Bearer 你的兰空token","Accept": "application/json"}img = open(img_path, 'rb')params = {'strategy_id': 1}myfiles = {'file': img}res = requests.post(url, headers=header, params=params,files=myfiles)  # 请求apireturn res.json()

download_pics的末尾添加如下代码,并对兰空图床的返回值进行判断,如果上传错误,同样添加到错误图片中!

    # 上传lskyres = lsky_upload(img_path=f"{targer_dir}/{filename}")print(res)if not res['status']:global err_imgif MDfilename not in err_img:err_img[MDfilename]=[]err_img[MDfilename].append(url)print("兰空上传错误!",url)time.sleep(1)

上传成功的返回值status是True

3.开始自动化上传

将上面的bug修改好了之后,就可以正式运行,在保存图片到本地的同时,上传到兰空图床了!

image-20230204074327382

图片也都成功保存到本地了

image-20230208190951728

上传完毕之后,也能在err里面看到错误的图片路径,以便重新处理。

可以看到这里面有一部分是gitee和csdn的链接,这些图片有防盗链,而且图片尾部添加了其他字段,导致lsky没有办法将其识别为图片(却少图片格式后缀)

不过我的目标是将阿里云OSS的图片转到lsky,这些本来就不是阿里云OSS的图片和我的目的无关!

image-20230204080115678

做完这一切,最让我感慨的是,我的阿里云oss里面有1g的图片,实际用的却只有下面这一丢丢;其他估计都是重复上传的

image-20230204085611110

文章来源:https://blog.csdn.net/muxuen/article/details/128941666
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ppmy.cn/news/23248.html

相关文章

((蓝桥杯 刷题全集)【备战(蓝桥杯)算法竞赛-第4天(搜索与图论-下 专题)】( 从头开始重新做题,记录备战竞赛路上的每一道题 )距离蓝桥杯还有63天

🏆🏆🏆🏆🏆🏆🏆 欢迎观看我的博客,如有问题交流,欢迎评论区留言,一定尽快回复!(大家可以去看我的专栏,是所有文章的目录&a…

【微信小程序】在WXML文件中显示JS文件中全局变量的方法

前言我们知道在wxml中可以通过数据绑定的方法来获取到js文件中data里面的数据,并且显示到wxml界面,那么我们该如何在wxml中显示js文件里面的全局变量呢?显示data里面数据的方法在wxml种我们可以显示js代码中data代码段中的变量。具体的操作是…

Jenkins部署及持续集成——傻瓜式教程

文章目录jenkins安装jenkins启动jenkins登录jenkins插件Jenkin创建一个项目通过Git进行构建构建策略jenkins安装 jenkins官网 https://www.jenkins.io/ 支持Docker pull下载安装 我用的windows,这里下载war包,这个位置下载的是最新的,需要java11或者更…

C++类和对象:面向对象编程的核心。| 面向对象还编什么程啊,活该你是单身狗。

👑专栏内容:C学习笔记⛪个人主页:子夜的星的主页💕座右铭:日拱一卒,功不唐捐 文章目录一、前言二、面向对象编程三、类和对象1、类的引入2、类的定义Ⅰ、声明和定义在一起Ⅱ、声明和定义分开Ⅲ、成员变量命…

P1616 疯狂的采药

题目背景此题为纪念 LiYuxiang 而生。题目描述LiYuxiang 是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说&…

windows webrtc vs2019编译大坑

通过该网址的方法cmd下编译成功。 Windows平台WebRTC编译-VS2017 - 剑痴乎 (jianchihu.net)但是用vs打开,无法编译调试,报错:ninja.exe 不是内部或外部命令,也不是可运行的程序在cmd执行ninja是ok的,但执行ninja.exe就…

工程复现 -- grid map和elevation map

工程复现 – grid map和elevation map 参考: 1. ROS grid map 2. ROS elevation_mapping 3. ROS高程地图–elevation_mapping使用记录(一) 4. ROS高程地图–elevation_mapping使用记录(二) 一.下载和编译安装工程 …

常用的数据集成ETL工具有哪些?

一、Informatica Informatica是全球领先的数据管理软件提供商。在如下 Gartner魔力象限位于领导者地位:数据集成工具魔力象限、数据质量工具魔力象限、元数据管理解决方案魔力象限、主数据管理解决方案魔力象限、企业级集成平台即服务(EiPaaS)魔力象限。 InformaticaEnterpri…