Python實(shí)現(xiàn)一鍵提取文本中的Markdown格式圖片鏈接
前言
經(jīng)常轉(zhuǎn)載博客的朋友可能會(huì)遇到一個(gè)頭疼的問(wèn)題:很多博客平臺(tái)不支持直接引用外站圖片,導(dǎo)致轉(zhuǎn)載后的文章圖片無(wú)法正常顯示。如果手動(dòng)一張張找圖片鏈接、復(fù)制、下載,不僅效率低,還容易遺漏。
為了解決這個(gè)問(wèn)題,我寫了一個(gè)「圖片鏈接提取與下載工具」,它能自動(dòng)從文本中提取Markdown格式的圖片鏈接(即形式),并批量下載到本地。只需粘貼文本、點(diǎn)擊提取、再點(diǎn)下載,所有圖片就能自動(dòng)保存,徹底告別手動(dòng)操作的繁瑣。
代碼倉(cāng)庫(kù)已經(jīng)上傳到github 可以通過(guò)鏈接直接下載:https://github.com/ChenAI-TGF/Extract_Fig_From_Markdown
簡(jiǎn)要代碼原理介紹
這個(gè)工具的核心功能分為兩部分:圖片鏈接提取和批量下載,我們重點(diǎn)看這兩部分的邏輯實(shí)現(xiàn)。
1. 圖片鏈接提取邏輯
Markdown中圖片的標(biāo)準(zhǔn)格式是,比如。我們需要從中提取出括號(hào)里的圖片鏈接,這里用到了正則表達(dá)式:
# 正則表達(dá)式匹配格式 pattern = r'!\[.*?\]\((.*?)\)' self.image_links = re.findall(pattern, text)
正則表達(dá)式r'!\[.*?\]\((.*?)\)'的作用:
!\[.*?\]匹配![圖片描述]部分(.*?表示非貪婪匹配,避免匹配到多個(gè)圖片時(shí)出錯(cuò));\((.*?)\)匹配(圖片鏈接)部分,其中(.*?)會(huì)捕獲括號(hào)里的鏈接內(nèi)容;re.findall會(huì)提取所有符合格式的鏈接,存到image_links列表中。
2. 批量下載邏輯
提取到鏈接后,需要將圖片批量下載到本地,核心步驟如下:
創(chuàng)建存儲(chǔ)文件夾:自動(dòng)在程序所在目錄創(chuàng)建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)
遍歷鏈接并下載:循環(huán)處理每個(gè)提取到的鏈接,用requests庫(kù)發(fā)送請(qǐng)求獲取圖片數(shù)據(jù):
for i, link in enumerate(self.image_links, 1):
# 發(fā)送請(qǐng)求獲取圖片
response = requests.get(link, timeout=10, stream=True)
response.raise_for_status() # 檢查請(qǐng)求是否成功(比如404、500錯(cuò)誤)
處理文件格式:自動(dòng)識(shí)別鏈接中的文件擴(kuò)展名(如jpg、png),如果格式不常見則默認(rèn)保存為jpg:
if '.' in link:
ext = link.split('.')[-1].lower()
# 限制常見圖片擴(kuò)展名
if ext not in ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']:
ext = 'jpg'
else:
ext = 'jpg'
保存圖片:分塊寫入圖片數(shù)據(jù)(適合大文件),避免內(nèi)存占用過(guò)高:
filename = f"{i}.{ext}" # 用序號(hào)命名,如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: # 過(guò)濾空塊
f.write(chunk)
異常處理與進(jìn)度反饋:下載過(guò)程中會(huì)捕獲錯(cuò)誤(如鏈接失效、網(wǎng)絡(luò)問(wèn)題)并提示,同時(shí)通過(guò)進(jìn)度條實(shí)時(shí)顯示下載進(jìn)度。
完整代碼
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)
# 設(shè)置中文字體支持
self.font = ('SimHei', 10)
# 創(chuàng)建UI組件
self.create_widgets()
# 存儲(chǔ)提取到的鏈接
self.image_links = []
def create_widgets(self):
# 創(chuàng)建主框架
main_frame = ttk.Frame(self.root, padding="10")
main_frame.pack(fill=tk.BOTH, expand=True)
# 文本輸入?yún)^(qū)域
ttk.Label(main_frame, text="請(qǐng)輸入包含圖片鏈接的文本:", 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))
# 按鈕區(qū)域
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)
# 進(jìn)度條
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))
# 結(jié)果顯示區(qū)域
ttk.Label(main_frame, text="提取結(jié)果與狀態(tài):", 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):
"""在結(jié)果區(qū)域顯示消息"""
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)
# 正則表達(dá)式匹配格式
pattern = r'!\[.*?\]\((.*?)\)'
self.image_links = re.findall(pattern, text)
if self.image_links:
self.log(f"成功提取到 {len(self.image_links)} 個(gè)圖片鏈接:")
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):
"""開始下載圖片(在新線程中執(zhí)行以避免UI凍結(jié))"""
if not self.image_links:
messagebox.showwarning("警告", "沒(méi)有可下載的圖片鏈接")
return
# 禁用按鈕防止重復(fù)操作
self.extract_btn.config(state=tk.DISABLED)
self.download_btn.config(state=tk.DISABLED)
# 啟動(dòng)下載線程
Thread(target=self.download_images, daemon=True).start()
def download_images(self):
"""下載圖片并保存到image文件夾"""
# 創(chuàng)建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"已創(chuàng)建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} 張圖片...")
# 發(fā)送請(qǐng)求
response = requests.get(link, timeout=10, stream=True)
response.raise_for_status() # 檢查請(qǐng)求是否成功
# 獲取文件擴(kuò)展名
if '.' in link:
ext = link.split('.')[-1].lower()
# 限制常見圖片擴(kuò)展名
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} 個(gè)鏈接): {str(e)}")
# 更新進(jìn)度條
progress = (i / total) * 100
self.progress_var.set(progress)
self.root.update_idletasks()
# 稍微延遲一下,避免請(qǐng)求過(guò)于頻繁
time.sleep(0.1)
# 下載完成
self.progress_var.set(100)
self.log(f"\n下載完成!成功下載 {success_count}/{total} 張圖片")
self.log(f"圖片保存路徑: {image_dir}")
# 恢復(fù)按鈕狀態(tài)
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()
效果演示
打開工具:運(yùn)行代碼后,會(huì)顯示一個(gè)圖形界面,包含文本輸入?yún)^(qū)、提取/下載按鈕、進(jìn)度條和結(jié)果顯示區(qū)。

輸入文本:將包含Markdown圖片格式的文本(比如從博客復(fù)制的內(nèi)容)粘貼到上方的文本輸入?yún)^(qū),例如:
這是一篇測(cè)試文章,包含3張圖片:



提取鏈接:點(diǎn)擊「提取鏈接」按鈕,工具會(huì)自動(dòng)識(shí)別并顯示所有圖片鏈接,結(jié)果區(qū)會(huì)顯示提取到的鏈接數(shù)量和具體地址,此時(shí)「下載圖片」按鈕變?yōu)榭牲c(diǎn)擊狀態(tài)。

批量下載:點(diǎn)擊「下載圖片」按鈕,工具會(huì)在程序所在目錄創(chuàng)建image文件夾,并開始下載圖片。進(jìn)度條會(huì)實(shí)時(shí)顯示下載進(jìn)度,結(jié)果區(qū)會(huì)提示每張圖片的下載狀態(tài)(成功/失敗原因)。

查看結(jié)果:下載完成后,會(huì)彈出提示框顯示成功數(shù)量和保存路徑,打開image文件夾就能看到所有下載的圖片(按1.jpg、2.png等序號(hào)命名)。
有了這個(gè)工具,轉(zhuǎn)載博客時(shí)處理圖片的效率能提升不少,再也不用手動(dòng)一個(gè)個(gè)下載了。如果需要處理其他格式的圖片鏈接,也可以通過(guò)修改正則表達(dá)式來(lái)適配,非常靈活~
以上就是Python實(shí)現(xiàn)一鍵提取文本中的Markdown格式圖片鏈接的詳細(xì)內(nèi)容,更多關(guān)于Python提取文本中圖片鏈接的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
python實(shí)現(xiàn)簡(jiǎn)單神經(jīng)網(wǎng)絡(luò)算法
這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)簡(jiǎn)單神經(jīng)網(wǎng)絡(luò)算法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-03-03
基于高德地圖API在Python中實(shí)現(xiàn)地圖功能的方法示例詳解
本文介紹在高德開放平臺(tái)中,申請(qǐng)、獲取地圖API的Key的方法,同時(shí)通過(guò)簡(jiǎn)單的Python代碼,調(diào)取API信息,對(duì)所得Key的可用性加以驗(yàn)證,感興趣的朋友一起看看吧2025-01-01
使用Python將xmind腦圖轉(zhuǎn)成excel用例的實(shí)現(xiàn)代碼(一)
這篇文章主要介紹了使用Python將xmind腦圖轉(zhuǎn)成excel用例的實(shí)現(xiàn)代碼(一),本文給大家介紹的非常詳細(xì)對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-10-10
Python3實(shí)現(xiàn)生成隨機(jī)密碼的方法
這篇文章主要介紹了Python3實(shí)現(xiàn)生成隨機(jī)密碼的方法,是Python程序設(shè)計(jì)中非常實(shí)用的一個(gè)技巧,需要的朋友可以參考下2014-08-08

