Skip to content

Commit 68ba3b8

Browse files
authored
v2.1.10: 适配JM大陆直连域名的HTML正则,优化保存图片的代码,更新文档 (#89)
1 parent aae008a commit 68ba3b8

11 files changed

+104
-93
lines changed

README.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,18 @@ jmcomic.download_album('422866') # 传入要下载的album的id,即可下载
3838
## 项目特点
3939

4040
- **绕过Cloudflare的反爬虫**
41-
- 支持使用**Github Action**下载漫画,不会编程都能用([教程:使用Github Actions下载禁漫本子](./assets/docs/教程:使用Github%20Actions下载禁漫本子.md)
42-
- 可配置性强
41+
- 支持使用**Github Actions**下载漫画,不会编程都能用([教程:使用Github Actions下载禁漫本子](./assets/docs/教程:使用Github%20Actions下载禁漫本子.md)
42+
- **可配置性强**
4343
- 不配置也能使用,十分方便
4444
- 配置可以从**配置文件**生成,支持多种文件格式,无需写Python代码
45-
- 配置点有:`是否使用磁盘缓存` `图片类型转换` `下载路径` `请求元信息(headers,cookies,代理)`
46-
- 可扩展性强
45+
- 配置点有:`是否使用磁盘缓存` `图片类型转换` `下载路径` `请求元信息(headers,cookies,代理)`
46+
- **可扩展性强**
4747
- 支持自定义本子/章节/图片下载前后的回调函数
4848
- 支持自定义debug日志的开关/格式
4949
- 支持自定义Option/Client/实体类
50+
- ...
5051
- 支持重试和域名切换机制
51-
- 多线程下载(可细化到一图一线程,效率极高)
52+
- **多线程下载**(可细化到一图一线程,效率极高)
5253
- 跟进了JM最新的图片分割算法(2023-02-08)
5354

5455
## 使用小说明

assets/docs/images/5.png

124 KB
Loading

assets/docs/教程:使用Github Actions下载禁漫本子.md

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,38 @@
33
一共需要三步:
44

55
1. fork一份我的代码仓库。
6-
2. 填写你需要下载的本子id,提交commit
6+
2. 填写你需要下载的本子id。
77
3. 等待Github Actions下载完成,下载成品zip文件。
88

99
下面截图解析这三步的详细过程。
1010

1111
## 1. fork一份我的代码仓库
1212

13-
访问这个网址: [https://github.com/hect0x7/JMComic-Crawler-Python/fork].
13+
访问下面这个网址:
14+
15+
`https://github.com/hect0x7/JMComic-Crawler-Python/fork`
1416

1517
直接拉到页面最底部,如下所示:
1618

1719
![1](./images/1.png)
1820

19-
## 2. 填写你需要下载的本子id,提交commit
21+
## 2. 填写你需要下载的本子id
22+
23+
### 2.1. 方式一(最新、推荐)
24+
25+
访问下面这个网址:
26+
27+
`https://github.com/hect0x7/JMComic-Crawler-Python/actions/workflows/download_dispatch.yml`
28+
29+
按下图步骤进行操作:
30+
31+
![5](./images/5.png)
32+
33+
34+
35+
### 2.2. 方式二
2036

21-
访问下面这个网址
37+
访问下面这个网址
2238

2339
`https://github.com/你的用户名/JMComic-Crawler-Python/edit/workflow/usage/workflow_download.py`
2440

src/jmcomic/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22
# 被依赖方 <--- 使用方
33
# config <--- entity <--- toolkit <--- client <--- option <--- downloader
44

5-
__version__ = '2.1.9'
5+
__version__ = '2.1.10'
66

77
from .api import *

src/jmcomic/jm_client_impl.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ def get_jmcomic_domain_all(self, postman=None):
133133
# noinspection PyUnusedLocal
134134
def fallback(self, request, url, domain_index, retry_count, **kwargs):
135135
msg = f"请求重试全部失败: [{url}], {self.domain_list}"
136-
jm_debug('fallback', msg)
136+
jm_debug('req.fallback', msg)
137137
raise AssertionError(msg)
138138

139139

src/jmcomic/jm_client_interface.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,14 @@ def transfer_to(self,
4848
img_url = img_url or self.url
4949

5050
if decode_image is False:
51-
# 不解密图片,直接返回
51+
# 不解密图片,直接保存文件
5252
JmImageSupport.save_resp_img(
5353
self,
5454
path,
5555
need_convert=suffix_not_equal(img_url, path),
5656
)
5757
else:
58-
# 解密图片,需要 photo_id、scramble_id
58+
# 解密图片并保存文件
5959
JmImageSupport.decode_and_save(
6060
JmImageSupport.get_num_by_url(scramble_id, img_url),
6161
JmImageSupport.open_Image(self.content),
@@ -241,6 +241,7 @@ def download_image(self,
241241
def save_image_resp(self, decode_image, img_save_path, img_url, resp, scramble_id):
242242
# gif图无需加解密,需要最先判断
243243
if self.img_is_not_need_to_decode(img_url, resp):
244+
# 相当于调用save_directly,但使用save_resp_img可以统一调用入口
244245
JmImageSupport.save_resp_img(resp, img_save_path, False)
245246
else:
246247
resp.transfer_to(img_save_path, scramble_id, decode_image, img_url)

src/jmcomic/jm_config.py

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,14 @@ class JmModuleConfig:
2424
JM_PUB_URL = f'{PROT}jmcomic2.bet'
2525
JM_CDN_IMAGE_URL_TEMPLATE = PROT + 'cdn-msp.{domain}/media/photos/{photo_id}/{index:05}{suffix}' # index 从1开始
2626
JM_IMAGE_SUFFIX = ['.jpg', '.webp', '.png', '.gif']
27-
# 缓存字段
28-
DOMAIN = None
29-
DOMAIN_LIST = None
3027

31-
# 访问JM可能会遇到的异常网页
28+
# JM的异常网页内容
3229
JM_ERROR_RESPONSE_TEXT = {
3330
"Could not connect to mysql! Please check your database settings!": "禁漫服务器内部报错",
3431
"Restricted Access!": "禁漫拒绝你所在ip地区的访问,你可以选择: 换域名/换代理",
3532
}
3633

34+
# JM的异常网页code
3735
JM_ERROR_STATUS_CODE = {
3836
403: 'ip地区禁止访问/爬虫被识别',
3937
520: '520: Web server is returning an unknown error (禁漫服务器内部报错)',
@@ -48,18 +46,22 @@ class JmModuleConfig:
4846
# API的相关配置
4947
MAGIC_18COMICAPPCONTENT = '18comicAPPContent'
5048

51-
# 下载时的一些默认值
49+
# 下载时的一些默认值配置
5250
default_author = 'default-author'
53-
default_photo_title = 'default-photo-title'
54-
default_photo_id = 'default-photo-id'
5551

56-
# debug
57-
enable_jm_debug = True
58-
debug_executor = default_jm_debug
59-
postman_constructor = default_postman_constructor
52+
# 模块级别的可重写配置
53+
DOMAIN = None
54+
DOMAIN_LIST = None
6055
DOWNLOADER_CLASS = None
6156
OPTION_CLASS = None
6257

58+
# 执行debug的函数
59+
debug_executor = default_jm_debug
60+
# postman构造函数
61+
postman_constructor = default_postman_constructor
62+
# debug开关标记
63+
enable_jm_debug = True
64+
6365
@classmethod
6466
def downloader_class(cls):
6567
if cls.DOWNLOADER_CLASS is not None:

src/jmcomic/jm_option.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ def new_jm_client(self, **kwargs) -> JmcomicClient:
252252
# domain_list
253253
domain_list = self.client.domain
254254
if len(domain_list) == 0:
255-
domain_list = JmModuleConfig.get_jmcomic_domain_all(postman)[:-1]
255+
domain_list = [JmcomicText.parse_to_jm_domain(JmModuleConfig.get_jmcomic_url(postman))]
256256

257257
# client
258258
client = self.jm_client_impl_mapping[self.client.impl](

src/jmcomic/jm_toolkit.py

Lines changed: 22 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class JmcomicText:
1212
pattern_html_photo_title = compile('<title>(.*?)\|.*</title>')
1313
# pattern_html_photo_data_original_list = compile('data-original="(.*?)" id="album_photo_.+?"')
1414
pattern_html_photo_data_original_domain = compile('src="https://(.*?)/media/albums/blank')
15-
pattern_html_photo_data_original_0 = compile('data-original="(.*?)" id="album_photo')
15+
pattern_html_photo_data_original_0 = compile('data-original="(.*?)"[ \n]*?id="album_photo')
1616
pattern_html_photo_keywords = compile('<meta name="keywords"[\s\S]*?content="(.*?)"')
1717
pattern_html_photo_series_id = compile('var series_id = (\d+);')
1818
pattern_html_photo_sort = compile('var sort = (\d+);')
@@ -207,41 +207,33 @@ class JmImageSupport:
207207
@classmethod
208208
def save_resp_img(cls, resp: Any, filepath: str, need_convert=True):
209209
"""
210-
保存图片的响应数据
211-
@param resp: Response对象
212-
@param filepath: 响应数据保存的绝对路径
213-
@param need_convert: True 使用PIL打开图片再保存; False 直接保存resp.content;
214-
如果需要改变图片的格式,比如 .jpg → .png,则需要neet_convert=True。
215-
如果不需要改变文件的格式,使用need_convert=False可以跳过PIL解析图片,效率更高。
210+
接收HTTP响应对象,将其保存到图片文件.
211+
如果需要改变图片的文件格式,比如 .jpg → .png,则需要指定参数 neet_convert=True.
212+
如果不需要改变图片的文件格式,使用 need_convert=False,可以跳过PIL解析图片,效率更高.
213+
214+
@param resp: HTTP响应对象
215+
@param filepath: 图片文件路径
216+
@param need_convert: 是否转换图片
216217
"""
217-
if need_convert is True:
218-
cls.save_image(cls.open_Image(resp.content), filepath)
218+
if need_convert is False:
219+
cls.save_directly(resp, filepath)
219220
else:
220-
save_resp_content(resp, filepath)
221+
cls.save_image(cls.open_Image(resp.content), filepath)
221222

222223
@classmethod
223-
def save_resp_decoded_img(cls,
224-
resp: Any,
225-
image: JmImageDetail,
226-
filepath: str
227-
) -> None:
228-
cls.decode_and_save(
229-
cls.get_num_by_detail(image),
230-
cls.open_Image(resp.content),
231-
filepath
232-
)
224+
def save_image(cls, image: Image, filepath: str):
225+
"""
226+
保存图片
227+
228+
@param image: PIL.Image对象
229+
@param filepath: 保存文件路径
230+
"""
231+
image.save(filepath)
233232

234233
@classmethod
235-
def decode_disk_img(cls,
236-
image: JmImageDetail,
237-
img_filepath: str,
238-
decoded_save_path: str
239-
) -> None:
240-
cls.decode_and_save(
241-
cls.get_num_by_detail(image),
242-
cls.open_Image(img_filepath),
243-
decoded_save_path
244-
)
234+
def save_directly(cls, resp, filepath):
235+
from common import save_resp_content
236+
save_resp_content(resp, filepath)
245237

246238
@classmethod
247239
def decode_and_save(cls,
@@ -292,10 +284,6 @@ def open_Image(cls, fp: Union[str, bytes]):
292284
fp = fp if isinstance(fp, str) else BytesIO(fp)
293285
return Image.open(fp)
294286

295-
@classmethod
296-
def save_image(cls, image: Image, filepath: str):
297-
image.save(filepath)
298-
299287
@classmethod
300288
def get_num(cls, scramble_id, aid, filename: str) -> int:
301289
"""

usage/getting_started.py

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -12,33 +12,6 @@
1212
# 如果没有配置,则会使用 JmOption.default(),下载的路径是[当前工作文件夹/本子章节名称/图片].
1313

1414

15-
"""
16-
--------------------
17-
批量下载介绍
18-
--------------------
19-
"""
20-
# 如果你想要批量下载,可以使用 list/set/tuple/生成器 作为第一个参数。
21-
# 第二个参数依然是可选的JmOption对象
22-
jmcomic.download_album(['422866', '1', '2', '3']) # list
23-
jmcomic.download_album({'422866', '1', '2', '3'}) # set
24-
jmcomic.download_album(('422866', '1', '2', '3')) # tuple
25-
jmcomic.download_album(aid for aid in ('422866', '1', '2', '3')) # 生成器
26-
27-
28-
"""
29-
--------------------
30-
获取域名介绍
31-
--------------------
32-
"""
33-
# 方式1: 访问禁漫发布页
34-
url_ls = jmcomic.JmModuleConfig.get_jmcomic_url_all()
35-
print(url_ls)
36-
37-
# 方式2(可能会报错,需要你自己配置梯子)
38-
url = jmcomic.JmModuleConfig.get_jmcomic_url()
39-
print(url)
40-
41-
4215
"""
4316
--------------------
4417
配置文件介绍
@@ -67,3 +40,30 @@
6740
}
6841
}
6942
})
43+
44+
45+
"""
46+
--------------------
47+
批量下载介绍
48+
--------------------
49+
"""
50+
# 如果你想要批量下载,可以使用 list/set/tuple/生成器 作为第一个参数。
51+
# 第二个参数依然是可选的JmOption对象
52+
jmcomic.download_album(['422866', '1', '2', '3']) # list
53+
jmcomic.download_album({'422866', '1', '2', '3'}) # set
54+
jmcomic.download_album(('422866', '1', '2', '3')) # tuple
55+
jmcomic.download_album(aid for aid in ('422866', '1', '2', '3')) # 生成器
56+
57+
58+
"""
59+
--------------------
60+
获取域名介绍
61+
--------------------
62+
"""
63+
# 方式1: 访问禁漫发布页
64+
url_ls = jmcomic.JmModuleConfig.get_jmcomic_url_all()
65+
print(url_ls)
66+
67+
# 方式2(可能会报错,需要你自己配置梯子)
68+
url = jmcomic.JmModuleConfig.get_jmcomic_url()
69+
print(url)

usage/sample_usage.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
f'你的配置文件路径,例如: D:/a/b/c/jmcomic/config.yml'
55
)
66
client = option.build_jm_client()
7-
client.enable_cache(debug=True)
87

98

109
@timeit('下载本子集: ')
@@ -21,14 +20,17 @@ def download_jm_album():
2120

2221
@timeit('获取实体类: ')
2322
def get_album_photo_detail():
24-
# 启用缓存,会缓存id → album和photo的实体类
23+
# 本子实体类
2524
album: JmAlbumDetail = client.get_album_detail('427413')
2625

27-
def show(photo):
28-
photo: JmPhotoDetail = client.get_photo_detail(photo.photo_id, False)
29-
for img in photo:
30-
img: JmImageDetail
31-
print(img.img_url)
26+
def show(photo: JmPhotoDetail):
27+
# 章节实体类
28+
photo = client.get_photo_detail(photo.photo_id, False)
29+
30+
# 图片实体类
31+
image: JmImageDetail
32+
for image in photo:
33+
print(image.img_url)
3234

3335
multi_thread_launcher(
3436
iter_objs=album,
@@ -69,6 +71,7 @@ def main():
6971
search_jm_album()
7072
download_jm_album()
7173
get_album_photo_detail()
74+
search_and_download()
7275

7376

7477
if __name__ == '__main__':

0 commit comments

Comments
 (0)