• .md图片链接转存并替换路径,及相关报错解决方法


    最初我想把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:codeget_mdPYtext书籍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:codeget_mdPYtext书籍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.assetsdark_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:codeget_mdPYtext书籍'):
    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:codeget_mdPYtext书籍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:codeget_mdPYtext书籍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.assetsdark_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:codeget_mdPYtext书籍'):
    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^)

  • 相关阅读:
    WPF之SharpAvi视频录制(AVI)
    WPF之录制桌面视频(FFMPeg)
    Unity3d之Navigation导航系统(AII敌人)
    Unity3D之InstantOC(遮挡剔除)
    Unity3D之Camera
    Unity3D之Material(材质、着色器、纹理)
    分布式服务弹性框架“Hystrix”实践与源码研究(一)
    平安某金所奇葩的面经-关于幂等和ROA设计的反思
    来自GitHub的Android UI开源项目
    JavaScript实现MVVM之我就是想监测一个普通对象的变化
  • 原文地址:https://www.cnblogs.com/1314h/p/14986680.html
Copyright © 2020-2023  润新知