107 lines
3.5 KiB
Python
107 lines
3.5 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
# -*- coding: utf-8 -*-
|
||
|
|
|
||
|
|
"""
|
||
|
|
热点数据模型
|
||
|
|
"""
|
||
|
|
|
||
|
|
from dataclasses import dataclass, field
|
||
|
|
from datetime import datetime
|
||
|
|
from typing import Optional, List
|
||
|
|
from enum import Enum
|
||
|
|
|
||
|
|
|
||
|
|
class HotTopicSource(Enum):
|
||
|
|
"""热点来源"""
|
||
|
|
WEIBO = "weibo" # 微博热搜
|
||
|
|
XIAOHONGSHU = "xhs" # 小红书
|
||
|
|
DOUYIN = "douyin" # 抖音
|
||
|
|
BAIDU = "baidu" # 百度热搜
|
||
|
|
BING = "bing" # Bing 搜索
|
||
|
|
CALENDAR = "calendar" # 节日日历
|
||
|
|
CUSTOM = "custom" # 自定义
|
||
|
|
|
||
|
|
|
||
|
|
class HotTopicCategory(Enum):
|
||
|
|
"""热点分类"""
|
||
|
|
TRAVEL = "travel" # 旅游相关
|
||
|
|
FOOD = "food" # 美食
|
||
|
|
FESTIVAL = "festival" # 节日节气
|
||
|
|
EVENT = "event" # 热门事件
|
||
|
|
TRENDING = "trending" # 热门话题
|
||
|
|
SEASON = "season" # 季节性
|
||
|
|
OTHER = "other" # 其他
|
||
|
|
|
||
|
|
|
||
|
|
@dataclass
|
||
|
|
class HotTopic:
|
||
|
|
"""热点话题"""
|
||
|
|
|
||
|
|
# 基本信息
|
||
|
|
title: str # 话题标题
|
||
|
|
source: HotTopicSource # 来源平台
|
||
|
|
|
||
|
|
# 可选信息
|
||
|
|
rank: Optional[int] = None # 排名
|
||
|
|
heat: Optional[int] = None # 热度值
|
||
|
|
category: HotTopicCategory = HotTopicCategory.OTHER
|
||
|
|
url: Optional[str] = None # 原始链接
|
||
|
|
description: Optional[str] = None # 描述
|
||
|
|
tags: List[str] = field(default_factory=list) # 标签
|
||
|
|
|
||
|
|
# 时间信息
|
||
|
|
fetched_at: datetime = field(default_factory=datetime.now)
|
||
|
|
expires_at: Optional[datetime] = None # 过期时间
|
||
|
|
|
||
|
|
# 额外数据
|
||
|
|
extra: dict = field(default_factory=dict)
|
||
|
|
|
||
|
|
def to_dict(self) -> dict:
|
||
|
|
"""转换为字典"""
|
||
|
|
return {
|
||
|
|
'title': self.title,
|
||
|
|
'source': self.source.value,
|
||
|
|
'rank': self.rank,
|
||
|
|
'heat': self.heat,
|
||
|
|
'category': self.category.value,
|
||
|
|
'url': self.url,
|
||
|
|
'description': self.description,
|
||
|
|
'tags': self.tags,
|
||
|
|
'fetched_at': self.fetched_at.isoformat(),
|
||
|
|
'expires_at': self.expires_at.isoformat() if self.expires_at else None,
|
||
|
|
'extra': self.extra,
|
||
|
|
}
|
||
|
|
|
||
|
|
@classmethod
|
||
|
|
def from_dict(cls, data: dict) -> 'HotTopic':
|
||
|
|
"""从字典创建"""
|
||
|
|
return cls(
|
||
|
|
title=data['title'],
|
||
|
|
source=HotTopicSource(data.get('source', 'custom')),
|
||
|
|
rank=data.get('rank'),
|
||
|
|
heat=data.get('heat'),
|
||
|
|
category=HotTopicCategory(data.get('category', 'other')),
|
||
|
|
url=data.get('url'),
|
||
|
|
description=data.get('description'),
|
||
|
|
tags=data.get('tags', []),
|
||
|
|
fetched_at=datetime.fromisoformat(data['fetched_at']) if data.get('fetched_at') else datetime.now(),
|
||
|
|
expires_at=datetime.fromisoformat(data['expires_at']) if data.get('expires_at') else None,
|
||
|
|
extra=data.get('extra', {}),
|
||
|
|
)
|
||
|
|
|
||
|
|
def is_expired(self) -> bool:
|
||
|
|
"""检查是否过期"""
|
||
|
|
if self.expires_at is None:
|
||
|
|
return False
|
||
|
|
return datetime.now() > self.expires_at
|
||
|
|
|
||
|
|
def is_travel_related(self) -> bool:
|
||
|
|
"""检查是否与旅游相关"""
|
||
|
|
travel_keywords = [
|
||
|
|
'旅游', '旅行', '景区', '景点', '酒店', '民宿',
|
||
|
|
'攻略', '自驾', '度假', '出游', '周边游', '亲子游',
|
||
|
|
'海边', '沙滩', '温泉', '滑雪', '露营', '徒步',
|
||
|
|
]
|
||
|
|
title_lower = self.title.lower()
|
||
|
|
return any(kw in title_lower for kw in travel_keywords)
|