This commit is contained in:
caiwx86 2023-06-22 22:03:35 +08:00
parent e6eadefe34
commit 7672b7c84b
6 changed files with 86 additions and 43 deletions

View File

@ -52,9 +52,9 @@ class JsonExport(JsonItemExporter):
class ComicInfoXmlItemExporter(XmlItemExporter):
custom_root_element = "ComicInfo"
def __init__(self, comic, chapter):
file_path = os.path.join(COMIC_INFO_XML_STORE, comic,
chapter, f"{self.custom_root_element}.xml")
def __init__(self, dir):
file_path = os.path.join(COMIC_INFO_XML_STORE, dir,
f"{self.custom_root_element}.xml")
dir_path = os.path.dirname(file_path)
if not os.path.exists(dir_path): os.makedirs(dir_path)
self.xml_file = open(file_path, "wb")

View File

@ -6,7 +6,11 @@ import os,Comics.settings as settings,logging
from scrapy.item import Item, Field
from Comics.utils.Constant import ComicPath
from Comics.utils.FileUtils import imageUtils
from scrapy.loader.processors import TakeFirst, MapCompose, Join
from itemloaders.processors import TakeFirst, MapCompose, Join
from scrapy.spiders import Spider
def current_project():
return Spider.name
def serialize_to_chinese(value):
return ComicPath.chinese_convert(value)
@ -35,7 +39,7 @@ def _serialize_to_images(value, result_type=None):
images_item.append(image_src)
image_urls.append(image_src)
count += 1
logging.info(f"images_len: {len(images_item)}")
logging.debug(f"images_len: {len(images_item)}")
if result_type == "image_urls": return image_urls
else: return images_item
@ -51,6 +55,8 @@ class ListComicItem(Item):
class ComicItem(Item):
# 工程
current_project = Field()
# 编号
index = Field(output_processor=TakeFirst())
# 漫画名
@ -113,7 +119,8 @@ def _serializer_info_imagesa(value, result_type=None):
def _serialize_info_images(value, result_type=None):
images = []
for image in value:
images.append(ComicPath().getFileScrambleImageSave(image,True,False))
if os.sep not in image:
images.append(ComicPath().getFileScrambleImageSave(image,True,False))
if result_type == "count":
return len(images)
else:

View File

@ -5,8 +5,9 @@
# useful for handling different item types with a single interface
import os, scrapy,logging,time,random
import os, scrapy,logging,time,random,shutil
from Comics import settings
from Comics.settings import CBZ_EXPORT_PATH,OUTPUT_DIR,PROJECT_KEY
from Comics.utils.Constant import ComicPath
from Comics.items import ComicItem
from scrapy.pipelines.images import ImagesPipeline
@ -19,43 +20,81 @@ class ComicsPipeline:
# item就是yield后面的对象
def process_item(self, item, spider):
if isinstance(item, ComicItem):
file = os.path.join(settings.OUTPUT_DIR,"json", item['name'], item['chapter'])
file = os.path.join(OUTPUT_DIR, spider.name, "json", item['name'], item['chapter'])
item['count'] = len(item['images'])
item['images'].append({'src':'icon.jpg', 'scramble': False})
item['image_urls'].append({'src': item['icon'] , 'scramble': False})
data = JsonExport(file=file).export_json(item, if_return=True)
#item['images'] = data['images']
data[PROJECT_KEY] = spider.name
return data
# image解析
def close_spider(self,spider):
pass
class ImgDownloadPipeline(ImagesPipeline):
def file_exits(self, image_path):
en_image_path = ComicPath().getFileScrambleImageSave(image_path, relative="fullpath")
return os.path.exists(os.path.join(settings.IMAGES_STORE, en_image_path))
def get_file_path(self, item, file=None, result_type="image"):
if result_type == "image":
if os.path.sep not in file:
file = os.path.join(item[settings.PROJECT_KEY], "images", item['name'], item['chapter'], file)
elif result_type == "comic_info":
file = os.path.join(item[settings.PROJECT_KEY], "images", item['name'], item['chapter'])
elif result_type == "cbz_icon":
file = os.path.join("CBZ", item[settings.PROJECT_KEY], item['name'], item['chapter']+".jpg")
elif result_type == "down_icon":
file = self.download_icon(item,result_type='fullpath')
elif result_type == "icon":
file = os.path.join(item[settings.PROJECT_KEY], "icons", item['name'], item['chapter']+".jpg")
elif result_type == "cbz":
file = os.path.join("CBZ", item[settings.PROJECT_KEY], item['name'], item['chapter']+".CBZ")
elif result_type == "images_dir":
file = os.path.join(settings.IMAGES_STORE, item[settings.PROJECT_KEY], "images", item['name'], item['chapter'])
return file
def file_full_path(self, item, image): return os.path.join(item['name'], item['chapter'], image)
def image_scramble_exits(self, item,image_path):
en_image_path = ComicPath().getFileScrambleImageSave(image_path, relative="fullpath")
return os.path.exists(os.path.join(settings.IMAGES_STORE, self.get_file_path(item, en_image_path)))
## Icon Path : CBZ/NAME/CHAPTER.jpg
def download_icon(self, item, result_type="download"):
icon_path = self.get_file_path(item, result_type="icon")
if result_type == "fullpath":
return os.path.join(settings.IMAGES_STORE, icon_path)
if os.path.exists(icon_path):
return False
else:
self.image_urls.append(item['icon'])
self.images.append(icon_path)
return True
def file_path(self, request, response=None, info=None, *, item=None): return request.meta['path']
def get_media_requests(self, item, info):
for image_url,image_path in zip(item['image_urls'],item['images']):
image_path = self.file_full_path(item, image_path)
if self.file_exits(image_path):
logging.info(f"file exists: {image_path}")
self.image_urls = item['image_urls']
self.images = item['images']
# 下载封面
self.download_icon(item)
for image_url,image in zip(self.image_urls,self.images):
image_path = self.get_file_path(item, image)
if self.image_scramble_exits(item, image_path):
logging.info(f"file exists: IMAGE_STORE {image_path}")
else:
logging.info(f"downloading {image_url} --> {image_path}")
logging.info(f"downloading {image_url} --> IMAGE_STORE {image_path}")
yield scrapy.Request(url=image_url, meta={'path': image_path})
def pack_icon(self, item):
cbz_icon = self.get_file_path(item=item, result_type="cbz_icon")
dwn_icon = self.get_file_path(item=item, result_type="down_icon")
logging.info(f"icon packing {dwn_icon} => {cbz_icon}")
cbz_icon_dir = os.path.dirname(cbz_icon)
if not os.path.exists(cbz_icon_dir): os.makedirs(cbz_icon_dir)
shutil.copyfile(dwn_icon, cbz_icon)
def item_completed(self, results, item, info):
item['images_name'] = results
# return item
# ComicInfoXml 生成
comic_info = ComicInfoXmlItemExporter(comic=item['name'], chapter=item['chapter']).export_xml(item)
comic_info = ComicInfoXmlItemExporter(dir=self.get_file_path(item=item, result_type="comic_info")).export_xml(item)
# 打包
CBZUtils.packComicChapterCBZ(comic=item['name'], chapter=item['chapter'],
comic_info_images= comic_info["Pages"], remove=False)
if CBZUtils.packComicChapterCBZ(src_dir= self.get_file_path(item, result_type="images_dir"),
dts_path= self.get_file_path(item, result_type="cbz"),
comic_info_images= comic_info['Pages'], remove=False):
self.pack_icon(item)
time.sleep(random.randint(5,10))

View File

@ -9,11 +9,11 @@
from fake_useragent import UserAgent
import os
PROJECT_KEY = "current_project"
BOT_NAME = 'Comics'
SPIDER_MODULES = ['Comics.spiders']
NEWSPIDER_MODULE = 'Comics.spiders'
OUTPUT_DIR = "output"
# Crawl responsibly by identifying yourself (and your website) on the user-agent
#USER_AGENT = 'Comics (+http://www.yourdomain.com)'
@ -28,7 +28,7 @@ CONCURRENT_REQUESTS = 16
# Configure a delay for requests for the same website (default: 0)
# See https://docs.scrapy.org/en/latest/topics/settings.html#download-delay
# See also autothrottle settings and docs
IMAGES_STORE = os.path.join(OUTPUT_DIR, 'images')
IMAGES_STORE = "output"
IMAGES_NAME_FORMAT = "{:0>3d}"
COMIC_INFO_XML_STORE = IMAGES_STORE
DOWNLOAD_DELAY = 0
@ -36,7 +36,7 @@ DOWNLOAD_DELAY = 0
RETRY_ENABLED = True
RETRY_TIMES = 10 # 想重试几次就写几
# 下面这行可要可不要
RETRY_HTTP_CODES = [500, 502, 503, 504, 408, 401]
# RETRY_HTTP_CODES = [500, 502, 503, 504, 408, 401]
# The download delay setting will honor only one of:
CONCURRENT_REQUESTS_PER_DOMAIN = 16
CONCURRENT_REQUESTS_PER_IP = 16
@ -105,7 +105,6 @@ AUTOTHROTTLE_DEBUG = False
HTTPCACHE_ENABLED = True
HTTPCACHE_EXPIRATION_SECS = 0
HTTPCACHE_DIR = 'httpcache'
HTTPCACHE_IGNORE_HTTP_CODES = [500, 502, 404]
HTTPCACHE_ALLOW_PREFIXS = [ 'jpg', 'png', 'gif']
HTTPCACHE_STORAGE = 'Comics.middlewares.MyFilesystemCacheStorage'

View File

@ -19,7 +19,6 @@ class RmComicSpider(scrapy.Spider):
books = books_comic.get_exec(data, str_exec=str_exec)
for book in books:
books_comic.add_value('link', book['id'])
logging.info(f"downloading books %s" % book['name'])
time.sleep(3)
yield scrapy.Request(url=self.start_urls+"/"+book['id'], callback=self.parse_comic)

View File

@ -275,30 +275,27 @@ class CBZUtils:
y = 0
for filename in filenames:
y = y + 1
logging.info(f"打包中:" + str(y) + "/" + str(len(filenames)), os.path.join(source_dir, filename))
print("打包中:" + str(y) + "/" + str(len(filenames)), os.path.join(source_dir, filename))
zf.write(path.joinpath(filename), arc_dir.joinpath(filename))
zf.close()
logging.info(f"打包完成:{target_file}")
@classmethod
def packComicChapterCBZ(cls, comic, chapter, comic_info_images, remove=True):
images_chapter_path = os.path.join(IMAGES_STORE, comic, chapter)
cbz_chapter_path = os.path.join(CBZ_EXPORT_PATH, comic, chapter) + ".CBZ"
if os.path.exists(images_chapter_path):
dirs = os.listdir(images_chapter_path)
def packComicChapterCBZ(cls, src_dir, dts_path, comic_info_images, remove=True):
if os.path.exists(src_dir):
dirs = os.listdir(src_dir)
for file in dirs:
if file.startswith(ComicPath.PREFIX_SCRAMBLE):
try:
imageUtils.deScrambleImagesByPath(os.path.join(images_chapter_path,file))
imageUtils.deScrambleImagesByPath(os.path.join(src_dir,file))
except Exception as e:
print(f"删除 {file} 发生错误 {e},已跳过")
return False
cls.zip_compression(images_chapter_path, cbz_chapter_path)
cls.zip_compression(src_dir, dts_path)
time.sleep(0.1)
if remove: shutil.rmtree(images_chapter_path)
if remove: shutil.rmtree(src_dir)
# validation
cls.cbz_validate(cbz_chapter_path, comic_info_images)
return True
return cls.cbz_validate(dts_path, comic_info_images)
@classmethod
def replaceZip(cls, filepath, unpack_dir=None):
@ -356,6 +353,8 @@ class CBZUtils:
def cbz_validate(cls, zip_path, comic_info_images):
if len(cls.zip_info(zip_path)) == len(comic_info_images):
logging.info(f"validating successfully === {zip_path}")
return True
else:
os.remove(zip_path)
logging.error(f"validating fail === {zip_path}")
return False