关于批量替换epub文件中图片的尝试
epub通常是用Kindle等黑白阅读器阅读,所以往往不需要图片质量太高,彩色高质量图片往往还体积庞大,有必要瘦身。
因为epub本身就是zip封装,所以最开始的想法也就是将其完整解压出来,替换掉image文件夹中的图片,再封装回去。
但是……
好,首先来解决图片瘦身的问题,采用的方案是灰阶化加缩小:
1 | import os |
上面有一段保持原文件名编码的部分很重要,因为有些文件名中的特殊字符会被某些程序更改,比如此例中的全角斜杠 /
会被自动替换为 ú»
,在压缩文件包中有时就会如此显示(win文件夹中显示正常,因为win会“猜测”修正)。之后的再更名为epub也会如此操作,epub应该不支持某些字符,比如全角斜杠 /
,会将它自动替换为 ú»
,而文章的html文件中的<img src=
仍保留并继续寻找全角斜杠 /
的地址,所以就会显示不出图片。
如上完成图片的批量瘦身后,用其替换掉解压来的image文件夹中的内容。
然后再将解压出来的epub文件重新封装回去,这里有需要注意的地方。
本来以为只是个zip压缩文件,就丢进惯常所用的winrar中算了,结果在更名epub后直接打不开,提示并非可用的zip文件。
上网查了一下,发现是因为epub中的mimetype
文件不可压缩,且必须放在第一个(这个似乎倒无所谓),它大概相当于一个导航式的文件,不能压缩。那么干脆,所有的文件都不压缩了,使用7zip的存储
模式,将替换过image内容的epub文件都放入,然后改名epub,可以打开了。
可以打开重新打包的epub进行阅读了。
但然后你会发现,一切都没问题,只是文章中所有图片都显示红叉叉。这种一般都是图片未能加载的问题了,也就是说,<img src=
中的图片地址与真实图片地址未能映射一致的问题。
经过仔细查对(在Calibre的Editor中对照html和左侧文件视图中的图片,发现前者是全角斜杠/,后者是ú»),就是前面说的那种文件名编码在转换过程中自动更改的情况。
问题很清楚了,就是在改为epub的过程中,可能是因为epub不支持全角斜杠 /
的文件名编码,所以全部自动替换成了 ú»
。所以,解决方案也有两种,一是改图片文件名,二是改html中的调用地址,于是分别写了两版程序:
-
改图片文件名
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389import os
import zipfile
import tempfile
import shutil
import re
from pathlib import Path
import xml.etree.ElementTree as ET
from bs4 import BeautifulSoup
import fnmatch
class EpubSlashFixer:
"""EPUB全角斜杠修复工具 - 统一将 ú» 修复为正确的全角斜杠 /"""
def __init__(self, epub_path):
self.epub_path = os.path.abspath(epub_path)
self.temp_dir = None
self.fixed_files = 0
self.fixed_references = 0
self.processed_files = []
def extract_epub(self):
"""解压EPUB文件到临时目录"""
self.temp_dir = tempfile.mkdtemp(prefix="epub_fix_")
print(f"📦 解压EPUB到临时目录: {self.temp_dir}")
try:
with zipfile.ZipFile(self.epub_path, 'r') as zf:
zf.extractall(self.temp_dir)
print("✅ EPUb解压完成")
return True
except Exception as e:
print(f"❌ EPUb解压失败: {e}")
return False
def find_files_with_mojibake(self):
"""查找所有包含 ú» 的文件和目录"""
mojibake_files = []
mojibake_dirs = []
for root, dirs, files in os.walk(self.temp_dir):
# 检查目录名
for dir_name in dirs:
if 'ú»' in dir_name:
full_path = os.path.join(root, dir_name)
mojibake_dirs.append(full_path)
# 检查文件名
for file_name in files:
if 'ú»' in file_name:
full_path = os.path.join(root, file_name)
mojibake_files.append(full_path)
return mojibake_files, mojibake_dirs
def rename_files_and_dirs(self):
"""重命名所有包含 ú» 的文件和目录"""
print("🔧 开始重命名文件和目录...")
files, dirs = self.find_files_with_mojibake()
total_items = len(files) + len(dirs)
if total_items == 0:
print("✅ 未发现需要重命名的文件或目录")
return True
print(f"📊 发现 {total_items} 个需要重命名的项目")
# 先重命名目录(从深到浅)
dirs.sort(key=lambda x: x.count(os.sep), reverse=True)
for dir_path in dirs:
self.rename_item(dir_path, is_dir=True)
# 重命名文件
for file_path in files:
self.rename_item(file_path, is_dir=False)
print(f"✅ 重命名完成: {self.fixed_files} 个项目已修复")
return True
def rename_item(self, old_path, is_dir=False):
"""重命名单个文件或目录"""
try:
old_name = os.path.basename(old_path)
parent_dir = os.path.dirname(old_path)
# 替换 ú» 为 /
new_name = old_name.replace('ú»', '/')
new_path = os.path.join(parent_dir, new_name)
# 确保新路径不存在
if not os.path.exists(new_path):
os.rename(old_path, new_path)
item_type = "目录" if is_dir else "文件"
print(f"✅ {item_type}重命名: {old_name} → {new_name}")
self.fixed_files += 1
self.processed_files.append((old_path, new_path))
else:
print(f"⚠️ 跳过: {new_name} 已存在")
except Exception as e:
print(f"❌ 重命名失败 {old_path}: {e}")
def update_content_references(self):
"""更新所有内容文件中的引用"""
print("🔧 开始更新文件引用...")
content_files = self.find_content_files()
for file_path in content_files:
try:
with open(file_path, 'r', encoding='utf-8') as f:
content = f.read()
# 检查是否包含 ú»
if 'ú»' in content:
# 替换所有 ú» 为 /
new_content = content.replace('ú»', '/')
with open(file_path, 'w', encoding='utf-8') as f:
f.write(new_content)
print(f"📄 更新引用: {os.path.basename(file_path)}")
self.fixed_references += 1
except UnicodeDecodeError:
# 跳过二进制文件
continue
except Exception as e:
print(f"⚠️ 处理文件失败 {file_path}: {e}")
def find_content_files(self):
"""查找所有需要检查的内容文件"""
content_extensions = [
'.html', '.htm', '.xhtml', # HTML文件
'.css', # 样式表
'.opf', '.ncx', # EPUB元数据文件
'.xml', # 其他XML文件
'.txt', '.js' # 文本和脚本文件
]
content_files = []
for root, dirs, files in os.walk(self.temp_dir):
for file in files:
if any(file.endswith(ext) for ext in content_extensions):
content_files.append(os.path.join(root, file))
return content_files
def update_opf_manifest(self):
"""专门处理OPF文件中的manifest条目"""
print("🔧 检查OPF文件清单...")
opf_files = []
for root, dirs, files in os.walk(self.temp_dir):
for file in files:
if file.endswith('.opf'):
opf_files.append(os.path.join(root, file))
for opf_file in opf_files:
try:
# 读取文件内容
with open(opf_file, 'r', encoding='utf-8') as f:
content = f.read()
# 检查是否包含 ú»
if 'ú»' in content:
# 替换所有 ú» 为 /
new_content = content.replace('ú»', '/')
with open(opf_file, 'w', encoding='utf-8') as f:
f.write(new_content)
print(f"📋 更新OPF清单: {os.path.basename(opf_file)}")
except Exception as e:
print(f"❌ 处理OPF文件失败 {opf_file}: {e}")
def repack_epub(self, output_path):
"""重新打包EPUB文件"""
print(f"📦 重新打包EPUB: {output_path}")
try:
# 确保输出目录存在
os.makedirs(os.path.dirname(output_path), exist_ok=True)
with zipfile.ZipFile(output_path, 'w', zipfile.ZIP_DEFLATED) as epub:
# 首先添加mimetype(必须无压缩)
mimetype_path = os.path.join(self.temp_dir, 'mimetype')
if os.path.exists(mimetype_path):
epub.write(mimetype_path, 'mimetype', zipfile.ZIP_STORED)
print("📄 添加mimetype文件")
# 添加其他所有文件
for root, dirs, files in os.walk(self.temp_dir):
for file in files:
if file != 'mimetype': # mimetype已经处理过了
file_path = os.path.join(root, file)
# 计算相对路径
arcname = os.path.relpath(file_path, self.temp_dir)
epub.write(file_path, arcname)
print("✅ EPUb重新打包完成")
return True
except Exception as e:
print(f"❌ EPUb打包失败: {e}")
return False
def cleanup(self):
"""清理临时文件"""
if self.temp_dir and os.path.exists(self.temp_dir):
shutil.rmtree(self.temp_dir)
print("🧹 清理临时文件")
def run(self, output_path=None):
"""运行完整的修复流程"""
if not os.path.exists(self.epub_path):
print(f"❌ 文件不存在: {self.epub_path}")
return False
if not output_path:
# 默认输出路径:原文件名_fixed.epub
base_dir = os.path.dirname(self.epub_path)
base_name = os.path.splitext(os.path.basename(self.epub_path))[0]
output_path = os.path.join(base_dir, f"{base_name}_fixed.epub")
print(f"🔄 开始修复EPUB: {self.epub_path}")
print("=" * 60)
# 解压EPUB
if not self.extract_epub():
return False
try:
# 执行修复步骤
self.rename_files_and_dirs() # 重命名文件和目录
self.update_content_references() # 更新内容文件引用
self.update_opf_manifest() # 更新OPF清单
# 重新打包
success = self.repack_epub(output_path)
if success:
print("\n🎯 修复完成!")
print("=" * 40)
print(f"📊 修复统计:")
print(f" 重命名项目: {self.fixed_files}")
print(f" 更新引用: {self.fixed_references}")
print(f" 输出文件: {output_path}")
return success
except Exception as e:
print(f"❌ 修复过程中出错: {e}")
return False
finally:
self.cleanup()
class BatchEpubFixer:
"""批量EPUB修复工具"""
def __init__(self, directory):
self.directory = os.path.abspath(directory)
self.processed_count = 0
self.failed_files = []
def find_epub_files(self):
"""查找目录中的所有EPUB文件"""
epub_files = []
for root, dirs, files in os.walk(self.directory):
for file in files:
if file.lower().endswith('.epub'):
epub_files.append(os.path.join(root, file))
return epub_files
def process_all(self):
"""批量处理所有EPUB文件"""
epub_files = self.find_epub_files()
if not epub_files:
print("❌ 未找到EPUB文件")
return
print(f"🔍 找到 {len(epub_files)} 个EPUB文件")
for epub_file in epub_files:
print(f"\n{'='*60}")
print(f"🔄 处理: {os.path.basename(epub_file)}")
try:
fixer = EpubSlashFixer(epub_file)
if fixer.run():
self.processed_count += 1
print(f"✅ 完成: {os.path.basename(epub_file)}")
else:
self.failed_files.append(epub_file)
print(f"❌ 失败: {os.path.basename(epub_file)}")
except Exception as e:
error_msg = f"处理失败 {epub_file}: {e}"
print(f"❌ {error_msg}")
self.failed_files.append((epub_file, error_msg))
# 输出统计
print(f"\n{'='*60}")
print("📊 批量处理完成!")
print(f"✅ 成功处理: {self.processed_count}")
print(f"❌ 失败: {len(self.failed_files)}")
if self.failed_files:
print("\n失败文件:")
for item in self.failed_files:
if isinstance(item, tuple):
print(f" - {os.path.basename(item[0])}: {item[1]}")
else:
print(f" - {os.path.basename(item)}")
def main():
"""主函数"""
print("📚 EPUB全角斜杠修复工具")
print("=" * 60)
print("功能: 将EPUB中的 ú» 统一修复为正确的全角斜杠 /")
print("=" * 60)
print("请选择操作模式:")
print("1. 修复单个EPUB文件")
print("2. 批量修复目录中的所有EPUB文件")
print("3. 退出")
while True:
choice = input("\n请输入选择 (1-3): ").strip()
if choice == '1':
epub_path = input("请输入EPUB文件路径: ").strip()
if not os.path.exists(epub_path):
print("❌ 文件不存在")
continue
if not epub_path.lower().endswith('.epub'):
print("❌ 文件不是EPUB格式")
continue
output_path = input("请输入输出文件路径(直接回车使用默认): ").strip()
if not output_path:
output_path = None
fixer = EpubSlashFixer(epub_path)
success = fixer.run(output_path)
if success:
print("🎉 修复完成!")
else:
print("❌ 修复失败")
elif choice == '2':
directory = input("请输入包含EPUB文件的目录路径: ").strip()
if not os.path.exists(directory):
print("❌ 目录不存在")
continue
# 确认操作
confirm = input("确定要批量处理所有EPUB文件吗? (y/n): ").strip().lower()
if confirm != 'y':
print("操作已取消")
continue
batch_fixer = BatchEpubFixer(directory)
batch_fixer.process_all()
elif choice == '3':
print("👋 再见!")
break
else:
print("❌ 无效选择,请重新输入")
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("\n👋 用户中断操作")
except Exception as e:
print(f"❌ 程序执行出错: {e}") -
改html中的调用地址
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341import os
import zipfile
import tempfile
import shutil
import re
from bs4 import BeautifulSoup
import xml.etree.ElementTree as ET
class EpubReferenceFixer:
"""EPUB引用修复工具 - 只修复HTML中的图片引用(/ → ú»)"""
def __init__(self, epub_path):
self.epub_path = os.path.abspath(epub_path)
self.temp_dir = None
self.fixed_references = 0
self.processed_files = []
def extract_epub(self):
"""解压EPUB文件到临时目录"""
self.temp_dir = tempfile.mkdtemp(prefix="epub_ref_fix_")
print(f"📦 解压EPUB到临时目录: {self.temp_dir}")
try:
with zipfile.ZipFile(self.epub_path, 'r') as zf:
zf.extractall(self.temp_dir)
print("✅ EPUb解压完成")
return True
except Exception as e:
print(f"❌ EPUb解压失败: {e}")
return False
def find_html_files(self):
"""查找所有HTML文件"""
html_files = []
for root, dirs, files in os.walk(self.temp_dir):
for file in files:
if file.lower().endswith(('.html', '.htm', '.xhtml')):
html_files.append(os.path.join(root, file))
return html_files
def fix_html_references(self):
"""修复HTML文件中的图片引用(/ → ú»)"""
print("🔧 开始修复HTML文件引用...")
html_files = self.find_html_files()
for html_file in html_files:
try:
# 读取HTML文件
with open(html_file, 'r', encoding='utf-8') as f:
content = f.read()
# 使用BeautifulSoup解析
soup = BeautifulSoup(content, 'html.parser')
updated = False
# 修复所有img标签的src属性
for img in soup.find_all('img'):
src = img.get('src', '')
if src and '/' in src:
new_src = src.replace('/', 'ú»')
img['src'] = new_src
print(f"🖼️ 修复图片引用: {src} → {new_src}")
updated = True
self.fixed_references += 1
# 修复其他可能包含图片引用的标签
for tag in soup.find_all(['a', 'link']):
href = tag.get('href', '')
if href and '/' in href and any(href.lower().endswith(ext) for ext in ['.jpg', '.jpeg', '.png', '.gif', '.webp']):
new_href = href.replace('/', 'ú»')
tag['href'] = new_href
print(f"🔗 修复链接引用: {href} → {new_href}")
updated = True
self.fixed_references += 1
# 修复CSS背景图片
for tag in soup.find_all(style=True):
style = tag['style']
if '/' in style:
new_style = style.replace('/', 'ú»')
tag['style'] = new_style
updated = True
self.fixed_references += 1
if updated:
# 保存更新后的内容
with open(html_file, 'w', encoding='utf-8') as f:
f.write(str(soup))
self.processed_files.append(os.path.basename(html_file))
print(f"✅ 更新HTML文件: {os.path.basename(html_file)}")
except Exception as e:
print(f"⚠️ 处理HTML文件失败 {html_file}: {e}")
def fix_css_references(self):
"""修复CSS文件中的图片引用"""
print("🔧 检查CSS文件引用...")
for root, dirs, files in os.walk(self.temp_dir):
for file in files:
if file.lower().endswith('.css'):
css_file = os.path.join(root, file)
try:
with open(css_file, 'r', encoding='utf-8') as f:
content = f.read()
if '/' in content:
new_content = content.replace('/', 'ú»')
with open(css_file, 'w', encoding='utf-8') as f:
f.write(new_content)
print(f"🎨 修复CSS文件: {file}")
self.fixed_references += content.count('/')
except Exception as e:
print(f"⚠️ 跳过CSS文件 {css_file}: {e}")
def repack_epub(self, output_path):
"""重新打包EPUB文件"""
print(f"📦 重新打包EPUB: {output_path}")
try:
# 确保输出目录存在
os.makedirs(os.path.dirname(output_path), exist_ok=True)
with zipfile.ZipFile(output_path, 'w', zipfile.ZIP_DEFLATED) as epub:
# 首先添加mimetype(必须无压缩)
mimetype_path = os.path.join(self.temp_dir, 'mimetype')
if os.path.exists(mimetype_path):
epub.write(mimetype_path, 'mimetype', zipfile.ZIP_STORED)
# 添加其他所有文件(保持原样)
for root, dirs, files in os.walk(self.temp_dir):
for file in files:
if file != 'mimetype':
file_path = os.path.join(root, file)
arcname = os.path.relpath(file_path, self.temp_dir)
epub.write(file_path, arcname)
print("✅ EPUb重新打包完成")
return True
except Exception as e:
print(f"❌ EPUb打包失败: {e}")
return False
def cleanup(self):
"""清理临时文件"""
if self.temp_dir and os.path.exists(self.temp_dir):
shutil.rmtree(self.temp_dir)
print("🧹 清理临时文件")
def run(self, output_path=None):
"""运行完整的修复流程"""
if not os.path.exists(self.epub_path):
print(f"❌ 文件不存在: {self.epub_path}")
return False
if not output_path:
# 默认输出路径:原文件名_fixed.epub
base_dir = os.path.dirname(self.epub_path)
base_name = os.path.splitext(os.path.basename(self.epub_path))[0]
output_path = os.path.join(base_dir, f"{base_name}_fixed.epub")
print(f"🔄 开始修复EPUB引用: {self.epub_path}")
print("=" * 60)
print("修复策略: 只修改HTML/CSS中的引用(/ → ú»),保持文件名不变")
print("=" * 60)
# 解压EPUB
if not self.extract_epub():
return False
try:
# 执行修复步骤
self.fix_html_references() # 修复HTML引用
self.fix_css_references() # 修复CSS引用
# 重新打包
success = self.repack_epub(output_path)
if success:
print("\n🎯 修复完成!")
print("=" * 40)
print(f"📊 修复统计:")
print(f" 修复引用数量: {self.fixed_references}")
print(f" 处理的HTML文件: {len(self.processed_files)}")
if self.processed_files:
print(f" 文件列表: {', '.join(self.processed_files)}")
print(f" 输出文件: {output_path}")
print("\n💡 提示: 文件名保持原样,只修改了引用路径")
return success
except Exception as e:
print(f"❌ 修复过程中出错: {e}")
return False
finally:
self.cleanup()
class BatchEpubReferenceFixer:
"""批量EPUB引用修复工具"""
def __init__(self, directory):
self.directory = os.path.abspath(directory)
self.processed_count = 0
self.failed_files = []
self.total_fixed = 0
def find_epub_files(self):
"""查找目录中的所有EPUB文件"""
epub_files = []
for root, dirs, files in os.walk(self.directory):
for file in files:
if file.lower().endswith('.epub'):
epub_files.append(os.path.join(root, file))
return epub_files
def process_all(self):
"""批量处理所有EPUB文件"""
epub_files = self.find_epub_files()
if not epub_files:
print("❌ 未找到EPUB文件")
return
print(f"🔍 找到 {len(epub_files)} 个EPUB文件")
for epub_file in epub_files:
print(f"\n{'='*60}")
print(f"🔄 处理: {os.path.basename(epub_file)}")
try:
fixer = EpubReferenceFixer(epub_file)
if fixer.run():
self.processed_count += 1
self.total_fixed += fixer.fixed_references
print(f"✅ 完成: {os.path.basename(epub_file)} (修复 {fixer.fixed_references} 处引用)")
else:
self.failed_files.append(epub_file)
print(f"❌ 失败: {os.path.basename(epub_file)}")
except Exception as e:
error_msg = f"处理失败 {epub_file}: {e}"
print(f"❌ {error_msg}")
self.failed_files.append((epub_file, error_msg))
# 输出统计
print(f"\n{'='*60}")
print("📊 批量处理完成!")
print(f"✅ 成功处理: {self.processed_count} 个文件")
print(f"🔧 总共修复: {self.total_fixed} 处引用")
print(f"❌ 失败: {len(self.failed_files)} 个文件")
if self.failed_files:
print("\n失败文件:")
for item in self.failed_files:
if isinstance(item, tuple):
print(f" - {os.path.basename(item[0])}: {item[1]}")
else:
print(f" - {os.path.basename(item)}")
def quick_fix_single(epub_path, output_path=None):
"""快速修复单个EPUB文件"""
fixer = EpubReferenceFixer(epub_path)
return fixer.run(output_path)
def main():
"""主函数"""
print("📚 EPUB引用修复工具")
print("=" * 60)
print("功能: 只修复HTML/CSS中的图片引用(/ → ú»),保持文件名不变")
print("适用: EPUB标准不支持全角斜杠,只能使用URL编码")
print("=" * 60)
print("请选择操作模式:")
print("1. 修复单个EPUB文件")
print("2. 批量修复目录中的所有EPUB文件")
print("3. 退出")
while True:
choice = input("\n请输入选择 (1-3): ").strip()
if choice == '1':
epub_path = input("请输入EPUB文件路径: ").strip()
if not os.path.exists(epub_path):
print("❌ 文件不存在")
continue
if not epub_path.lower().endswith('.epub'):
print("❌ 文件不是EPUB格式")
continue
output_path = input("请输入输出文件路径(直接回车使用默认): ").strip()
if not output_path:
output_path = None
success = quick_fix_single(epub_path, output_path)
if success:
print("🎉 修复完成!")
else:
print("❌ 修复失败")
elif choice == '2':
directory = input("请输入包含EPUB文件的目录路径: ").strip()
if not os.path.exists(directory):
print("❌ 目录不存在")
continue
# 确认操作
confirm = input("确定要批量处理所有EPUB文件吗? (y/n): ").strip().lower()
if confirm != 'y':
print("操作已取消")
continue
batch_fixer = BatchEpubReferenceFixer(directory)
batch_fixer.process_all()
elif choice == '3':
print("👋 再见!")
break
else:
print("❌ 无效选择,请重新输入")
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("\n👋 用户中断操作")
except Exception as e:
print(f"❌ 程序执行出错: {e}")
**注意:**以上两种方法,只选其一即可,两个都用就又回到原点了——地址仍不一致!
上面是对原epub文件不做更改的方法。因为原epub文件已经做好了图片与html文章的对应,不能贸然更改图片名称。这种方法对原epub的各种内容和顺序几乎没有更改。下面还有一种可重新将html文章与图片进行组织对应的小程序,它会对原epub的内容顺序进行重构,重新生成一个epub:
1 | import os |