parsehub 2.3.14__tar.gz → 2.3.15__tar.gz

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.
Files changed (85) hide show
  1. {parsehub-2.3.14/src/parsehub.egg-info → parsehub-2.3.15}/PKG-INFO +2 -2
  2. {parsehub-2.3.14 → parsehub-2.3.15}/pyproject.toml +2 -2
  3. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/parsers/parser/xhs.py +1 -22
  4. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/parsers/parser/zuiyou.py +2 -1
  5. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/provider_api/xhs.py +6 -9
  6. {parsehub-2.3.14 → parsehub-2.3.15/src/parsehub.egg-info}/PKG-INFO +2 -2
  7. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub.egg-info/requires.txt +1 -1
  8. {parsehub-2.3.14 → parsehub-2.3.15}/test/test_core_offline.py +1 -2
  9. {parsehub-2.3.14 → parsehub-2.3.15}/LICENSE +0 -0
  10. {parsehub-2.3.14 → parsehub-2.3.15}/README.md +0 -0
  11. {parsehub-2.3.14 → parsehub-2.3.15}/setup.cfg +0 -0
  12. {parsehub-2.3.14 → parsehub-2.3.15}/src/__init__.py +0 -0
  13. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/__init__.py +0 -0
  14. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/cli.py +0 -0
  15. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/cli_config.py +0 -0
  16. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/config/__init__.py +0 -0
  17. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/config/config.py +0 -0
  18. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/errors.py +0 -0
  19. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/parsers/__init__.py +0 -0
  20. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/parsers/base/__init__.py +0 -0
  21. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/parsers/base/base.py +0 -0
  22. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/parsers/base/ytdlp.py +0 -0
  23. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/parsers/parser/__init__.py +0 -0
  24. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/parsers/parser/bangumi.py +0 -0
  25. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/parsers/parser/bilibili.py +0 -0
  26. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/parsers/parser/coolapk.py +0 -0
  27. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/parsers/parser/douban.py +0 -0
  28. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/parsers/parser/douyin.py +0 -0
  29. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/parsers/parser/facebook.py +0 -0
  30. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/parsers/parser/instagram.py +0 -0
  31. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/parsers/parser/kuaishou.py +0 -0
  32. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/parsers/parser/medium.py +0 -0
  33. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/parsers/parser/pipix.py +0 -0
  34. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/parsers/parser/snapchat.py +0 -0
  35. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/parsers/parser/threads.py +0 -0
  36. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/parsers/parser/tieba.py +0 -0
  37. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/parsers/parser/tiktok.py +0 -0
  38. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/parsers/parser/toutiao.py +0 -0
  39. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/parsers/parser/twitter.py +0 -0
  40. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/parsers/parser/weibo.py +0 -0
  41. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/parsers/parser/weixin.py +0 -0
  42. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/parsers/parser/wxchannels.py +0 -0
  43. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/parsers/parser/xiaoheihe.py +0 -0
  44. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/parsers/parser/youtube.py +0 -0
  45. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/parsers/parser/zhihu.py +0 -0
  46. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/provider_api/__init__.py +0 -0
  47. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/provider_api/bangumi.py +0 -0
  48. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/provider_api/bilibili.py +0 -0
  49. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/provider_api/coolapk.py +0 -0
  50. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/provider_api/douban.py +0 -0
  51. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/provider_api/douyin.py +0 -0
  52. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/provider_api/instagram.py +0 -0
  53. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/provider_api/kuaishou.py +0 -0
  54. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/provider_api/medium.py +0 -0
  55. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/provider_api/pipix.py +0 -0
  56. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/provider_api/threads.py +0 -0
  57. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/provider_api/tieba.py +0 -0
  58. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/provider_api/tiktok.py +0 -0
  59. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/provider_api/toutiao.py +0 -0
  60. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/provider_api/twitter.py +0 -0
  61. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/provider_api/weibo.py +0 -0
  62. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/provider_api/weixin.py +0 -0
  63. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/provider_api/wxchannels.py +0 -0
  64. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/provider_api/xiaoheihe.py +0 -0
  65. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/provider_api/zhihu.py +0 -0
  66. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/provider_api/zuiyou.py +0 -0
  67. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/types/__init__.py +0 -0
  68. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/types/callback.py +0 -0
  69. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/types/media_file.py +0 -0
  70. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/types/media_ref.py +0 -0
  71. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/types/platform.py +0 -0
  72. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/types/post.py +0 -0
  73. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/types/result.py +0 -0
  74. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/utils/downloader.py +0 -0
  75. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/utils/fallback.py +0 -0
  76. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/utils/helpers.py +0 -0
  77. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub/utils/media_info.py +0 -0
  78. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub.egg-info/SOURCES.txt +0 -0
  79. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub.egg-info/dependency_links.txt +0 -0
  80. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub.egg-info/entry_points.txt +0 -0
  81. {parsehub-2.3.14 → parsehub-2.3.15}/src/parsehub.egg-info/top_level.txt +0 -0
  82. {parsehub-2.3.14 → parsehub-2.3.15}/test/test_bilibili_offline.py +0 -0
  83. {parsehub-2.3.14 → parsehub-2.3.15}/test/test_cli.py +0 -0
  84. {parsehub-2.3.14 → parsehub-2.3.15}/test/test_cli_config.py +0 -0
  85. {parsehub-2.3.14 → parsehub-2.3.15}/test/test_downloader.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: parsehub
3
- Version: 2.3.14
3
+ Version: 2.3.15
4
4
  Summary: 轻量、异步、开箱即用的社交媒体聚合解析库
5
5
  Author-email: 梓澪 <zilingmio@gmail.com>
6
6
  License: MIT
@@ -22,7 +22,7 @@ Requires-Dist: pydub>=0.25.1
22
22
  Requires-Dist: python-dotenv>=1.0.1
23
23
  Requires-Dist: tenacity>=8.5.0
24
24
  Requires-Dist: urlextract>=1.9.0
25
- Requires-Dist: yt-dlp[default]>=2026.10.10.233141.dev0
25
+ Requires-Dist: yt-dlp[default]>=2026.10.26.220202.dev0
26
26
  Requires-Dist: lxml>=5.3.0
27
27
  Requires-Dist: pydantic>=1.10.19
28
28
  Requires-Dist: markdownify>=1.1.0
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "parsehub"
3
- version = "2.3.14"
3
+ version = "2.3.15"
4
4
  description = "轻量、异步、开箱即用的社交媒体聚合解析库"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12.0"
@@ -25,7 +25,7 @@ dependencies = [
25
25
  "python-dotenv>=1.0.1",
26
26
  "tenacity>=8.5.0",
27
27
  "urlextract>=1.9.0",
28
- "yt-dlp[default]>=2026.10.10.233141.dev0",
28
+ "yt-dlp[default]>=2026.10.26.220202.dev0",
29
29
  "lxml>=5.3.0",
30
30
  "pydantic>=1.10.19",
31
31
  "markdownify>=1.1.0",
@@ -1,8 +1,6 @@
1
1
  import re
2
2
  from typing import Union
3
3
 
4
- import httpx
5
-
6
4
  from ...provider_api.xhs import MOBILE_HEADERS, PC_HEADERS, XHSAPI, XHSMedia, XHSMediaType, XHSPost, XHSPostType
7
5
  from ...types import (
8
6
  ContentUnavailableError,
@@ -81,12 +79,8 @@ class XHSParser(BaseParser):
81
79
  LivePhotoRef(url=i.thumb_url or "", video_url=i.url, width=i.width, height=i.height)
82
80
  )
83
81
  else:
84
- # 小红书图片格式: "png" | "webp" | "jpeg" | "heic" | "avif"
85
- ext = await self.get_ext_by_url(i.url)
86
- if ext not in ["png", "webp", "jpeg", "heic", "avif"]:
87
- ext = "jpeg"
88
82
  photos.append(
89
- ImageRef(url=i.url, ext=ext, thumb_url=i.thumb_url, width=i.width, height=i.height)
83
+ ImageRef(url=i.url, ext="jpg", thumb_url=i.thumb_url, width=i.width, height=i.height)
90
84
  )
91
85
 
92
86
  return ImageParseResult(
@@ -97,21 +91,6 @@ class XHSParser(BaseParser):
97
91
  case _:
98
92
  raise ParseError("不支持的类型")
99
93
 
100
- async def get_ext_by_url(self, url: str) -> str:
101
- async with httpx.AsyncClient(proxy=self.proxy) as client:
102
- try:
103
- response = await client.head(url, follow_redirects=True)
104
- except Exception:
105
- return ""
106
-
107
- if content_type := response.headers.get("content-type"):
108
- media_type = content_type.split(";")[0].strip()
109
- if "/" in media_type:
110
- extension = media_type.split("/")[-1]
111
- return str(extension)
112
-
113
- return ""
114
-
115
94
  @staticmethod
116
95
  def hashtag_handler(desc: str | None) -> str:
117
96
  if not desc:
@@ -6,7 +6,8 @@ from ..base.base import BaseParser
6
6
  class ZuiYouParser(BaseParser):
7
7
  __platform__ = Platform.ZUIYOU
8
8
  __supported_type__ = ["视频", "图文"]
9
- __match__ = r"^(http(s)?://)share.xiaochuankeji.cn/hybrid/share/post\?pid=\d+"
9
+ __match__ = r"^(http(s)?://)(share.xiaochuankeji.cn/hybrid/share/post\?pid=\d+|s.izuiyou.com/s/\w+)"
10
+ __redirect_keywords__ = ["s.izuiyou.com/s/"]
10
11
  __reserved_parameters__ = ["pid"]
11
12
 
12
13
  async def _do_parse(self, raw_url: str) -> MultimediaParseResult:
@@ -8,6 +8,7 @@ import re
8
8
  from dataclasses import dataclass
9
9
  from enum import Enum
10
10
  from typing import Any, cast
11
+ from urllib.parse import urlsplit
11
12
 
12
13
  import httpx
13
14
  from bs4 import BeautifulSoup
@@ -87,6 +88,7 @@ class XHSAPI:
87
88
  script = scripts[0].text
88
89
  json_data = script.replace("window.__INITIAL_STATE__=", "")
89
90
  json_data = re.sub(r"\bundefined\b", "null", json_data) # 清理js对象
91
+ json_data = re.sub(r"new Set\((\[[^\]]*\])\)", r"\1", json_data)
90
92
  data = json.loads(json_data)
91
93
  return cast(dict[str, Any], data)
92
94
 
@@ -192,18 +194,13 @@ class XHSAPI:
192
194
 
193
195
  @staticmethod
194
196
  def get_trace_id(img_url: str) -> str:
195
- match = re.search(r"/[a-f0-9]{32}/(.*)/([^/!]+)(?:!.*)?", img_url)
196
- if match:
197
- return f"{match.group(1)}/{match.group(2)}"
198
-
199
- match = re.search(r"/([^/!]+)(?:!.*)?$", img_url)
200
- if match:
201
- return match.group(1)
202
- return img_url
197
+ path = urlsplit(img_url).path.split("!", 1)[0]
198
+ match = re.search(r"/[a-f0-9]{32}/(.+)", path)
199
+ return match.group(1) if match else path.lstrip("/")
203
200
 
204
201
  def get_raw_image_url(self, ime_url: str) -> str:
205
202
  """拼接无水印图片链接"""
206
- return f"http://sns-img-hw.xhscdn.com/{self.get_trace_id(ime_url)}"
203
+ return f"https://sns-img-hw.xhscdn.com/{self.get_trace_id(ime_url)}?imageView2/format/jpg"
207
204
 
208
205
 
209
206
  class XHSMediaType(Enum):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: parsehub
3
- Version: 2.3.14
3
+ Version: 2.3.15
4
4
  Summary: 轻量、异步、开箱即用的社交媒体聚合解析库
5
5
  Author-email: 梓澪 <zilingmio@gmail.com>
6
6
  License: MIT
@@ -22,7 +22,7 @@ Requires-Dist: pydub>=0.25.1
22
22
  Requires-Dist: python-dotenv>=1.0.1
23
23
  Requires-Dist: tenacity>=8.5.0
24
24
  Requires-Dist: urlextract>=1.9.0
25
- Requires-Dist: yt-dlp[default]>=2026.10.10.233141.dev0
25
+ Requires-Dist: yt-dlp[default]>=2026.10.26.220202.dev0
26
26
  Requires-Dist: lxml>=5.3.0
27
27
  Requires-Dist: pydantic>=1.10.19
28
28
  Requires-Dist: markdownify>=1.1.0
@@ -5,7 +5,7 @@ pydub>=0.25.1
5
5
  python-dotenv>=1.0.1
6
6
  tenacity>=8.5.0
7
7
  urlextract>=1.9.0
8
- yt-dlp[default]>=2026.10.10.233141.dev0
8
+ yt-dlp[default]>=2026.10.26.220202.dev0
9
9
  lxml>=5.3.0
10
10
  pydantic>=1.10.19
11
11
  markdownify>=1.1.0
@@ -640,8 +640,7 @@ class TestPlatformUrlMatching(unittest.TestCase):
640
640
  ],
641
641
  Platform.XIAOHEIHE: [
642
642
  "https://www.xiaoheihe.cn/app/bbs/link/174972336",
643
- "https://www.xiaoheihe.cn/v3/bbs/app/api/web/share?link_id=174972336",
644
- "https://api.xiaoheihe.cn/v3/bbs/app/link?link_id=174972336",
643
+ "https://api.xiaoheihe.cn/v3/bbs/app/api/web/share?h_camp=link&h_src=YXBwX3NoYXJl&link_id=57b172affdbc",
645
644
  ],
646
645
  Platform.YOUTUBE: [
647
646
  "https://www.youtube.com/watch?v=1h_uc3K4Cpg",
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes