Files
bettafish-company/MindSpider/DeepSentimentCrawling/MediaCrawler/tools/utils.py
T

213 lines
7.1 KiB
Python

# 声明:本代码仅供学习和研究目的使用。使用者应遵守以下原则:
# 1. 不得用于任何商业用途。
# 2. 使用时应遵守目标平台的使用条款和robots.txt规则。
# 3. 不得进行大规模爬取或对平台造成运营干扰。
# 4. 应合理控制请求频率,避免给目标平台带来不必要的负担。
# 5. 不得用于任何非法或不当的用途。
#
# 详细许可条款请参阅项目根目录下的LICENSE文件。
# 使用本代码即表示您同意遵守上述原则和LICENSE中的所有条款。
import argparse
import logging
import os
import re
import sys
from logging.handlers import RotatingFileHandler
from pathlib import Path
from .crawler_util import *
from .slider_util import *
from .time_util import *
def init_loging_config():
level = logging.INFO
# 日志格式
log_format = "%(asctime)s %(name)s %(levelname)s (%(filename)s:%(lineno)d) - %(message)s"
date_format = '%Y-%m-%d %H:%M:%S'
# 创建日志目录(项目根目录的 logs 文件夹)
# 从当前文件位置向上查找,直到找到包含 logs 目录的项目根目录
current_file = Path(__file__).resolve()
project_root = None
# 方法1: 向上查找直到找到 logs 目录
for parent in current_file.parents:
logs_dir = parent / "logs"
if logs_dir.exists() or parent.name == "BettaFish-1.2.0":
project_root = parent
break
# 方法2: 如果没找到,使用当前工作目录
if project_root is None:
project_root = Path.cwd()
# 如果当前在 MediaCrawler 目录,向上查找
if project_root.name == "MediaCrawler":
project_root = project_root.parent.parent
log_dir = project_root / "logs"
log_dir.mkdir(exist_ok=True)
# 日志文件路径
log_file = log_dir / "mediacrawler.log"
# 配置根日志记录器
root_logger = logging.getLogger()
root_logger.setLevel(level)
# 清除已有的处理器,避免重复
root_logger.handlers.clear()
# 控制台处理器 - 明确使用 sys.stdout 确保输出到控制台
console_handler = logging.StreamHandler(sys.stdout)
console_handler.setLevel(level)
console_formatter = logging.Formatter(log_format, datefmt=date_format)
console_handler.setFormatter(console_formatter)
root_logger.addHandler(console_handler)
# 确保输出立即刷新
sys.stdout.flush()
sys.stderr.flush()
# 文件处理器(带轮转,最大10MB,保留5个备份)
try:
file_handler = RotatingFileHandler(
log_file,
maxBytes=10 * 1024 * 1024, # 10MB
backupCount=5,
encoding='utf-8'
)
file_handler.setLevel(level)
file_formatter = logging.Formatter(log_format, datefmt=date_format)
file_handler.setFormatter(file_formatter)
root_logger.addHandler(file_handler)
except Exception as e:
# 如果文件日志初始化失败,至少保证控制台日志可用
print(f"警告: 无法初始化文件日志: {e}")
# 创建 MediaCrawler 专用日志记录器
_logger = logging.getLogger("MediaCrawler")
_logger.setLevel(level)
# 关闭 httpx 的 INFO 日志
logging.getLogger("httpx").setLevel(logging.WARNING)
# 输出日志文件位置
_logger.info(f"日志文件: {log_file}")
return _logger
logger = init_loging_config()
def str2bool(v):
if isinstance(v, bool):
return v
if v.lower() in ('yes', 'true', 't', 'y', '1'):
return True
elif v.lower() in ('no', 'false', 'f', 'n', '0'):
return False
else:
raise argparse.ArgumentTypeError('Boolean value expected.')
def check_keyword_match_strict(content: str, keyword: str) -> bool:
"""
严格关键词匹配:检查内容是否包含关键词(严格模式)
Args:
content: 要检查的内容文本
keyword: 关键词(可以是单个关键词,也可以是逗号分隔的多个关键词)
Returns:
bool: 如果内容包含任意一个关键词返回True,否则返回False
"""
if not content or not keyword:
return False
# 清理HTML标签
clean_content = re.sub(r"<.*?>", "", content)
# 转换为小写进行匹配
clean_content_lower = clean_content.lower()
# 支持多个关键词(逗号分隔),只要匹配任意一个即可
keywords = [k.strip().lower() for k in keyword.split(",") if k.strip()]
# 检查内容是否包含任意一个关键词
for kw in keywords:
if kw in clean_content_lower:
return True
return False
def check_keyword_match_fuzzy(content: str, keyword: str) -> bool:
"""
模糊关键词匹配:检查内容是否包含关键词(模糊模式,支持部分匹配)
Args:
content: 要检查的内容文本
keyword: 关键词(可以是单个关键词,也可以是逗号分隔的多个关键词)
Returns:
bool: 如果内容包含任意一个关键词(或关键词的部分)返回True,否则返回False
"""
if not content or not keyword:
return False
# 清理HTML标签
clean_content = re.sub(r"<.*?>", "", content)
# 转换为小写进行匹配
clean_content_lower = clean_content.lower()
# 支持多个关键词(逗号分隔),只要匹配任意一个即可
keywords = [k.strip().lower() for k in keyword.split(",") if k.strip()]
# 检查内容是否包含任意一个关键词(或关键词的部分)
for kw in keywords:
# 精确匹配
if kw in clean_content_lower:
return True
# 模糊匹配:如果关键词长度>=3,检查是否包含关键词的主要部分
if len(kw) >= 3:
# 去除空格后匹配
kw_no_space = kw.replace(" ", "")
content_no_space = clean_content_lower.replace(" ", "")
if kw_no_space in content_no_space:
return True
# 检查关键词的前半部分(至少2个字符)
if len(kw) >= 4:
half_kw = kw[:len(kw)//2]
if half_kw in clean_content_lower:
return True
return False
def check_keyword_match_with_modes(content: str, strict_keywords: str = None, fuzzy_keywords: str = None) -> bool:
"""
使用精确和模糊两种模式检查关键词匹配
Args:
content: 要检查的内容文本
strict_keywords: 精确匹配关键词(逗号分隔)
fuzzy_keywords: 模糊匹配关键词(逗号分隔)
Returns:
bool: 如果内容匹配任意一个关键词(精确或模糊)返回True,否则返回False
"""
# 先检查精确匹配关键词
if strict_keywords:
if check_keyword_match_strict(content, strict_keywords):
return True
# 再检查模糊匹配关键词
if fuzzy_keywords:
if check_keyword_match_fuzzy(content, fuzzy_keywords):
return True
return False