最初我想把Typora中.md文件中的web图片链接都下载保存到本地,并且替换.md文本中的路径

说干就干,因为在网上没有找到现成的程序所以自己写了这个程序

思路是循环查找文件夹中的文件,然后yield返回

再用readlines()方法读取该文件,开始是采用 r 模式读取,后来遇到一些编码问题就改为 rb 模式,后面会介绍

获取文件中的数据后按行得到了一个list,再对每行进行正则匹配,匹配到图片链接就进行下载,并返回该文件名

再用正则替换该文件内容,大致就是这样

从文件夹获取文件函数

def get_files(dir):
"""
获取一个目录下所有文件列表,包括子目录
:param dir:
:return:
"""
for root, dirs, files in os.walk(dir, topdown=False):
if 'HTML' in root or '.assets' in root:  # 文件过滤
continue
for file in files:
if '.zip' in file:
continue
yield os.path.join(root, file)

 得到文件路径进行读取, 但显示编码报错 "UnicodeDecodeError: 'gbk' codec can't decode byte 0x80 in position 48: illegal multibyte sequence"

with open(file, 'r') as f:

然后我试了加encoding="gbk"和utf-8编码格式都不行,最后采取rb二进制读取解决此问题

下面是对数据匹配后进行替换,代码如下

def thread_task(file, md_content):
"""
多线程任务
:param file:文件路径
:param md_content:文件转为list二进制数据
:return:
"""
print(f'正在处理:{file}')
for index, url in enumerate(md_content):
if uu := re.findall(br'\((http|https://.+\.\w+)\)', url):
print(f'下载中:{uu[0]}')
if file_name := download_pics(uu[0].decode(), file):
md_content[index] = re.sub(br'\((http|https://.+\.\w+)\)', f'({file_name})'.encode(), url)
with open(file, 'wb') as f:
f.writelines(md_content)
f.close()
sem.release()
 

代码中用到了海象运算符,所以python版本要在3.8及以上,或者自行改动一点代码就能使用

因为一个文件中有许多个图片链接,所以我采用readlines方式读取,得到一个list的二进制数据文件

在对该文件数据进行正则匹配,但是匹配时候报错 "TypeError: cannot use a string pattern on a bytes-like object"

解决方法就是在正则匹配语句前加上 b 转为对二进制匹配,不加b默认是字符串匹配,参考如下

re.findall(br'\((http|https://.+\.\w+)\)', url)

下面是下载文档中图片链接的代码,源码如下

def download_pics(url, file):
"""
下载图片
:param url: https://matplotlib.org/_images/sphx_glr_dark_background_001.png
:param file: D:\code\get_md\PYtext\书籍\Matplotlib 参考实例\MD\第10章 样式表.md
:return:
"""
try:
img_data = requests.get(url).content
except Exception as e:
print(f'路径:{file} 下载出错:{e}')
return
filename = os.path.basename(file) # 第10章 样式表.md
dirname = os.path.dirname(file) # D:\code\get_md\PYtext\书籍\Matplotlib 参考实例\MD
targer_dir = os.path.join(dirname, f'{filename}.assets')
if not os.path.exists(targer_dir):
os.mkdir(targer_dir)
with open(os.path.join(targer_dir, os.path.basename(url)), 'w+') as f: # \Matplotlib 参考实例\MD\第10章 样式表.md.assets\dark_background_001.png
f.buffer.write(img_data)
f.close()
print(url, '下载成功')
return f'{filename}.assets/{os.path.basename(url)}'

创建文件夹下载图片保存到里面,也没啥需要多讲的 略过~

下一步进行多线程优化,代码如下

def main():
for file in get_files(r'D:\code\get_md\PYtext\书籍'):
with open(file, 'rb') as f:
sem.acquire()
Thread(target=thread_task, args=(file, f.readlines())).start()
f.close()
# thread_task(file, f.readlines())

下面是完整的程序源码,分享给有需要的同志

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@Project :get_md
@File :img to local.py
@IDE :PyCharm
@Author :Naihe
@Date :2021/7/6 14:51
"""
import os
import re
import requests
import threading

from threading import Thread

sem = threading.Semaphore(5) # 限制线程的最大数量

def get_files(dir):
"""
获取一个目录下所有文件列表,包括子目录
:param dir:
:return:
"""
for root, dirs, files in os.walk(dir, topdown=False):
if 'HTML' in root or '.assets' in root:
continue
for file in files:
if '.zip' in file:
continue
yield os.path.join(root, file)

def download_pics(url, file):
"""
下载图片
:param url: https://matplotlib.org/_images/sphx_glr_dark_background_001.png
:param file: D:\code\get_md\PYtext\书籍\Matplotlib 参考实例\MD\第10章 样式表.md
:return:
"""
try:
img_data = requests.get(url).content
except Exception as e:
print(f'路径:{file} 下载出错:{e}')
return
filename = os.path.basename(file) # 第10章 样式表.md
dirname = os.path.dirname(file) # D:\code\get_md\PYtext\书籍\Matplotlib 参考实例\MD
targer_dir = os.path.join(dirname, f'{filename}.assets')
if not os.path.exists(targer_dir):
os.mkdir(targer_dir)
with open(os.path.join(targer_dir, os.path.basename(url)), 'w+') as f: # \Matplotlib 参考实例\MD\第10章 样式表.md.assets\dark_background_001.png
f.buffer.write(img_data)
f.close()
print(url, '下载成功')
return f'{filename}.assets/{os.path.basename(url)}'

def thread_task(file, md_content):
"""
多线程任务
:param file:文件路径
:param md_content:文件转为list二进制数据
:return:
"""
print(f'正在处理:{file}')
for index, url in enumerate(md_content):
if uu := re.findall(br'\((http|https://.+\.\w+)\)', url):
print(f'下载中:{uu[0]}')
if file_name := download_pics(uu[0].decode(), file):
md_content[index] = re.sub(br'\((http|https://.+\.\w+)\)', f'({file_name})'.encode(), url)
with open(file, 'wb') as f:
f.writelines(md_content)
f.close()
sem.release()

def main():
for file in get_files(r'D:\code\get_md\PYtext\书籍'):
with open(file, 'rb') as f:
sem.acquire()
Thread(target=thread_task, args=(file, f.readlines())).start()
f.close()
# thread_task(file, f.readlines())

if __name__ == '__main__':
sem = threading.Semaphore(4) # 限制线程的最大数量为4个
main()

码字不易,还请各位三连鼓励(^v^)

.md图片链接转存并替换路径,及相关报错解决方法的更多相关文章

  1. vue 动态加载图片路径报错解决方法

    最近遇到图片路径加载报错的问题 之前一直都是把图片放到assets的文件下的.总是报错,看到一些文章并且尝试成功了,特意记录下 首先先说明下vue-cli的assets和static的两个文件的区别, ...

  2. 搭建lamp或者lnmp环境,本地链接mysql报错解决方法

    报错:1130-host...is not allowed to connect to this mysql server 解决方法: 1.改表法 可能是你的账号不允许从远程登录,这个时候只要进入服务 ...

  3. python listdir() 中文路径 中文文件夹 乱码 解决方法

    python listdir() 中文路径 中文文件夹 乱码 解决方法 listdir(path)返回的结果的编码似乎和我们提供的 path 参数的编码有关: path = 'd:/test' try ...

  4. pod导入融云路径报错解决办法

    build Settings中搜索sear Search Patchs下点开Library Search Paths 将$(inherited)"$(SRCROOT)/Pods"分 ...

  5. vue-cli项目 build后请求本地static文件中的 json数据,路径不对,报错404处理方法

    vue-cli 项目 build  出错点: 1,build生成dist 放在tomcat上 报错,不显示内容  解决办法: config>index.js===>assetsPublic ...

  6. vue项目打包后一片空白及资源引入的路径报错解决办法

    网上很多说自己的VUE项目通过Webpack打包生成的list文件,放到HBulider打包后,通过手机打开一片空白.这个主要原因是路径的问题. 1.记得改一下config下面的index.js中bu ...

  7. TP3.2框架,实现空模块、空控制器、空操作的页面404替换||同步实现apache报错404页面替换

    一,前言 一.1)以下代码是在TP3.0版本之后,URL的默认模式=>PATHINFO的前提下进行的.(通俗点,URL中index.php必须存在且正确) 代码和讲解如下: 1.空模块解决:ht ...

  8. vue2.0 在页面中使用process获取全局路径的时候 报错 process is not defined

    如果是刚配置好的全局变量需要 重新启动一下vue才能通过proccess.env.xxx 获取到 如果想在html中使用 需要在data中声明一个变量 然后在vue生命周期中 将process.env ...

  9. SQL Server 2008 修改安装路径后安装出错的解决方法

    1.安装时如果修改安装路径后报错 例如想把“C:\Program Files\Microsoft SQL Server” 修改为“D:\Program Files\Microsoft SQL Serv ...

随机推荐

  1. SAP -SE30 程序运行时间分析

    运行SE30 选中Program,点击Excute 点击运行 分析结果

  2. 2022giao考游记

    Day -12: 今年高考准备去考着玩玩,考前心态十分稳健.~~毕竟我才高一/cy~~ 这次高考我倒是没啥目标,主要是来试试水,感受一下高考的氛围,体会一下自己和高三应届生们的水平的差距.也算是丰富自 ...

  3. labelimg使用指南

    labelimg使用指南 From RSMX - https://www.cnblogs.com/rsmx/ 目录 labelimg使用指南 1. 确保已经安装了 Python 环境 2. 使用pip ...

  4. Oracle 创建表空间及用户授权、dmp数据导入、表空间、用户删除

    1.创建表空间 // 创建表空间 物理位置为'C:\app\admin\oradata\NETHRA\NETHRA.DBF',初始大小100M,当空间不足时自动扩展步长为10M create tabl ...

  5. NC16618 [NOIP2008]排座椅

    NC16618 [NOIP2008]排座椅 题目 题目描述 上课的时候总有一些同学和前后左右的人交头接耳,这是令小学班主任十分头疼的一件事情.不过,班主任小雪发现了一些有趣的现象,当同学们的座次确定下 ...

  6. MongoDB 的安装和基本操作

    MongoDB 的安装 使用 docker 安装 下载镜像: docker pull mongo:4.4.8(推荐,下载指定版本) docker pull mongo:latest (默认下载最新版本 ...

  7. CF1656E Equal Tree Sums 题解

    题目链接 思路分析 自认为是一道很好的构造题,但是我并不会做. 看了题解后有一些理解,在这里再梳理一遍巧妙的思路. 我们先来看这样的一张图: 我们发现当去掉叶子节点的父亲时,剩下树的价值和等于叶子节点 ...

  8. Intel的CPU系列说明

    至强可扩展系列是英特尔推出的新一代至强处理器系列,如今距离该系列推出几乎过去一年了.新的CPU并没有延续E系列的命名,英特尔将至强可扩展系列以金属命名,将该系列分为"铂金Platinum&q ...

  9. SimpleDateFormat类介绍和 DateFormat类的format方法和parse方法

    使用 SimpleDateFormat格式化日期 SimpleDateFormat 是一个以语言环境敏感的方式来格式化和分析日期的类.SimpleDateFormat 允许你选择任何用户自定义日期时间 ...

  10. 超酷炫的转场动画?CSS 轻松拿下!

    在 WeGame 的 PC 端官网首页,有着非常多制作精良的基于滚动的动画效果. 这里我简单截取其中 2 个比较有意思的转场动画,大家感受感受.转场动画 1: 转场动画 2: 是不是挺有意思的,整个动 ...