3434 'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0'
3535}
3636
37- MAX_WORKERS = 2
38- MAX_TITLE_LIST_NUM = 6
39- SPIDER_BASE_SLEEP_TIME = 200
40- IS_STRIP_TITLE = True
41- IS_STRIP_AUTHOR = True
42- IS_NCLHASH = True
43- IS_PURSETAG = False
44- IS_FUZZY_SEARCH_WITH_AUTHOR = True
45- ADD_CLC_TO_TAGS = True
46- CONVERT_CLC_TO_TAG = True
47- CLC_PARSE_LEVEL = 2
37+ # 配置字典:存储所有可配置项的默认值
38+ CONFIG = {
39+ 'max_workers' : 2 ,
40+ 'max_title_list_num' : 6 ,
41+ 'spider_base_sleep_time' : 200 ,
42+ 'is_strip_title' : True ,
43+ 'is_strip_author' : True ,
44+ 'is_nlchash' : True ,
45+ 'is_pursetag' : False ,
46+ 'is_fuzzy_search_with_author' : True ,
47+ 'add_clc_to_tags' : True ,
48+ 'convert_clc_to_tag' : True ,
49+ 'clc_parse_level' : 2 ,
50+ }
4851
4952def spider_sleep ():
5053 """
@@ -53,7 +56,7 @@ def spider_sleep():
5356 函数通过模拟掷8个120面的骰子并求和,加上一个随机数和基础睡眠时间,来确定睡眠时间,并使当前线程进入睡眠状态。
5457 """
5558 sleep_time = sum (randint (1 , 120 ) for _ in range (8 )) # 掷3个8到120面的骰子并求和
56- sleep_time = sleep_time + randint (30 , 600 ) + SPIDER_BASE_SLEEP_TIME
59+ sleep_time = sleep_time + randint (30 , 600 ) + CONFIG [ 'spider_base_sleep_time' ]
5760 time .sleep (sleep_time / 1000 )
5861
5962
@@ -93,43 +96,53 @@ def get_dynamic_url(log):
9396 else :
9497 raise ValueError ("无法找到动态URL" )
9598
96- def title2metadata (title , log , result_queue , clean_downloaded_metadata , max_workers = MAX_WORKERS , max_title_list_num = MAX_TITLE_LIST_NUM ):
99+ def title2metadata (title , log , result_queue , clean_downloaded_metadata , max_workers = None , max_title_list_num = None ):
100+ if max_workers is None :
101+ max_workers = CONFIG ['max_workers' ]
102+ if max_title_list_num is None :
103+ max_title_list_num = CONFIG ['max_title_list_num' ]
104+
97105 if not isinstance (title , str ):
98106 raise TypeError ("title必须是字符串" )
99-
107+
100108 title = urllib .parse .quote (f"{ title } " )
101109 dynamic_url = get_dynamic_url (log )
102110 if not dynamic_url :
103111 return None
104112
105113 search_url = SEARCH_URL_TEMPLATE_TITLE .format (title = title )
106-
114+
107115 response = urllib .request .urlopen (urllib .request .Request (search_url , headers = HEADERS ), timeout = 10 )
108116
109117 response_text = response .read ().decode ('utf-8' )
110118
111119 titlelist = parse_search_list (response_text , log )
112-
120+
113121 spider_sleep ()
114122
115-
116- if len (titlelist )> MAX_TITLE_LIST_NUM :
117- titlelist = titlelist [:MAX_TITLE_LIST_NUM ]
123+
124+ if len (titlelist )> max_title_list_num :
125+ titlelist = titlelist [:max_title_list_num ]
118126 # 使用线程池处理并发请求
119127 metadatas = []
120- with ThreadPoolExecutor (max_workers = MAX_WORKERS ) as executor :
121- future_to_url = {executor .submit (url2metadata , item [1 ], log , result_queue , clean_downloaded_metadata , max_workers = MAX_WORKERS , max_title_list_num = MAX_TITLE_LIST_NUM ): item for item in titlelist }
128+ with ThreadPoolExecutor (max_workers = max_workers ) as executor :
129+ future_to_url = {executor .submit (url2metadata , item [1 ], log , result_queue , clean_downloaded_metadata , max_workers = max_workers , max_title_list_num = max_title_list_num ): item for item in titlelist }
122130 for future in as_completed (future_to_url ):
123131 data = future .result ()
124132 if data :
125133 metadatas .append (data )
126134 return metadatas
127135
128- def url2metadata (url , log , result_queue , clean_downloaded_metadata , max_workers = MAX_WORKERS , max_title_list_num = MAX_TITLE_LIST_NUM ):
136+ def url2metadata (url , log , result_queue , clean_downloaded_metadata , max_workers = None , max_title_list_num = None ):
137+ if max_workers is None :
138+ max_workers = CONFIG ['max_workers' ]
139+ if max_title_list_num is None :
140+ max_title_list_num = CONFIG ['max_title_list_num' ]
141+
129142 if not isinstance (url , str ):
130143 raise TypeError ("url必须是字符串" )
131144 search_url = url
132-
145+
133146 spider_sleep ()
134147
135148 try :
@@ -333,7 +346,7 @@ def get_parse_metadata(html, isbn, log):
333346
334347 # 优化标题格式
335348 title = data .get ("题名与责任" , f"{ isbn } " )
336- if IS_STRIP_TITLE :
349+ if CONFIG [ 'is_strip_title' ] :
337350 pattern = r"([\u4e00-\u9fa5a-zA-Z0-9]+(?:[\u4e00-\u9fa5a-zA-Z0-9\s]+)?)(?=\s\[[\u4e00-\u9fa5]{2}\])" #
338351 try :
339352 match = re .search (pattern , title )
@@ -342,8 +355,8 @@ def get_parse_metadata(html, isbn, log):
342355 except re .error as e :
343356 log .error (f"正则表达式匹配错误: { e } , title: { title } " )
344357
345- authors = data .get ("著者" , "" ).split (' & ' )
346- if IS_STRIP_AUTHOR :
358+ authors = data .get ("著者" , "" ).split ('\n ' )
359+ if CONFIG [ 'is_strip_author' ] :
347360 author_pattern = re .compile (r'^(.*?)\s+(?:著|编)' )
348361 try :
349362 stripped_authors = []
@@ -376,16 +389,16 @@ def get_parse_metadata(html, isbn, log):
376389 publisher = publisher_match .group (1 ) if publisher_match else ""
377390
378391 tags = data .get ("主题" , "" ).replace ('--' , '&' )
379- if not IS_PURSETAG :
392+ if not CONFIG [ 'is_pursetag' ] :
380393 tags += f' & { publisher } '
381394 if year :
382395 tags += f' & { year } '
383396 # 处理中图分类号相关选项
384397 clc_code = data .get ("中图分类号" , "" )
385- if ADD_CLC_TO_TAGS :
386- if CONVERT_CLC_TO_TAG :
398+ if CONFIG [ 'add_clc_to_tags' ] :
399+ if CONFIG [ 'convert_clc_to_tag' ] :
387400 # 使用 Parser 解析中图分类号
388- parse_level = CLC_PARSE_LEVEL
401+ parse_level = CONFIG [ 'clc_parse_level' ]
389402 parsed_clc = Parser .parse (clc_code )
390403 if parsed_clc :
391404 clc_codes = list (parsed_clc .values ())[0 ]
@@ -425,7 +438,7 @@ def to_metadata(book, add_translator_to_author, log):
425438 ) if add_translator_to_author and book .get ('translators' , None ) else book ['authors' ]
426439 mi = MetaInformation (book ['title' ], authors )
427440
428- if IS_NCLHASH :
441+ if CONFIG [ 'is_nlchash' ] :
429442 mi .identifiers = {PROVIDER_ID : book .get ('isbn' , '' ),
430443 'nlchash' : f"{ hash_utf8_string (book ['title' ]+ book .get ('pubdate' , None ))} "
431444 }
@@ -439,7 +452,9 @@ def to_metadata(book, add_translator_to_author, log):
439452 pubdate = book .get ('pubdate' , None )
440453 if pubdate :
441454 try :
442- if re .compile ('^\\ d{4}-\\ d+$' ).match (pubdate ):
455+ if re .compile ('^\\ d{4}$' ).match (pubdate ):
456+ mi .pubdate = datetime .strptime (pubdate , '%Y' )
457+ elif re .compile ('^\\ d{4}-\\ d+$' ).match (pubdate ):
443458 mi .pubdate = datetime .strptime (pubdate , '%Y-%m' )
444459 elif re .compile ('^\\ d{4}-\\ d+-\\ d+$' ).match (pubdate ):
445460 mi .pubdate = datetime .strptime (pubdate , '%Y-%m-%d' )
@@ -470,64 +485,69 @@ class NLCISBNPlugin(Source):
470485 # name, type, default, label, default, choices
471486 # type 'number', 'string', 'bool', 'choices'
472487 Option (
473- 'max_workers' , 'number' , MAX_WORKERS ,
488+ 'max_workers' , 'number' , CONFIG [ 'max_workers' ] ,
474489 _ ('最大线程数' ),
475490 _ ('爬虫最大线程数。如果过大可能导致用户IP被封锁。' )
476491 ),
477492 Option (
478- 'max_title_list_num' , 'number' , MAX_TITLE_LIST_NUM ,
493+ 'max_title_list_num' , 'number' , CONFIG [ 'max_title_list_num' ] ,
479494 _ ('最大返回量' ),
480495 _ ('通过标题搜索时,最多返回多少数据。请求量过多可能因为请求过于频繁被封锁IP。' )
481496 ),
482497 Option (
483- 'spider_base_sleep_time' , 'number' , SPIDER_BASE_SLEEP_TIME ,
498+ 'spider_base_sleep_time' , 'number' , CONFIG [ 'spider_base_sleep_time' ] ,
484499 _ ('爬虫基础间隔时间' ),
485500 _ ('爬虫两次爬取的间隔时间(单位:ms毫秒)。爬虫间隔时间 = 爬虫基础间隔时间 + 30 ~ 600 ms 的随机间隔时间' )
486501 ),
487502 Option (
488- 'is_strip_title' , 'bool' , IS_STRIP_TITLE ,
503+ 'is_strip_title' , 'bool' , CONFIG [ 'is_strip_title' ] ,
489504 _ ('是否优化标题(实验功能)' ),
490- _ ('是否优化标题。如果该项为“是” ,则去除标题中多余的部分。默认为“是” 。' )
505+ _ ('是否优化标题。如果该项为"是" ,则去除标题中多余的部分。默认为"是" 。' )
491506 ),
492507 Option (
493- 'is_strip_author' , 'bool' , IS_STRIP_AUTHOR ,
508+ 'is_strip_author' , 'bool' , CONFIG [ 'is_strip_author' ] ,
494509 _ ('是否优化作者字段(实验功能)' ),
495- _ ('是否优化作者字段。如果该项为“是” ,则去除作者字段中多余的部分。默认为“是” 。该项可能导致错误,例如名字末尾本身带有“ 著/编” 。' )
510+ _ ('是否优化作者字段。如果该项为"是" ,则去除作者字段中多余的部分。默认为"是" 。该项可能导致错误,例如名字末尾本身带有" 著/编" 。' )
496511 ),
497512 Option (
498- 'is_nlchash' , 'bool' , IS_NCLHASH ,
513+ 'is_nlchash' , 'bool' , CONFIG [ 'is_nlchash' ] ,
499514 _ ('是否使用nlchash字段(实验功能)' ),
500- _ ('是否使用nlchash字段。如果该项为“否” ,则去除nlchash字段。默认为“是” 。该项可能有利于改善isbn相同,而标题不同的情况。' )
515+ _ ('是否使用nlchash字段。如果该项为"否" ,则去除nlchash字段。默认为"是" 。该项可能有利于改善isbn相同,而标题不同的情况。' )
501516 ),
502517 Option (
503- 'is_pursetag' , 'bool' , IS_PURSETAG ,
518+ 'is_pursetag' , 'bool' , CONFIG [ 'is_pursetag' ] ,
504519 _ ('纯净的标签' ),
505- _ ('是否添加“日期”和“ 出版社” 到标签。如果该项为“否” ,则不添加日期和出版社信息到标签。默认为“否” 。' )
520+ _ ('是否添加"日期"和" 出版社" 到标签。如果该项为"否" ,则不添加日期和出版社信息到标签。默认为"否" 。' )
506521 ),
507522 Option (
508- 'is_fuzzy_search_with_author' , 'bool' , IS_FUZZY_SEARCH_WITH_AUTHOR ,
523+ 'is_fuzzy_search_with_author' , 'bool' , CONFIG [ 'is_fuzzy_search_with_author' ] ,
509524 _ ('是否使用作者信息进行模糊搜索(实验功能)' ),
510- _ ('是否将作者信息添加到标题中进行模糊搜索。如果该项为“是” ,则将作者信息添加到标题中进行模糊搜索。默认为“是” 。' )
525+ _ ('是否将作者信息添加到标题中进行模糊搜索。如果该项为"是" ,则将作者信息添加到标题中进行模糊搜索。默认为"是" 。' )
511526 ),
512527 Option (
513- 'add_clc_to_tags' , 'bool' , ADD_CLC_TO_TAGS ,
528+ 'add_clc_to_tags' , 'bool' , CONFIG [ 'add_clc_to_tags' ] ,
514529 _ ('是否添加中图分类号到标签' ),
515- _ ('是否将中图分类号添加到书籍标签中。默认为“是” 。' )
530+ _ ('是否将中图分类号添加到书籍标签中。默认为"是" 。' )
516531 ),
517532 Option (
518- 'convert_clc_to_tag' , 'bool' , CONVERT_CLC_TO_TAG ,
519- _ ('中图分类号是否转化为具体分类' ),
520- _ ('是否将中图分类号转换为具体的分类信息。默认为“是” 。' )
533+ 'convert_clc_to_tag' , 'bool' , CONFIG [ 'convert_clc_to_tag' ] ,
534+ _ ('中图分类号是否转化为具体分类' ),
535+ _ ('是否将中图分类号转换为具体的分类信息。默认为"是" 。' )
521536 ),
522537 Option (
523- 'clc_parse_level' , 'number' , CLC_PARSE_LEVEL ,
538+ 'clc_parse_level' , 'number' , CONFIG [ 'clc_parse_level' ] ,
524539 _ ('中图分类号解析层级' ),
525540 _ ('解析中图分类号的层级深度,取值范围1-3。1表示仅解析一级分类,3表示解析完整分类。默认为2。' )
526541 )
527542 )
528543
529544 def __init__ (self , * args , ** kwargs ):
530545 Source .__init__ (self , * args , ** kwargs )
546+ # 从用户设置更新 CONFIG
547+ global CONFIG
548+ for key in CONFIG :
549+ if key in self .prefs :
550+ CONFIG [key ] = self .prefs [key ]
531551
532552 def get_book_url (self , identifiers ):
533553 return None
@@ -549,7 +569,7 @@ def identify(self, log, result_queue, abort, title=None, authors=None, identifie
549569 metadata = None
550570 if title :
551571 log .info (f"正在根据书名获取metadata..." )
552- if IS_FUZZY_SEARCH_WITH_AUTHOR and authors and isinstance (authors , list ):
572+ if CONFIG [ 'is_fuzzy_search_with_author' ] and authors and isinstance (authors , list ):
553573 title += authors [0 ]
554574
555575 metadatas = title2metadata (title , log , result_queue , self .clean_downloaded_metadata ,
0 commit comments