first commit

This commit is contained in:
jianxin committed 2025-04-02 21:01:25 +08:00
commit 4890793ce5
1029 files changed
+5992

No files matched your search

+3
View File
@@ -0,0 +1,3 @@
"""工具函数模块."""
# 使 utils 目录成为 Python 包
+147
View File
@@ -0,0 +1,147 @@
import logging
import time
from typing import Optional
from playwright.sync_api import Page, TimeoutError as PlaywrightTimeoutError
logger = logging.getLogger(__name__)
class BrowserUtils:
"""浏览器操作工具类"""
@staticmethod
def wait_for_element(page: Page, selector: str, timeout: int = 30000) -> bool:
"""
等待元素出现
Args:
page: Playwright页面对象
selector: CSS选择器
timeout: 超时时间(毫秒)
Returns:
bool: 成功返回True,超时返回False
"""
try:
page.wait_for_selector(selector, timeout=timeout)
return True
except PlaywrightTimeoutError:
logger.warning(f"等待元素超时: {selector}")
return False
@staticmethod
def fill_input(
page: Page, selector: str, text: str, clear_first: bool = True
) -> bool:
"""
填充输入框
Args:
page: Playwright页面对象
selector: CSS选择器
text: 要填充的文本
clear_first: 是否先清除原有内容
Returns:
bool: 成功返回True,失败返回False
"""
try:
# 等待元素出现
if not BrowserUtils.wait_for_element(page, selector):
return False
# 如果需要先清除原有内容
if clear_first:
page.fill(selector, "")
# 填充文本
page.fill(selector, text)
return True
except Exception as e:
logger.error(f"填充输入框时出错: {str(e)}")
return False
@staticmethod
def click_element(page: Page, selector: str, timeout: int = 30000) -> bool:
"""
点击元素
Args:
page: Playwright页面对象
selector: CSS选择器
timeout: 超时时间(毫秒)
Returns:
bool: 成功返回True,失败返回False
"""
try:
# 等待元素出现
if not BrowserUtils.wait_for_element(page, selector, timeout):
return False
# 点击元素
page.click(selector)
return True
except Exception as e:
logger.error(f"点击元素时出错: {str(e)}")
return False
@staticmethod
def get_text(page: Page, selector: str) -> Optional[str]:
"""
获取元素文本内容
Args:
page: Playwright页面对象
selector: CSS选择器
Returns:
str or None: 元素文本内容或None
"""
try:
# 等待元素出现
if not BrowserUtils.wait_for_element(page, selector):
return None
# 获取文本内容
return page.text_content(selector)
except Exception as e:
logger.error(f"获取元素文本内容时出错: {str(e)}")
return None
@staticmethod
def take_screenshot(page: Page, path: str) -> bool:
"""
截取屏幕截图
Args:
page: Playwright页面对象
path: 截图保存路径
Returns:
bool: 成功返回True,失败返回False
"""
try:
page.screenshot(path=path)
logger.info(f"已保存截图: {path}")
return True
except Exception as e:
logger.error(f"截图时出错: {str(e)}")
return False
@staticmethod
def is_element_visible(page: Page, selector: str) -> bool:
"""
检查元素是否可见
Args:
page: Playwright页面对象
selector: CSS选择器
Returns:
bool: 可见返回True,不可见返回False
"""
try:
return page.is_visible(selector)
except Exception:
return False
+57
View File
@@ -0,0 +1,57 @@
import os
import logging
from logging.handlers import RotatingFileHandler
import time
def setup_logger():
"""
配置应用程序日志记录器
- 将日志输出到控制台
- 将日志保存到文件(带有时间戳的文件名)
- 使用轮换文件处理程序限制日志文件大小
"""
# 确保日志目录存在
logs_dir = os.path.join(
os.path.dirname(os.path.dirname(os.path.dirname(__file__))), "logs"
)
os.makedirs(logs_dir, exist_ok=True)
# 创建时间戳日志文件名
timestamp = time.strftime("%Y%m%d-%H%M%S")
log_file = os.path.join(logs_dir, f"douyin_imbot_{timestamp}.log")
# 配置根日志记录器
root_logger = logging.getLogger()
root_logger.setLevel(logging.INFO)
# 清除任何现有的处理程序
for handler in root_logger.handlers[:]:
root_logger.removeHandler(handler)
# 创建控制台处理程序
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)
console_format = logging.Formatter(
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)
console_handler.setFormatter(console_format)
root_logger.addHandler(console_handler)
# 创建文件处理程序(限制每个文件大小为5MB,最多保留5个备份)
file_handler = RotatingFileHandler(
log_file, maxBytes=5 * 1024 * 1024, backupCount=5, encoding="utf-8" # 5 MB
)
file_handler.setLevel(logging.INFO)
file_format = logging.Formatter(
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)
file_handler.setFormatter(file_format)
root_logger.addHandler(file_handler)
# 记录启动信息
logging.info("日志系统初始化完成")
logging.info(f"日志文件: {log_file}")
return root_logger