update 20230806
This commit is contained in:
parent
40d484ee4c
commit
aeff24daa4
@ -57,6 +57,8 @@ class ListComicItem(Item):
|
|||||||
class ComicItem(Item):
|
class ComicItem(Item):
|
||||||
# 工程
|
# 工程
|
||||||
current_project = Field()
|
current_project = Field()
|
||||||
|
# link
|
||||||
|
link = Field()
|
||||||
# 编号
|
# 编号
|
||||||
index = Field(output_processor=TakeFirst())
|
index = Field(output_processor=TakeFirst())
|
||||||
# 漫画名
|
# 漫画名
|
||||||
|
|||||||
@ -10,7 +10,7 @@ class ComicLoader(ItemLoader):
|
|||||||
data = data.get(dot)
|
data = data.get(dot)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def add_xpath(self, field_name, xpath, *processors, index=None, exec=None, re=None, **kw):
|
def add_xpath(self, field_name, xpath, *processors, index=None, exec=None, re=None, is_null=None, **kw):
|
||||||
"""
|
"""
|
||||||
Similar to :meth:`ItemLoader.add_value` but receives an XPath instead of a
|
Similar to :meth:`ItemLoader.add_value` but receives an XPath instead of a
|
||||||
value, which is used to extract a list of strings from the
|
value, which is used to extract a list of strings from the
|
||||||
@ -33,11 +33,15 @@ class ComicLoader(ItemLoader):
|
|||||||
if exec is not None:
|
if exec is not None:
|
||||||
values = self.parseExec(values, exec)
|
values = self.parseExec(values, exec)
|
||||||
if index is not None:
|
if index is not None:
|
||||||
|
if len(values) - 1 >= index:
|
||||||
try:
|
try:
|
||||||
values = values[index]
|
values = values[index]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(f"values [{values}] error index [{index}]")
|
logging.error(f"values [{values}] error index [{index}]")
|
||||||
logging.error(e)
|
logging.error(e)
|
||||||
|
else:
|
||||||
|
if is_null is not None: values = is_null
|
||||||
|
else: values=""
|
||||||
self.add_value(field_name, values, *processors, re=re, **kw)
|
self.add_value(field_name, values, *processors, re=re, **kw)
|
||||||
|
|
||||||
def add_exec(self, field_name, value, str_exec=None, *processors, re=None, **kw):
|
def add_exec(self, field_name, value, str_exec=None, *processors, re=None, **kw):
|
||||||
|
|||||||
@ -22,8 +22,13 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
class ProxyMiddleware(object):
|
class ProxyMiddleware(object):
|
||||||
def process_request(self, request, spider):
|
def process_request(self, request, spider):
|
||||||
|
url = request.url
|
||||||
|
logging.debug(f"proxy url=== {url} {str(url).split('.')[-1]}")
|
||||||
|
if str(url).split('.')[-1] not in HTTPCACHE_ALLOW_PREFIXS:
|
||||||
if len(PROXY_LIST) != 0:
|
if len(PROXY_LIST) != 0:
|
||||||
request.meta["proxy"] = random.choice(PROXY_LIST)
|
request.meta["proxy"] = random.choice(PROXY_LIST)
|
||||||
|
else:
|
||||||
|
logging.info(f"skip proxy... {url}")
|
||||||
|
|
||||||
################################################################
|
################################################################
|
||||||
# HTTP/HTTPS文件缓存中间件
|
# HTTP/HTTPS文件缓存中间件
|
||||||
|
|||||||
@ -17,37 +17,23 @@ from Comics.utils.FileUtils import CBZUtils
|
|||||||
class ComicsPipeline:
|
class ComicsPipeline:
|
||||||
def open_spider(self, spider):
|
def open_spider(self, spider):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# item就是yield后面的对象
|
# item就是yield后面的对象
|
||||||
def process_item(self, item, spider):
|
def process_item(self, item, spider):
|
||||||
if isinstance(item, ComicItem):
|
if isinstance(item, ComicItem):
|
||||||
file = os.path.join(OUTPUT_DIR, spider.name, "json", item['name'], item['chapter'])
|
file = os.path.join(OUTPUT_DIR, spider.name, "json", item['name'], item['chapter'])
|
||||||
item['count'] = len(item['images'])
|
item['count'] = len(item['images'])
|
||||||
data = JsonExport(file=file).export_json(item, if_return=True)
|
data = JsonExport(file=file).export_json(item, if_return=True)
|
||||||
data[PROJECT_KEY] = spider.name
|
#data[PROJECT_KEY] = spider.name
|
||||||
return data
|
return data
|
||||||
# image解析
|
# image解析
|
||||||
|
|
||||||
def close_spider(self,spider):
|
def close_spider(self, spider):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class ImgDownloadPipeline(ImagesPipeline):
|
class ImgDownloadPipeline(ImagesPipeline):
|
||||||
def get_file_path(self, item, file=None, result_type="image"):
|
def get_file_path(self, item, file=None, result_type="image"):
|
||||||
if result_type == "image":
|
return ComicPath.get_file_path(item=item, file=file, result_type= result_type)
|
||||||
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_EXPORT_PATH, 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_EXPORT_PATH, 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 image_scramble_exits(self, item,image_path):
|
def image_scramble_exits(self, item,image_path):
|
||||||
en_image_path = ComicPath().getFileScrambleImageSave(image_path, relative="fullpath")
|
en_image_path = ComicPath().getFileScrambleImageSave(image_path, relative="fullpath")
|
||||||
|
|||||||
@ -18,6 +18,7 @@ OUTPUT_DIR = "output"
|
|||||||
# Crawl responsibly by identifying yourself (and your website) on the user-agent
|
# Crawl responsibly by identifying yourself (and your website) on the user-agent
|
||||||
#USER_AGENT = 'Comics (+http://www.yourdomain.com)'
|
#USER_AGENT = 'Comics (+http://www.yourdomain.com)'
|
||||||
USER_AGENT = UserAgent().random
|
USER_AGENT = UserAgent().random
|
||||||
|
# Override the default request headers:
|
||||||
# Obey robots.txt rules
|
# Obey robots.txt rules
|
||||||
ROBOTSTXT_OBEY = False
|
ROBOTSTXT_OBEY = False
|
||||||
|
|
||||||
|
|||||||
@ -1,32 +1,34 @@
|
|||||||
import scrapy,logging,time
|
import scrapy,logging,time,os
|
||||||
from Comics.items import ComicItem
|
from Comics.items import ComicItem
|
||||||
from Comics.loader import ComicLoader
|
from Comics.loader import ComicLoader
|
||||||
from Comics.items import ListComicItem
|
from Comics.items import ListComicItem
|
||||||
|
from Comics.utils.Constant import ComicPath
|
||||||
|
from Comics.settings import PROJECT_KEY
|
||||||
|
|
||||||
class RmComicSpider(scrapy.Spider):
|
class RmComicSpider(scrapy.Spider):
|
||||||
name = 'rm_comic'
|
name = 'rm_comic'
|
||||||
allowed_domains = ['rm01.xyz']
|
allowed_domains = ['rouman5.com']
|
||||||
main_url = 'https://rm01.xyz'
|
main_url = 'https://'+allowed_domains[0]
|
||||||
start_urls = 'https://rm01.xyz/books'
|
start_urls = main_url+'/books'
|
||||||
|
|
||||||
def start_requests(self):
|
def start_requests(self):
|
||||||
yield scrapy.Request(self.start_urls, callback=self.books_comic)
|
yield scrapy.Request(self.start_urls, callback=self.books_comic)
|
||||||
|
|
||||||
def books_comic(self, response):
|
def books_comic(self, response):
|
||||||
books_comic = ComicLoader(item=ListComicItem(), response=response)
|
#books_comic = ComicLoader(item=ListComicItem(), response=response)
|
||||||
|
books_comic = ComicLoader(item=ComicItem(), response=response)
|
||||||
data = books_comic.get_xpath('//script[@id="__NEXT_DATA__"]/text()')[0]
|
data = books_comic.get_xpath('//script[@id="__NEXT_DATA__"]/text()')[0]
|
||||||
str_exec = "props.pageProps.books"
|
str_exec = "props.pageProps.books"
|
||||||
books = books_comic.get_exec(data, str_exec=str_exec)
|
books = books_comic.get_exec(data, str_exec=str_exec)
|
||||||
for book in books:
|
for book in books:
|
||||||
books_comic.add_value('link', book['id'])
|
books_comic.add_value('link', self.start_urls+"/"+book['id'])
|
||||||
time.sleep(3)
|
|
||||||
yield scrapy.Request(url=self.start_urls+"/"+book['id'], callback=self.parse_comic)
|
yield scrapy.Request(url=self.start_urls+"/"+book['id'], callback=self.parse_comic)
|
||||||
|
|
||||||
|
|
||||||
# 获取某个漫画的相关数据
|
# 获取某个漫画的相关数据
|
||||||
# 获取到多个章节链接后进入下个流程
|
# 获取到多个章节链接后进入下个流程
|
||||||
def parse_comic(self, response):
|
def parse_comic(self, response):
|
||||||
comic_item = ComicLoader(item=ComicItem(), response=response)
|
comic_item = ComicLoader(item=ComicItem(), response=response)
|
||||||
|
comic_item.add_value(PROJECT_KEY, self.name)
|
||||||
comic_item.add_xpath('name', '//div[@class="col"]/h5/text()')
|
comic_item.add_xpath('name', '//div[@class="col"]/h5/text()')
|
||||||
comic_item.add_xpath('icon', '//img[@class="img-thumbnail"]/@src')
|
comic_item.add_xpath('icon', '//img[@class="img-thumbnail"]/@src')
|
||||||
comic_item.add_xpath('author', '//div[contains(@class,"bookid_bookInfo")]/p[1]/text()', index=1)
|
comic_item.add_xpath('author', '//div[contains(@class,"bookid_bookInfo")]/p[1]/text()', index=1)
|
||||||
@ -39,9 +41,21 @@ class RmComicSpider(scrapy.Spider):
|
|||||||
'//div[contains(@class,"bookid_chapter")]/a/@href')
|
'//div[contains(@class,"bookid_chapter")]/a/@href')
|
||||||
#chapters = response.xpath('//div[contains(@class,"bookid_chapterBox")]'
|
#chapters = response.xpath('//div[contains(@class,"bookid_chapterBox")]'
|
||||||
# '//div[contains(@class,"bookid_chapter")]/a/text()').extract()
|
# '//div[contains(@class,"bookid_chapter")]/a/text()').extract()
|
||||||
|
|
||||||
|
chapters = comic_item.get_xpath('//div[contains(@class,"bookid_chapterBox")]'
|
||||||
|
'//div[contains(@class,"bookid_chapter")]/a/text()')
|
||||||
#for chapter, link in zip(chapters, chapter_href):
|
#for chapter, link in zip(chapters, chapter_href):
|
||||||
for i, link in enumerate(chapter_href, start=1):
|
for i, link in enumerate(chapter_href, start=1):
|
||||||
yield scrapy.Request(self.main_url+link, meta={'item': comic_item.load_item(), 'num': i}, callback=self.parse_chapter)
|
# yield scrapy.Request(self.main_url+link, meta={'item': comic_item.load_item(), 'num': i}, callback=self.parse_chapter)
|
||||||
|
comic_item.add_value('chapter', chapters[i-1])
|
||||||
|
item = comic_item.load_item()
|
||||||
|
cbz_path = ComicPath.get_file_path(item=item, result_type="cbz", convert=True)
|
||||||
|
if os.path.exists(cbz_path):
|
||||||
|
logging.info(f"漫画 {cbz_path} 已存在, 跳过中...")
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
yield scrapy.Request(self.main_url+link, meta={'item': item, 'num': i}, callback=self.parse_chapter)
|
||||||
|
|
||||||
|
|
||||||
# 读取某章节下的所有图片
|
# 读取某章节下的所有图片
|
||||||
def parse_chapter(self, response):
|
def parse_chapter(self, response):
|
||||||
@ -72,3 +86,6 @@ class RmComicSpider(scrapy.Spider):
|
|||||||
|
|
||||||
def parse(self, response):
|
def parse(self, response):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def error_parse(self, response):
|
||||||
|
raise NotImplementedError
|
||||||
@ -1,5 +1,6 @@
|
|||||||
import os.path
|
import os.path
|
||||||
import re
|
import re
|
||||||
|
from Comics import settings
|
||||||
from opencc import OpenCC
|
from opencc import OpenCC
|
||||||
class ComicPath:
|
class ComicPath:
|
||||||
PREFIX_SCRAMBLE = "scramble="
|
PREFIX_SCRAMBLE = "scramble="
|
||||||
@ -46,3 +47,30 @@ class ComicPath:
|
|||||||
filename = filename[0:len(filename)+1-count]
|
filename = filename[0:len(filename)+1-count]
|
||||||
break
|
break
|
||||||
return filename
|
return filename
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_file_path(cls, item, result_type="image", file=None, convert=False):
|
||||||
|
PROJECT = item[settings.PROJECT_KEY][0]
|
||||||
|
if not convert:
|
||||||
|
name = item['name']
|
||||||
|
chapter = item['chapter']
|
||||||
|
else:
|
||||||
|
name = cls.fix_file_name(cls.chinese_convert(item['name']))
|
||||||
|
chapter = cls.fix_file_name(cls.chinese_convert(item['chapter']))
|
||||||
|
|
||||||
|
if result_type == "image":
|
||||||
|
if os.path.sep not in file:
|
||||||
|
file = os.path.join(PROJECT, "images", name, chapter, file)
|
||||||
|
elif result_type == "comic_info":
|
||||||
|
file = os.path.join(PROJECT, "images", name, chapter)
|
||||||
|
elif result_type == "cbz_icon":
|
||||||
|
file = os.path.join(settings.CBZ_EXPORT_PATH, PROJECT, name, chapter+".jpg")
|
||||||
|
elif result_type == "down_icon":
|
||||||
|
file = os.path.join(settings.IMAGES_STORE, cls.get_file_path(item=item, result_type="icon"))
|
||||||
|
elif result_type == "icon":
|
||||||
|
file = os.path.join(PROJECT, "icons", name+".jpg")
|
||||||
|
elif result_type == "cbz":
|
||||||
|
file = os.path.join(settings.CBZ_EXPORT_PATH, PROJECT, name, chapter+".CBZ")
|
||||||
|
elif result_type == "images_dir":
|
||||||
|
file = os.path.join(settings.IMAGES_STORE, PROJECT, "images", name, chapter)
|
||||||
|
return file
|
||||||
Loading…
Reference in New Issue
Block a user