CoolBotDataSys/scripts/daily_report.py

191 lines
6.8 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
"""CoolBotDataSys 每日飞书日报推送"""
import sys
import os
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import requests
import logging
from datetime import datetime
from database import db
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def get_collection_stats():
"""获取藏品统计"""
with db.get_cursor() as cursor:
cursor.execute("SELECT COUNT(*) as cnt FROM collections")
total = cursor.fetchone()["cnt"]
return {"total_collections": total}
def get_yichens_stats():
"""获取一尘数据统计"""
with db.get_cursor() as cursor:
# 总帖子数
cursor.execute("SELECT COUNT(*) as cnt FROM yichens_posts")
total_posts = cursor.fetchone()["cnt"]
# 今日新增
cursor.execute("SELECT COUNT(*) as cnt FROM yichens_posts WHERE DATE(crawled_at) = CURDATE()")
today_posts = cursor.fetchone()["cnt"]
# 交易帖数量
cursor.execute("SELECT COUNT(*) as cnt FROM yichens_posts WHERE post_type = 'deal'")
deal_posts = cursor.fetchone()["cnt"]
# 有价格标注的帖子
cursor.execute("SELECT COUNT(*) as cnt FROM yichens_posts WHERE price IS NOT NULL AND price > 0")
priced_posts = cursor.fetchone()["cnt"]
# 今日价格区间统计
cursor.execute("""
SELECT
COUNT(*) as cnt,
AVG(price) as avg_price,
MIN(price) as min_price,
MAX(price) as max_price
FROM yichens_posts
WHERE price IS NOT NULL AND price > 0 AND DATE(crawled_at) = CURDATE()
""")
today_price_stats = cursor.fetchone()
# 最新帖子(标题示例)
cursor.execute("""
SELECT title, price, price_unit
FROM yichens_posts
WHERE price IS NOT NULL AND price > 0
ORDER BY crawled_at DESC LIMIT 5
""")
latest_with_price = cursor.fetchall()
# 最近爬虫状态
cursor.execute("""
SELECT source, status, items_count, finished_at
FROM crawl_logs
ORDER BY finished_at DESC LIMIT 3
""")
crawl_status = cursor.fetchall()
return {
"total_posts": total_posts,
"today_posts": today_posts,
"deal_posts": deal_posts,
"priced_posts": priced_posts,
"today_price_stats": today_price_stats,
"latest_with_price": latest_with_price,
"crawl_status": crawl_status
}
def build_feishu_message(collection_stats, yichens_stats):
"""构建飞书消息卡片"""
now = datetime.now()
# 最新价格帖子示例
latest_items = ""
for item in yichens_stats.get("latest_with_price", []):
price_str = f"¥{item['price']}{item['price_unit']}" if item['price'] else "价格待确认"
latest_items += f"- {item['title'][:30]}... : {price_str}\n"
if not latest_items:
latest_items = "今日暂无价格数据\n"
# 爬虫状态
crawl_info = ""
for log in yichens_stats.get("crawl_status", []):
status_emoji = "" if log["status"] == "success" else ""
crawl_info += f"{status_emoji} {log['source']}: {log['items_count']}条 @ {log['finished_at']}\n"
if not crawl_info:
crawl_info = "暂无爬虫运行记录\n"
# 价格统计
price_stats = yichens_stats.get("today_price_stats", {})
price_info = ""
if price_stats and price_stats.get("cnt", 0) > 0:
price_info = f"均价: ¥{price_stats['avg_price']:.0f} | 区间: ¥{price_stats['min_price']:.0f}{price_stats['max_price']:.0f} ({price_stats['cnt']}条)"
else:
price_info = "今日暂无价格统计"
message = {
"msg_type": "interactive",
"card": {
"header": {
"title": {"tag": "plain_text", "content": f"📊 CoolBotDataSys 日报 {now.strftime('%Y-%m-%d %H:%M')}"},
"template": "blue"
},
"elements": [
{
"tag": "div",
"text": {
"tag": "lark_md",
"content": (
f"**🐉 一尘连体纪念钞数据**\n"
f"- 总帖子: {yichens_stats['total_posts']}\n"
f"- 今日新增: +{yichens_stats['today_posts']}\n"
f"- 交易帖: {yichens_stats['deal_posts']}\n"
f"- 有价格: {yichens_stats['priced_posts']}\n\n"
f"**💰 今日价格动态**\n{price_info}\n\n"
f"**📈 最新交易帖**\n{latest_items}\n\n"
f"**🔄 爬虫状态**\n{crawl_info}"
)
}
},
{"tag": "hr"},
{
"tag": "note",
"elements": [
{"tag": "plain_text", "content": f"CoolBotDataSys · {now.strftime('%H:%M:%S')}"}
]
}
]
}
}
return message
def send_feishu(message):
"""发送飞书消息"""
webhook = os.environ.get("FEISHU_WEBHOOK_URL", "")
if not webhook:
logger.warning("飞书Webhook未配置跳过发送")
return False
try:
response = requests.post(webhook, json=message, timeout=10)
result = response.json()
if result.get("code") == 0 or result.get("StatusCode") == 0:
logger.info("✅ 飞书消息发送成功")
return True
else:
logger.error(f"❌ 飞书发送失败: {result}")
return False
except Exception as e:
logger.error(f"❌ 飞书发送异常: {e}")
return False
def main():
logger.info("📊 开始生成日报...")
collection_stats = get_collection_stats()
yichens_stats = get_yichens_stats()
print(f"统计概览:")
print(f" 一尘帖子总数: {yichens_stats['total_posts']}")
print(f" 今日新增: {yichens_stats['today_posts']}")
print(f" 交易帖: {yichens_stats['deal_posts']}")
print(f" 有价格标注: {yichens_stats['priced_posts']}")
message = build_feishu_message(collection_stats, yichens_stats)
print(f"\n消息卡片内容预览:")
print(message["card"]["elements"][0]["text"]["content"][:500])
# 检查是否启用飞书推送
webhook = os.environ.get("FEISHU_WEBHOOK_URL", "")
if webhook:
send_feishu(message)
else:
print("\n⚠️ 未配置 FEISHU_WEBHOOK_URL 环境变量,跳过飞书推送")
return yichens_stats
if __name__ == "__main__":
main()