【Python】爬取Markdown文章内的图片


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

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的版本

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仓库
转自:慕雪华年


文章作者: Kezade
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Kezade !
评论
  目录