Python实现一键提取文本中的Markdown格式图片链接

Written by

in

文章目录
  • 经常转载博客的朋友可能会遇到一个头疼的问题:很多博客平台不支持直接引用外站图片,导致转载后的文章图片无法正常显示。如果手动一张张找图片链接、复制、下载,不仅效率低,还容易遗漏。 为了解决这个问题,我写了一个「图片链接提取与下载工具」,它能自动从文本中提取Markdown格式的图片链接(即![描述](链接)形式),并批量下载到本地。只需粘贴文本、点击提取、再点下载,所有图片就能自动保存,彻底告别手动操作的繁琐。 代码仓库已经上传到github 可以通过链接直接下载:https://github.com/ChenAI-TGF/Extract_Fig_From_Markdown
  • 这个工具的核心功能分为两部分:图片链接提取和批量下载,我们重点看这两部分的逻辑实现。
  • import tkinter as tk from tkinter import scrolledtext, ttk, messagebox import re import requests import os from threading import Thread import time class ImageLinkExtractor: def __init__(self, root): self.root = root self.root.title(“图片链接提取与下载工具”) self.root.geometry(“800×600″) self.root.resizable(True, True) # 设置中文字体支持 self.font = (‘SimHei’, 10) # 创建UI组件 self.create_widgets() # 存储提取到的链接 self.image_links = [] def create_widgets(self): # 创建主框架 main_frame = ttk.Frame(self.root, padding=”10″) main_frame.pack(fill=tk.BOTH, expand=True) # 文本输入区域 ttk.Label(main_frame, text=”请输入包含图片链接的文本:”, font=self.font).pack(anchor=tk.W) self.text_input = scrolledtext.ScrolledText(main_frame, wrap=tk.WORD, font=self.font) self.text_input.pack(fill=tk.BOTH, expand=True, pady=(5, 10)) # 按钮区域 button_frame = ttk.Frame(main_frame) button_frame.pack(fill=tk.X, pady=(0, 10)) self.extract_btn = ttk.Button(button_frame, text=”提取链接”, command=self.extract_links) self.extract_btn.pack(side=tk.LEFT, padx=(0, 10)) self.download_btn = ttk.Button(button_frame, text=”下载图片”, command=self.start_download, state=tk.DISABLED) self.download_btn.pack(side=tk.LEFT) # 进度条 self.progress_var = tk.DoubleVar() self.progress_bar = ttk.Progressbar(main_frame, variable=self.progress_var, length=100) self.progress_bar.pack(fill=tk.X, pady=(0, 10)) # 结果显示区域 ttk.Label(main_frame, text=”提取结果与状态:”, font=self.font).pack(anchor=tk.W) self.result_text = scrolledtext.ScrolledText(main_frame, wrap=tk.WORD, font=self.font, height=10) self.result_text.pack(fill=tk.BOTH, expand=True) self.result_text.config(state=tk.DISABLED) def log(self, message): “””在结果区域显示消息””” self.result_text.config(state=tk.NORMAL) self.result_text.insert(tk.END, message + “n”) self.result_text.see(tk.END) self.result_text.config(state=tk.DISABLED) def extract_links(self): “””从文本中提取图片链接””” text = self.text_input.get(“1.0″, tk.END) # 正则表达式匹配![描述](链接)格式 pattern = r’![.*?]((.*?))’ self.image_links = re.findall(pattern, text) if self.image_links: self.log(f”成功提取到 {len(self.image_links)} 个图片链接:”) for i, link in enumerate(self.image_links, 1): self.log(f”{i}. {link}”) self.download_btn.config(state=tk.NORMAL) else: self.log(“未找到任何图片链接”) self.download_btn.config(state=tk.DISABLED) def start_download(self): “””开始下载图片(在新线程中执行以避免UI冻结)””” if not self.image_links: messagebox.showwarning(“警告”, “没有可下载的图片链接”) return # 禁用按钮防止重复操作 self.extract_btn.config(state=tk.DISABLED) self.download_btn.config(state=tk.DISABLED) # 启动下载线程 Thread(target=self.download_images, daemon=True).start() def download_images(self): “””下载图片并保存到image文件夹””” # 创建image文件夹 image_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), “image”) if not os.path.exists(image_dir): os.makedirs(image_dir) self.log(f”已创建image文件夹: {image_dir}”) total = len(self.image_links) success_count = 0 for i, link in enumerate(self.image_links, 1): try: self.log(f”正在下载第 {i}/{total} 张图片…”) # 发送请求 response = requests.get(link, timeout=10, stream=True) response.raise_for_status() # 检查请求是否成功 # 获取文件扩展名 if ‘.’ in link: ext = link.split(‘.’)[-1].lower() # 限制常见图片扩展名 if ext not in [‘jpg’, ‘jpeg’, ‘png’, ‘gif’, ‘bmp’, ‘webp’]: ext = ‘jpg’ else: ext = ‘jpg’ # 保存文件 filename = f”{i}.{ext}” file_path = os.path.join(image_dir, filename) with open(file_path, ‘wb’) as f: for chunk in response.iter_content(chunk_size=1024): if chunk: f.write(chunk) success_count += 1 self.log(f”成功保存: {filename}”) except Exception as e: self.log(f”下载失败 (第 {i} 个链接): {str(e)}”) # 更新进度条 progress = (i / total) * 100 self.progress_var.set(progress) self.root.update_idletasks() # 稍微延迟一下,避免请求过于频繁 time.sleep(0.1) # 下载完成 self.progress_var.set(100) self.log(f”n下载完成!成功下载 {success_count}/{total} 张图片”) self.log(f”图片保存路径: {image_dir}”) # 恢复按钮状态 self.extract_btn.config(state=tk.NORMAL) self.download_btn.config(state=tk.NORMAL) # 显示完成消息 messagebox.showinfo(“完成”, f”下载完成!成功下载 {success_count}/{total} 张图片n保存路径: {image_dir}”) if __name__ == “__main__”: root = tk.Tk() app = ImageLinkExtractor(root) root.mainloop()
  • 打开工具:运行代码后,会显示一个图形界面,包含文本输入区、提取/下载按钮、进度条和结果显示区。 输入文本:将包含Markdown图片格式的文本(比如从博客复制的内容)粘贴到上方的文本输入区,例如: 这是一篇测试文章,包含3张图片:![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fexample.com%2Fimg1.jpg&pos_id=img-1hg7yUwV-1763282765960)![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fexample.com%2Fimg2.png&pos_id=img-gW28j 81E-1763282765961)![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fexample.com%2Fimg3.webp&pos_id=img-d5i77pbw-1763282765961) 提取链接:点击「提取链接」按钮,工具会自动识别并显示所有图片链接,结果区会显示提取到的链接数量和具体地址,此时「下载图片」按钮变为可点击状态。 批量下载:点击「下载图片」按钮,工具会在程序所在目录创建image文件夹,并开始下载图片。进度条会实时显示下载进度,结果区会提示每张图片的下载状态(成功/失败原因)。 查看结果:下载完成后,会弹出提示框显示成功数量和保存路径,打开image文件夹就能看到所有下载的图片(按1.jpg、2.png等序号命名)。 有了这个工具,转载博客时处理图片的效率能提升不少,再也不用手动一个个下载了。如果需要处理其他格式的图片链接,也可以通过修改正则表达式来适配,非常灵活~ 以上就是Python实现一键提取文本中的Markdown格式图片链接的详细内容,更多关于Python提取文本中图片链接的资料请关注风君子博客其它相关文章! 您可能感兴趣的文章: Python利用Spire.OCR for Python实现从图片中提取文本和坐标 Python实现精准提取 PDF中的文本,表格与图片 Python提取Pdf文件内容的操作方法(表格、文本、图片) Python实现提取Word文档中的文本和图片 Python实现提取或替换PPT中文本与图片的示例代码
  • 目录
    • 前言
    • 简要代码原理介绍
      • 1. 图片链接提取逻辑
      • 2. 批量下载逻辑
    • 完整代码
      • 效果演示

        经常转载博客的朋友可能会遇到一个头疼的问题:很多博客平台不支持直接引用外站图片,导致转载后的文章图片无法正常显示。如果手动一张张找图片链接、复制、下载,不仅效率低,还容易遗漏。

        为了解决这个问题,我写了一个「图片链接提取与下载工具」,它能自动从文本中提取Markdown格式的图片链接(即![描述](链接)形式),并批量下载到本地。只需粘贴文本、点击提取、再点下载,所有图片就能自动保存,彻底告别手动操作的繁琐。

        代码仓库已经上传到github 可以通过链接直接下载:https://github.com/ChenAI-TGF/Extract_Fig_From_Markdown

        这个工具的核心功能分为两部分:图片链接提取批量下载,我们重点看这两部分的逻辑实现。

        Markdown中图片的标准格式是![图片描述](图片链接),比如![示例图](https://example.com/image.jpg)。我们需要从中提取出括号里的图片链接,这里用到了正则表达式:

        # 正则表达式匹配![描述](链接)格式
        pattern = r'![.*?]((.*?))'
        self.image_links = re.findall(pattern, text)
        

        正则表达式r'![.*?]((.*?))'的作用:

        • ![.*?]匹配![图片描述]部分(.*?表示非贪婪匹配,避免匹配到多个图片时出错);
        • ((.*?))匹配(图片链接)部分,其中(.*?)会捕获括号里的链接内容;
        • re.findall会提取所有符合格式的链接,存到image_links列表中。

        提取到链接后,需要将图片批量下载到本地,核心步骤如下:

        创建存储文件夹:自动在程序所在目录创建image文件夹,用于存放下载的图片:

        image_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "image")
        if not os.path.exists(image_dir):
            os.makedirs(image_dir)
        

        遍历链接并下载:循环处理每个提取到的链接,用requests库发送请求获取图片数据:

        for i, link in enumerate(self.image_links, 1):
            # 发送请求获取图片
            response = requests.get(link, timeout=10, stream=True)
            response.raise_for_status()  # 检查请求是否成功(比如404、500错误)
        

        处理文件格式:自动识别链接中的文件扩展名(如jpg、png),如果格式不常见则默认保存为jpg:

        if '.' in link:
            ext = link.split('.')[-1].lower()
            # 限制常见图片扩展名
            if ext not in ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']:
                ext = 'jpg'
        else:
            ext = 'jpg'
        

        保存图片:分块写入图片数据(适合大文件),避免内存占用过高:

        filename = f"{i}.{ext}"  # 用序号命名,如1.jpg、2.png
        file_path = os.path.join(image_dir, filename)
        with open(file_path, 'wb') as f:
            for chunk in response.iter_content(chunk_size=1024):
                if chunk:  # 过滤空块
                    f.write(chunk)
        

        异常处理与进度反馈:下载过程中会捕获错误(如链接失效、网络问题)并提示,同时通过进度条实时显示下载进度。

        import tkinter as tk
        from tkinter import scrolledtext, ttk, messagebox
        import re
        import requests
        import os
        from threading import Thread
        import time
        
        class ImageLinkExtractor:
            def __init__(self, root):
                self.root = root
                self.root.title("图片链接提取与下载工具")
                self.root.geometry("800x600")
                self.root.resizable(True, True)
                
                # 设置中文字体支持
                self.font = ('SimHei', 10)
                
                # 创建UI组件
                self.create_widgets()
                
                # 存储提取到的链接
                self.image_links = []
                
            def create_widgets(self):
                # 创建主框架
                main_frame = ttk.Frame(self.root, padding="10")
                main_frame.pack(fill=tk.BOTH, expand=True)
                
                # 文本输入区域
                ttk.Label(main_frame, text="请输入包含图片链接的文本:", font=self.font).pack(anchor=tk.W)
                self.text_input = scrolledtext.ScrolledText(main_frame, wrap=tk.WORD, font=self.font)
                self.text_input.pack(fill=tk.BOTH, expand=True, pady=(5, 10))
                
                # 按钮区域
                button_frame = ttk.Frame(main_frame)
                button_frame.pack(fill=tk.X, pady=(0, 10))
                
                self.extract_btn = ttk.Button(button_frame, text="提取链接", command=self.extract_links)
                self.extract_btn.pack(side=tk.LEFT, padx=(0, 10))
                
                self.download_btn = ttk.Button(button_frame, text="下载图片", command=self.start_download, state=tk.DISABLED)
                self.download_btn.pack(side=tk.LEFT)
                
                # 进度条
                self.progress_var = tk.DoubleVar()
                self.progress_bar = ttk.Progressbar(main_frame, variable=self.progress_var, length=100)
                self.progress_bar.pack(fill=tk.X, pady=(0, 10))
                
                # 结果显示区域
                ttk.Label(main_frame, text="提取结果与状态:", font=self.font).pack(anchor=tk.W)
                self.result_text = scrolledtext.ScrolledText(main_frame, wrap=tk.WORD, font=self.font, height=10)
                self.result_text.pack(fill=tk.BOTH, expand=True)
                self.result_text.config(state=tk.DISABLED)
            
            def log(self, message):
                """在结果区域显示消息"""
                self.result_text.config(state=tk.NORMAL)
                self.result_text.insert(tk.END, message + "n")
                self.result_text.see(tk.END)
                self.result_text.config(state=tk.DISABLED)
            
            def extract_links(self):
                """从文本中提取图片链接"""
                text = self.text_input.get("1.0", tk.END)
                
                # 正则表达式匹配![描述](链接)格式
                pattern = r'![.*?]((.*?))'
                self.image_links = re.findall(pattern, text)
                
                if self.image_links:
                    self.log(f"成功提取到 {len(self.image_links)} 个图片链接:")
                    for i, link in enumerate(self.image_links, 1):
                        self.log(f"{i}. {link}")
                    self.download_btn.config(state=tk.NORMAL)
                else:
                    self.log("未找到任何图片链接")
                    self.download_btn.config(state=tk.DISABLED)
            
            def start_download(self):
                """开始下载图片(在新线程中执行以避免UI冻结)"""
                if not self.image_links:
                    messagebox.showwarning("警告", "没有可下载的图片链接")
                    return
                
                # 禁用按钮防止重复操作
                self.extract_btn.config(state=tk.DISABLED)
                self.download_btn.config(state=tk.DISABLED)
                
                # 启动下载线程
                Thread(target=self.download_images, daemon=True).start()
            
            def download_images(self):
                """下载图片并保存到image文件夹"""
                # 创建image文件夹
                image_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "image")
                if not os.path.exists(image_dir):
                    os.makedirs(image_dir)
                    self.log(f"已创建image文件夹: {image_dir}")
                
                total = len(self.image_links)
                success_count = 0
                
                for i, link in enumerate(self.image_links, 1):
                    try:
                        self.log(f"正在下载第 {i}/{total} 张图片...")
                        
                        # 发送请求
                        response = requests.get(link, timeout=10, stream=True)
                        response.raise_for_status()  # 检查请求是否成功
                        
                        # 获取文件扩展名
                        if '.' in link:
                            ext = link.split('.')[-1].lower()
                            # 限制常见图片扩展名
                            if ext not in ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']:
                                ext = 'jpg'
                        else:
                            ext = 'jpg'
                        
                        # 保存文件
                        filename = f"{i}.{ext}"
                        file_path = os.path.join(image_dir, filename)
                        
                        with open(file_path, 'wb') as f:
                            for chunk in response.iter_content(chunk_size=1024):
                                if chunk:
                                    f.write(chunk)
                        
                        success_count += 1
                        self.log(f"成功保存: {filename}")
                        
                    except Exception as e:
                        self.log(f"下载失败 (第 {i} 个链接): {str(e)}")
                    
                    # 更新进度条
                    progress = (i / total) * 100
                    self.progress_var.set(progress)
                    self.root.update_idletasks()
                    
                    # 稍微延迟一下,避免请求过于频繁
                    time.sleep(0.1)
                
                # 下载完成
                self.progress_var.set(100)
                self.log(f"n下载完成!成功下载 {success_count}/{total} 张图片")
                self.log(f"图片保存路径: {image_dir}")
                
                # 恢复按钮状态
                self.extract_btn.config(state=tk.NORMAL)
                self.download_btn.config(state=tk.NORMAL)
                
                # 显示完成消息
                messagebox.showinfo("完成", f"下载完成!成功下载 {success_count}/{total} 张图片n保存路径: {image_dir}")
        
        if __name__ == "__main__":
            root = tk.Tk()
            app = ImageLinkExtractor(root)
            root.mainloop()
        

        打开工具:运行代码后,会显示一个图形界面,包含文本输入区、提取/下载按钮、进度条和结果显示区。

        输入文本:将包含Markdown图片格式的文本(比如从博客复制的内容)粘贴到上方的文本输入区,例如:

        这是一篇测试文章,包含3张图片:
        ![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fexample.com%2Fimg1.jpg&pos_id=img-1hg7yUwV-1763282765960)
        ![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fexample.com%2Fimg2.png&pos_id=img-gW28j 81E-1763282765961)
        ![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fexample.com%2Fimg3.webp&pos_id=img-d5i77pbw-1763282765961)

        提取链接:点击「提取链接」按钮,工具会自动识别并显示所有图片链接,结果区会显示提取到的链接数量和具体地址,此时「下载图片」按钮变为可点击状态。

        批量下载:点击「下载图片」按钮,工具会在程序所在目录创建image文件夹,并开始下载图片。进度条会实时显示下载进度,结果区会提示每张图片的下载状态(成功/失败原因)。

        查看结果:下载完成后,会弹出提示框显示成功数量和保存路径,打开image文件夹就能看到所有下载的图片(按1.jpg、2.png等序号命名)。

        有了这个工具,转载博客时处理图片的效率能提升不少,再也不用手动一个个下载了。如果需要处理其他格式的图片链接,也可以通过修改正则表达式来适配,非常灵活~

        以上就是Python实现一键提取文本中的Markdown格式图片链接的详细内容,更多关于Python提取文本中图片链接的资料请关注风君子博客其它相关文章!

        您可能感兴趣的文章:

        • Python利用Spire.OCR for Python实现从图片中提取文本和坐标
        • Python实现精准提取 PDF中的文本,表格与图片
        • Python提取Pdf文件内容的操作方法(表格、文本、图片)
        • Python实现提取Word文档中的文本和图片
        • Python实现提取或替换PPT中文本与图片的示例代码

        站内搜索