背景
网页上的培训材料,内容全是PPT页面图片。直接通过浏览器打印,会存在只打印第一页,并且把浏览器上无效信息也打印出来情况。但目标是希望将页面图片全部打印为pdf形式。
实现方案
- 利用网页“另存为”,将页面内所有图片资源下载到本地;
- 利用页面html源码,解析出图片下载名与标准名之间对应关系;
- 格式化标准名,按文件名顺序排序;
- 按文件名顺序合并所有图片到一个pdf文件中。
技术点
- 利用BS4解析html文档
- 利用PIL的Image合并图片到pdf
操作步骤
-
打开页面并选择“另存为”。
-
保存到F:\course目录下
-
将所有图片文件复制到tmp目录
通过分析页面图片,所有有效图片都是后缀为JPG格式的图片。
-
运行read_html.py文件,标准化tmp目录下图片文件名
1、使用img标签下的alt文件名替换tmp目录下文件名。(本处实现,发现下载图片文件名为src下文件名,但alt属性中文件名更便于理解和排序)
2、将文件名中编号规整,保持3位数字。(本处实现,最大的序号为366;名称为“幻灯片2.JPG”的会显示在“幻灯片11.JPG”的后面,需要将“幻灯片2.JPG’和”幻灯片11.JPG“规整为"幻灯片002.JPG"和”幻灯片011.JPG“)
-
运行merge_img2pdf.py文件,将tmp目录下所有图片合并成一个pdf文件
源代码及注释
# content of read_html.py
# 解析本地html文件,并将图片文件标准化命名
import re
import os
from bs4 import BeautifulSoup
def main():
img_dict = {}
soup = BeautifulSoup(open('个人中心-云阅读_希赛网.html')) # 读取另存为生成的html文件
imgs = soup.find_all('img') # 获取所有img标签
for img in imgs:
if len(img['alt']) == 0: # 过滤掉img标签中alt属性内容为空的字段
continue
real_name = img['alt']
if len(real_name) == 9: # 标准化img文件名,全部变为"幻灯片XXX.JPG"形式
real_name = real_name[0:3]+'0'+real_name[3:]
elif len(real_name) == 8:
real_name = real_name[0:3]+'00'+real_name[3:]
img_dict[os.path.basename(img['src'])] = real_name # 构造字典,key为下载到本地的文件名,value为易读的待修改后的文件名
print(img_dict)
os.chdir('tmp') # 切换到tmp目录下
for old_file_name, new_file_name in img_dict.items():
if os.path.exists(old_file_name): # 若实际文件存在才进行更名
try: # 增加异常捕获,alt属性名称存在同名情况,有发生异常风险。
os.rename(old_file_name,new_file_name) # 重命令文件
except:
pass
if __name__ == "__main__":
main()
# content of merge_img2pdf.py
# 遍历tmp下所有jpg文件,并在运行目录下生成pdf文件
from io import BytesIO
from PIL import Image
import os
def get_file_list():
file_list = []
for file in os.listdir(): # 遍历目录下所有JPG或jpg文件,并保存到file_list列表中,列表中图片顺序根据文件名称排序。
if file.endswith('JPG') or file.endswith('jpg'):
file_list.append(file)
return file_list
def convert_to_pdf(file_list:list):
sources = []
output = Image.open(file_list[0]) # Image中加入第一张图片
print(file_list)
file_list.pop(0) # 从列表中去除第一张图片
for file in file_list:
file = Image.open(file) # 逐张打开图片
if file.mode == "RGB":
file = file.convert("RGB")
sources.append(file) # 并添加到sources列表中
os.chdir('..') # 返回程序运行目录
output.save("output.pdf","pdf",save_all=True,append_images=sources) # 保存图片到pdf文件中,创建output时已经设置了第一张图片,append_images列表中按顺序保存了其它图片内容。
def main():
os.chdir('tmp') # 进入tmp目录下
file_list = get_file_list()
convert_to_pdf(file_list)
if __name__ == "__main__":
main()
后续优化
- 目前是通过命令行方式运行,可以考虑通过pyside6做页面。
- 当前只适配了希赛一个网站,根据后续需求增加程序的适配图片格式。