feat: Add Xiaohongshu (小红书) URL support
- Add xhslink.com short link resolution - Add xiaohongshu.com note/explore/notes URL patterns - Add discovery/item pattern (resolved from short links) - Add user profile pattern - Support multiple Xiaohongshu URL formats
This commit is contained in:
@@ -6,7 +6,8 @@ Supports:
|
||||
- Bilibili (video, article, up主, collection, series)
|
||||
- YouTube (video, channel, playlist)
|
||||
- Zhihu (question, answer, user, collection)
|
||||
- Short links (b23.tv, etc.)
|
||||
- Xiaohongshu (note, user)
|
||||
- Short links (b23.tv, xhslink.com, etc.)
|
||||
|
||||
Usage:
|
||||
python link-parser.py --url "https://www.bilibili.com/video/BV1xx411c7mD"
|
||||
@@ -44,6 +45,13 @@ class LinkParser:
|
||||
YOUTUBE_USER_PATTERN = re.compile(r'(?:https?://)?(?:www\.)?youtube\.com/user/([a-zA-Z0-9_-]+)')
|
||||
YOUTUBE_PLAYLIST_PATTERN = re.compile(r'(?:https?://)?(?:www\.)?youtube\.com/playlist\?list=([a-zA-Z0-9_-]+)')
|
||||
|
||||
# Xiaohongshu (小红书) patterns
|
||||
XIAOHONGSHU_SHORT_PATTERN = re.compile(r'https?://xhslink\.com/o/([a-zA-Z0-9]+)')
|
||||
XIAOHONGSHU_NOTE_PATTERN = re.compile(r'https?://(?:www\.)?xiaohongshu\.com/explore/([a-zA-Z0-9]+)')
|
||||
XIAOHONGSHU_NOTE_PATTERN2 = re.compile(r'https?://(?:www\.)?xiaohongshu\.com/notes/([a-zA-Z0-9]+)')
|
||||
XIAOHONGSHU_DISCOVERY_PATTERN = re.compile(r'https?://(?:www\.)?xiaohongshu\.com/discovery/item/([a-zA-Z0-9]+)')
|
||||
XIAOHONGSHU_USER_PATTERN = re.compile(r'https?://(?:www\.)?xiaohongshu\.com/user/profile/(\d+)')
|
||||
|
||||
# Zhihu patterns
|
||||
ZHIHAU_QUESTION_PATTERN = re.compile(r'https?://(?:www\.)?zhihu\.com/question/(\d+)')
|
||||
ZHIHAU_ANSWER_PATTERN = re.compile(r'https?://(?:www\.)?zhihu\.com/question/\d+/answer/(\d+)')
|
||||
@@ -84,6 +92,15 @@ class LinkParser:
|
||||
# Fallback: return original URL
|
||||
return url
|
||||
|
||||
# Check if it's Xiaohongshu short link
|
||||
if self.XIAOHONGSHU_SHORT_PATTERN.match(url):
|
||||
try:
|
||||
import requests
|
||||
response = requests.get(url, allow_redirects=True, timeout=10)
|
||||
return response.url
|
||||
except Exception:
|
||||
return url
|
||||
|
||||
return url
|
||||
|
||||
def extract_bilibili_id(self, url: str) -> Optional[Dict[str, str]]:
|
||||
@@ -361,6 +378,63 @@ class LinkParser:
|
||||
|
||||
return None
|
||||
|
||||
def extract_xiaohongshu_id(self, url: str) -> Optional[Dict[str, str]]:
|
||||
"""
|
||||
Extract Xiaohongshu ID from URL.
|
||||
|
||||
Args:
|
||||
url: Xiaohongshu URL
|
||||
|
||||
Returns:
|
||||
Dict with platform, type, and id fields, or None if not matched
|
||||
"""
|
||||
# Try short link
|
||||
match = self.XIAOHONGSHU_SHORT_PATTERN.match(url)
|
||||
if match:
|
||||
return {
|
||||
"platform": "xiaohongshu",
|
||||
"type": "note",
|
||||
"id": match.group(1)
|
||||
}
|
||||
|
||||
# Try explore link
|
||||
match = self.XIAOHONGSHU_NOTE_PATTERN.match(url)
|
||||
if match:
|
||||
return {
|
||||
"platform": "xiaohongshu",
|
||||
"type": "note",
|
||||
"id": match.group(1)
|
||||
}
|
||||
|
||||
# Try notes link
|
||||
match = self.XIAOHONGSHU_NOTE_PATTERN2.match(url)
|
||||
if match:
|
||||
return {
|
||||
"platform": "xiaohongshu",
|
||||
"type": "note",
|
||||
"id": match.group(1)
|
||||
}
|
||||
|
||||
# Try discovery item link (resolved from short link)
|
||||
match = self.XIAOHONGSHU_DISCOVERY_PATTERN.match(url)
|
||||
if match:
|
||||
return {
|
||||
"platform": "xiaohongshu",
|
||||
"type": "note",
|
||||
"id": match.group(1)
|
||||
}
|
||||
|
||||
# Try user profile
|
||||
match = self.XIAOHONGSHU_USER_PATTERN.match(url)
|
||||
if match:
|
||||
return {
|
||||
"platform": "xiaohongshu",
|
||||
"type": "user",
|
||||
"id": match.group(1)
|
||||
}
|
||||
|
||||
return None
|
||||
|
||||
def parse(self, url: str) -> Dict[str, Any]:
|
||||
"""
|
||||
Parse URL and extract platform-specific ID.
|
||||
@@ -406,6 +480,13 @@ class LinkParser:
|
||||
result["success"] = True
|
||||
return result
|
||||
|
||||
# Try Xiaohongshu
|
||||
xiaohongshu_result = self.extract_xiaohongshu_id(url)
|
||||
if xiaohongshu_result:
|
||||
result.update(xiaohongshu_result)
|
||||
result["success"] = True
|
||||
return result
|
||||
|
||||
# Check for short links that need resolution
|
||||
short_links = self.shortlink_resolver.detect_short_links(url)
|
||||
if short_links:
|
||||
|
||||
Reference in New Issue
Block a user