用python爬取《龙珠·超次元乱战》漫画并转化成pdf阅读
需求描述
为了回忆童年,龙珠的漫画、动漫、剧场版已经基本看完了。突然又发现了有个叫《龙珠·超次元乱战》的同人漫画,看评价还不错,于是去官网上去阅读,谁知这是一个国外运营的网站,是供全球读者观看的,这个小水管的服务器自然看起来也就特别慢了,刷新图片都要几秒才能出来。因此产生了想要下载之后观看的想法,秉着懒人不做批量化事情的思想,决定采用程序进行抓取和下载。
问题分析
源码获取
直接使用requests
库进行下载源码即可:
r = requests.get(self.CHAPTER_LIST_URL)
html = r.text
print(u'网页源码获取成功...')
源码查看
<div class="cadrelect chapters " ch='7'><a href='chapters.html?chapter=7'><img src='/cn/pages/small/0144.jpg' alt='[Chapter Cover]' /></a><h4>Chapter 7: 休息一下吃个午饭吧</h4><p><a href='page-144.html' class=''>144</a><a href='page-145.html' class=''>145</a><a href='page-146.html' class=''>146</a><a href='page-147.html' class=''>147</a><a href='page-148.html' class=''>148</a><a href='page-149.html' class=''>149</a><a href='page-150.html' class=''>150</a><a href='page-151.html' class=''>151</a><a href='page-152.html' class=''>152</a><a href='page-153.html' class=''>153</a><a href='page-154.html' class=''>154</a><a href='page-155.html' class=''>155</a><a href='page-156.html' class=''>156</a><a href='page-157.html' class=''>157</a><a href='page-158.html' class=''>158</a><a href='page-159.html' class=''>159</a><a href='page-160.html' class=''>160</a><a href='page-161.html' class=''>161</a><a href='page-162.html' class=''>162</a><a href='page-163.html' class=''>163</a><a href='page-164.html' class=''>164</a><a href='page-165.html' class=''>165</a><a href='page-166.html' class=''>166</a><a href='page-167.html' class=''>167</a></p></div>
代码几乎都是这样的形式,通过表达式抓取即可。
# 使用正则提取数据
# 提取大块数据的正则
pattern1 = '<div\sclass="cadrelect\s.+'
# 提取章节信息的正则
pattern2 = "ch='(\d+)'><a\shref=\S+\ssrc='(\S+)'\s\S+\s\S+\s\S+<h4>(.+)</h4>"
# 提取图片的正则
pattern3 = "href='page-(\d+).html"
result1 = re.findall(pattern1, html)
datas = []
for chatper_text in result1:
data = {}
# 解析每一章节
result2 = re.findall(pattern2, chatper_text)
data['id'] = result2[0][0]
data['cover'] = self.get_absolute_url(result2[0][1])
data['name'] = result2[0][2]
# 图片
result3 = re.findall(pattern3, chatper_text)
# data['images'] = [self.make_image_url(i) for i in result3]
data['image_indexs'] = result3
datas.append(data)
self.datas = datas
经过这样处理之后,得到的数据的格式如下:
[
{
id: 章节序号,
name: 章节名称,
cover: 封面图片的地址,
images: [
每一个图片的地址
]
}
]
图片下载
def download(self):
r"""
下载所有图片。
在存放数据的文件中,建立以章节名称建立文件夹,并把所有图片下载到对应的文件夹中。
:return: 无
"""
for data in self.get_chapters():
# 建立文件夹
dir_path = os.path.join(self.get_dir_path(), data['name'])
if not os.path.exists(dir_path):
os.makedirs(dir_path)
# 下载文件
for i in data['image_indexs']:
image = self.make_image_url(i, self.suffix)
if self.image_downloaded_by_index(data['name'], i):
print(u'%s已经下载' % i)
else:
# 没有下载
image = self.make_image_url(i, self.suffix)
try:
basename = os.path.basename(image)
filepath = os.path.join(dir_path, basename)
urlretrieve(image, filepath)
print(basename + u'下载成功')
except:
self.change_suffix()
image = self.make_image_url(i, self.suffix)
basename = os.path.basename(image)
filepath = os.path.join(dir_path, basename)
# 最后一次尝试
try:
urlretrieve(image, filepath)
print(basename + u'下载成功')
except:
# 尝试使用php的方式下载
try:
self.download_from_php(data['name'], i)
except:
self.download_fail(i)
time.sleep(1)
# 处理完以章
print(u'《%s》下载成功' % data['name'])
pdf生成
首先安装reportlab
库:
pip install reportlab
然后再github
上下载这个库:
https://github.com/wizard1989/Unite-multiple-pictures-into-pdf
接着使用自己写的PdfHandler
来执行:
r"""
将下载的图片打包成pdf
"""
import os
from unite_pictures_into_pdf import unite_pictures_into_pdf
from Fetcher import Fetcher
class PdfHandler(object):
r"""
打包器
"""
# 保存pdf的文件夹
output_name = 'pdfs'
# 根路径
BASE_DIR = os.path.dirname(__file__)
def convert_chapter(self, chapter_name):
r"""
转化一章
:param chapter_name: 章节名称
:return: 无
"""
print(u"正在处理《%s》" % chapter_name)
outputPdfName = chapter_name
pathToSavePdfTo = os.path.join(self.BASE_DIR, self.output_name)
if not os.path.exists(pathToSavePdfTo):
os.makedirs(pathToSavePdfTo)
pathToPictures = os.path.join(self.BASE_DIR, Fetcher.dir_name, chapter_name)
print(pathToPictures)
splitType = "none"
numberOfEntitiesInOnePdf = 1
listWithImagesExtensions = ["png", "jpg"]
picturesAreInRootFolder = True
nameOfPart = "volume"
unite_pictures_into_pdf(outputPdfName, pathToSavePdfTo, pathToPictures, splitType, numberOfEntitiesInOnePdf,
listWithImagesExtensions, picturesAreInRootFolder, nameOfPart)
def convert_chapters(self):
r"""
转化所有章节
:return:
"""
dir_path = os.path.join(self.BASE_DIR, Fetcher.dir_name)
dirnames =os.listdir(dir_path)
dirnames = [d for d in dirnames if d != ".DS_Store"]
for dirname in dirnames:
self.convert_chapter(dirname)
if __name__ == '__main__':
PdfHandler().convert_chapters()
注意事项
会遇到图片截断的问题,需要修改一下reportlab
:
修改reportlab/lib/utils.py
,第530
行改成下面的东西:
try:
from PIL import Image
from PIL import ImageFile
ImageFile.LOAD_TRUNCATED_IMAGES = True
except ImportError:
try:
import Image
except ImportError:
Image = None
运行
首先运行Fetcher().download()
,然后运行PdfHandler().convert_chapters()
即可。
结果
所有pdf会上传到csdn上。地址如下:
csdn不让上传大于220MB的文件。。。。
如果有志同道合的人的话,可以在评论区反映。