cobweb-launcher 3.1.30__py3-none-any.whl → 3.1.32__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cobweb/base/request.py +132 -1
- {cobweb_launcher-3.1.30.dist-info → cobweb_launcher-3.1.32.dist-info}/METADATA +1 -1
- {cobweb_launcher-3.1.30.dist-info → cobweb_launcher-3.1.32.dist-info}/RECORD +6 -6
- {cobweb_launcher-3.1.30.dist-info → cobweb_launcher-3.1.32.dist-info}/LICENSE +0 -0
- {cobweb_launcher-3.1.30.dist-info → cobweb_launcher-3.1.32.dist-info}/WHEEL +0 -0
- {cobweb_launcher-3.1.30.dist-info → cobweb_launcher-3.1.32.dist-info}/top_level.txt +0 -0
cobweb/base/request.py
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
import random
|
2
2
|
import logging
|
3
|
+
import time
|
4
|
+
|
3
5
|
import requests
|
4
6
|
|
5
7
|
from urllib.parse import urlparse
|
@@ -215,7 +217,7 @@ class FileTypeDetector:
|
|
215
217
|
result['methods_used'].append('extension')
|
216
218
|
|
217
219
|
# 3. 如果前两种方法不确定,使用文件签名检测
|
218
|
-
if result['confidence'] in ['unknown', 'medium']:
|
220
|
+
if data and result['confidence'] in ['unknown', 'medium']:
|
219
221
|
signature_detected = self.detect_by_signature(data)
|
220
222
|
if signature_detected:
|
221
223
|
if not result['detected_type']:
|
@@ -309,6 +311,8 @@ class Request:
|
|
309
311
|
"""
|
310
312
|
self.scheme = None
|
311
313
|
self.netloc = None
|
314
|
+
self.detector_info = None
|
315
|
+
self.content_length = None
|
312
316
|
self._validate_url(url)
|
313
317
|
|
314
318
|
self.url = url
|
@@ -408,6 +412,133 @@ class Request:
|
|
408
412
|
"""下载方法,为了向后兼容性保留"""
|
409
413
|
return self.execute()
|
410
414
|
|
415
|
+
def normal_download(self, file_type_detect: bool = True) -> bytes:
|
416
|
+
"""普通下载模式"""
|
417
|
+
detect_settings = self.request_settings.copy()
|
418
|
+
detect_settings.pop('stream', None)
|
419
|
+
|
420
|
+
response = requests.request(
|
421
|
+
method=self.method,
|
422
|
+
url=self.url,
|
423
|
+
**detect_settings
|
424
|
+
)
|
425
|
+
|
426
|
+
if self.check_status_code:
|
427
|
+
response.raise_for_status()
|
428
|
+
|
429
|
+
content_type = response.headers.get('content-type')
|
430
|
+
result = response.content
|
431
|
+
response.close()
|
432
|
+
|
433
|
+
if file_type_detect and not self.detector_info:
|
434
|
+
head_data = result[:64]
|
435
|
+
detector = FileTypeDetector()
|
436
|
+
self.detector_info = detector.get_detailed_info(
|
437
|
+
url=self.url, content_type=content_type, data=head_data
|
438
|
+
)
|
439
|
+
|
440
|
+
return result
|
441
|
+
|
442
|
+
def range_download(self, start: int = 0, chunk_size: int = 1024, file_type_detect: bool = True) -> iter(bytes):
|
443
|
+
# 分块下载
|
444
|
+
downloaded = start
|
445
|
+
retry_count = 0
|
446
|
+
max_retries = 3
|
447
|
+
|
448
|
+
detect_settings = self.request_settings.copy()
|
449
|
+
detect_settings.pop('stream', None)
|
450
|
+
|
451
|
+
if file_type_detect and not self.detector_info:
|
452
|
+
detect_settings.setdefault("headers", {})['Range'] = "bytes=0-63"
|
453
|
+
test_response = requests.request(
|
454
|
+
method=self.method,
|
455
|
+
url=self.url,
|
456
|
+
**detect_settings
|
457
|
+
)
|
458
|
+
content_type = test_response.headers.get("Content-Type")
|
459
|
+
head_data = test_response.content
|
460
|
+
test_response.close()
|
461
|
+
|
462
|
+
detector = FileTypeDetector()
|
463
|
+
self.detector_info = detector.get_detailed_info(
|
464
|
+
url=self.url, content_type=content_type, data=head_data
|
465
|
+
)
|
466
|
+
|
467
|
+
while downloaded < self.content_length:
|
468
|
+
_start = downloaded
|
469
|
+
_end = min(downloaded + chunk_size - 1, self.total_size - 1)
|
470
|
+
detect_settings.setdefault("headers", {})['Range'] = f"bytes={_start}-{_end}"
|
471
|
+
|
472
|
+
response = requests.request(
|
473
|
+
method=self.method,
|
474
|
+
url=self.url,
|
475
|
+
**detect_settings
|
476
|
+
)
|
477
|
+
|
478
|
+
if response.status_code == 206:
|
479
|
+
chunk_data = response.content
|
480
|
+
yield chunk_data
|
481
|
+
downloaded += len(chunk_data)
|
482
|
+
retry_count = 0 # 重置重试计数
|
483
|
+
logging.info(f"下载进度: {downloaded}/{self.total_size} ({downloaded / self.total_size * 100:.1f}%)")
|
484
|
+
|
485
|
+
elif response.status_code == 416: # Range Not Satisfiable
|
486
|
+
logging.info("Range请求超出范围")
|
487
|
+
break
|
488
|
+
|
489
|
+
else:
|
490
|
+
logging.debug(f"Range请求失败: {response.status_code}")
|
491
|
+
if retry_count < max_retries:
|
492
|
+
retry_count += 1
|
493
|
+
time.sleep(0.5)
|
494
|
+
continue
|
495
|
+
|
496
|
+
response.close()
|
497
|
+
|
498
|
+
def detect_accept_ranges(self) -> bool:
|
499
|
+
detect_settings = self.request_settings.copy()
|
500
|
+
detect_settings.pop('stream', None)
|
501
|
+
|
502
|
+
head_response = requests.head(self.url, **detect_settings)
|
503
|
+
if head_response.status_code not in [200, 206]:
|
504
|
+
logging.error(f"HEAD请求失败: {head_response.status_code}")
|
505
|
+
raise ValueError("HTTP状态码错误")
|
506
|
+
|
507
|
+
self.content_length = int(head_response.headers.get('content-length', 0))
|
508
|
+
accept_ranges = str(head_response.headers.get('accept-ranges')).lower()
|
509
|
+
|
510
|
+
supports_range = True
|
511
|
+
|
512
|
+
# 根据检测结果使用不同下载方式
|
513
|
+
if accept_ranges == 'none' or not self.content_length:
|
514
|
+
supports_range = False
|
515
|
+
else:
|
516
|
+
test_range_settings = detect_settings.copy()
|
517
|
+
test_range_settings.setdefault("headers", {})['Range'] = "bytes=0-63"
|
518
|
+
test_response = requests.request(
|
519
|
+
method=self.method,
|
520
|
+
url=self.url,
|
521
|
+
**test_range_settings
|
522
|
+
)
|
523
|
+
head_data = test_response.content
|
524
|
+
content_type = test_response.headers.get("Content-Type")
|
525
|
+
|
526
|
+
if test_response.status_code == 206:
|
527
|
+
if len(head_data) != 64:
|
528
|
+
logging.debug(f"⚠️ Range请求返回长度不匹配: 期望64, 实际{len(head_data)}")
|
529
|
+
supports_range = False
|
530
|
+
else:
|
531
|
+
detector = FileTypeDetector()
|
532
|
+
self.detector_info = detector.get_detailed_info(
|
533
|
+
url=self.url, content_type=content_type, data=head_data
|
534
|
+
)
|
535
|
+
else:
|
536
|
+
supports_range = False
|
537
|
+
|
538
|
+
test_response.close()
|
539
|
+
|
540
|
+
return supports_range
|
541
|
+
|
411
542
|
def detect_file_type(self) -> Dict[str, Any]:
|
412
543
|
"""
|
413
544
|
检测文件类型。
|
@@ -5,7 +5,7 @@ cobweb/base/__init__.py,sha256=NanSxJr0WsqjqCNOQAlxlkt-vQEsERHYBzacFC057oI,222
|
|
5
5
|
cobweb/base/common_queue.py,sha256=hYdaM70KrWjvACuLKaGhkI2VqFCnd87NVvWzmnfIg8Q,1423
|
6
6
|
cobweb/base/item.py,sha256=1bS4U_3vzI2jzSSeoEbLoLT_5CfgLPopWiEYtaahbvw,1674
|
7
7
|
cobweb/base/logger.py,sha256=Vsg1bD4LXW91VgY-ANsmaUu-mD88hU_WS83f7jX3qF8,2011
|
8
|
-
cobweb/base/request.py,sha256=
|
8
|
+
cobweb/base/request.py,sha256=_NRqwZJGwlWgxSzSQjuDEilT0_ckPPRrxpUKUReKTq4,20934
|
9
9
|
cobweb/base/response.py,sha256=L3sX2PskV744uz3BJ8xMuAoAfGCeh20w8h0Cnd9vLo0,11377
|
10
10
|
cobweb/base/seed.py,sha256=ddaWCq_KaWwpmPl1CToJlfCxEEnoJ16kjo6azJs9uls,5000
|
11
11
|
cobweb/base/task_queue.py,sha256=2MqGpHGNmK5B-kqv7z420RWyihzB9zgDHJUiLsmtzOI,6402
|
@@ -34,8 +34,8 @@ cobweb/utils/decorators.py,sha256=ZwVQlz-lYHgXgKf9KRCp15EWPzTDdhoikYUNUCIqNeM,11
|
|
34
34
|
cobweb/utils/dotting.py,sha256=L-jGSApdnFIP4jUWH6p5qIme0aJ1vyDrxAx8wOJWvcs,1960
|
35
35
|
cobweb/utils/oss.py,sha256=wmToIIVNO8nCQVRmreVaZejk01aCWS35e1NV6cr0yGI,4192
|
36
36
|
cobweb/utils/tools.py,sha256=14TCedqt07m4z6bCnFAsITOFixeGr8V3aOKk--L7Cr0,879
|
37
|
-
cobweb_launcher-3.1.
|
38
|
-
cobweb_launcher-3.1.
|
39
|
-
cobweb_launcher-3.1.
|
40
|
-
cobweb_launcher-3.1.
|
41
|
-
cobweb_launcher-3.1.
|
37
|
+
cobweb_launcher-3.1.32.dist-info/LICENSE,sha256=z1rxSIGOyzcSb3orZxFPxzx-0C1vTocmswqBNxpKfEk,1063
|
38
|
+
cobweb_launcher-3.1.32.dist-info/METADATA,sha256=8SmVQDWc48GUGuhEUx8cjOtjD4LtgNG9-2_n0UeJgGc,6051
|
39
|
+
cobweb_launcher-3.1.32.dist-info/WHEEL,sha256=ewwEueio1C2XeHTvT17n8dZUJgOvyCWCt0WVNLClP9o,92
|
40
|
+
cobweb_launcher-3.1.32.dist-info/top_level.txt,sha256=4GETBGNsKqiCUezmT-mJn7tjhcDlu7nLIV5gGgHBW4I,7
|
41
|
+
cobweb_launcher-3.1.32.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|