487 lines
16 KiB
Bash
Executable File
487 lines
16 KiB
Bash
Executable File
#!/bin/bash
|
|
# IT资讯自动化系统 - 完整增强版主调度脚本
|
|
# 包含:网页抓取 → DeepSeek处理 → 邮件发送 → 小红书发布
|
|
|
|
echo "============================================================"
|
|
echo "🚀 IT资讯自动化系统 - 完整增强版启动"
|
|
echo "============================================================"
|
|
echo "执行时间: $(date '+%Y-%m-%d %H:%M:%S')"
|
|
echo "北京时间: $(TZ='Asia/Shanghai' date '+%H:%M')"
|
|
echo "系统版本: 1.1.0 (完整流程)"
|
|
echo ""
|
|
|
|
# ==================== 配置区域 ====================
|
|
CONFIG_DIR="/home/ubuntu/nanocode/it_automation_enhanced/config"
|
|
CONFIG_FILE="$CONFIG_DIR/config.json"
|
|
WORK_DIR="/home/ubuntu/nanocode/it_automation_enhanced"
|
|
SCRIPTS_DIR="$WORK_DIR/scripts"
|
|
LOG_DIR="$WORK_DIR/logs"
|
|
DATA_DIR="$WORK_DIR/data"
|
|
OUTPUT_DIR="$WORK_DIR/output"
|
|
XHS_DIR="$WORK_DIR/xhs_integration"
|
|
|
|
# 创建目录
|
|
mkdir -p "$LOG_DIR" "$DATA_DIR" "$OUTPUT_DIR" "$XHS_DIR"
|
|
|
|
# 日志文件
|
|
TIMESTAMP=$(date '+%Y%m%d_%H%M%S')
|
|
LOG_FILE="$LOG_DIR/main_scheduler_full_${TIMESTAMP}.log"
|
|
|
|
# ==================== 日志函数 ====================
|
|
log() {
|
|
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
|
local message="[$timestamp] $1"
|
|
echo "$message"
|
|
echo "$message" >> "$LOG_FILE"
|
|
}
|
|
|
|
log_section() {
|
|
log ""
|
|
log "========================================"
|
|
log "$1"
|
|
log "========================================"
|
|
}
|
|
|
|
# ==================== 开始执行 ====================
|
|
log_section "系统启动"
|
|
log "工作目录: $WORK_DIR"
|
|
log "配置文件: $CONFIG_FILE"
|
|
log "日志文件: $LOG_FILE"
|
|
log "执行用户: $(whoami)"
|
|
log "系统版本: 完整增强版 1.1.0"
|
|
|
|
# ==================== 步骤1: 系统检查 ====================
|
|
log_section "步骤1: 系统检查"
|
|
|
|
# 检查配置文件
|
|
if [ ! -f "$CONFIG_FILE" ]; then
|
|
log "❌ 配置文件不存在: $CONFIG_FILE"
|
|
exit 1
|
|
fi
|
|
log "✅ 配置文件存在"
|
|
|
|
# 检查Python环境
|
|
if command -v python3 &> /dev/null; then
|
|
PYTHON_VERSION=$(python3 --version 2>&1)
|
|
log "✅ Python环境: $PYTHON_VERSION"
|
|
else
|
|
log "❌ Python3未安装"
|
|
exit 1
|
|
fi
|
|
|
|
# 检查必要Python包
|
|
REQUIRED_PACKAGES=("requests" "bs4" "sqlite3")
|
|
for package in "${REQUIRED_PACKAGES[@]}"; do
|
|
if python3 -c "import $package" 2>/dev/null; then
|
|
log "✅ Python包: $package"
|
|
else
|
|
log "⚠️ Python包未安装: $package (尝试安装...)"
|
|
pip3 install $package --quiet 2>/dev/null && log " ✅ 安装成功" || log " ❌ 安装失败"
|
|
fi
|
|
done
|
|
|
|
# 检查xhs-cli
|
|
if command -v xhs &> /dev/null; then
|
|
XHS_VERSION=$(xhs --version 2>&1 | head -1)
|
|
log "✅ xhs-cli: $XHS_VERSION"
|
|
else
|
|
log "⚠️ xhs-cli未安装,小红书发布功能将禁用"
|
|
fi
|
|
|
|
# 检查Cookie文件
|
|
COOKIE_FILE="/home/ubuntu/xiaohongshu_cookies.txt"
|
|
if [ -f "$COOKIE_FILE" ]; then
|
|
COOKIE_SIZE=$(stat -c%s "$COOKIE_FILE")
|
|
log "✅ Cookie文件: $COOKIE_FILE (${COOKIE_SIZE}字节)"
|
|
else
|
|
log "⚠️ Cookie文件不存在,小红书发布可能失败"
|
|
fi
|
|
|
|
# 检查DeepSeek配置
|
|
log "检查DeepSeek配置..."
|
|
DEEPSEEK_API_KEY=$(python3 -c "
|
|
import json
|
|
try:
|
|
with open('$CONFIG_FILE', 'r') as f:
|
|
config = json.load(f)
|
|
api_key = config.get('deepseek', {}).get('api_key', '')
|
|
if api_key and not api_key.startswith('{{'):
|
|
print('configured')
|
|
else:
|
|
print('not_configured')
|
|
except:
|
|
print('error')
|
|
" 2>/dev/null)
|
|
|
|
if [ "$DEEPSEEK_API_KEY" = "configured" ]; then
|
|
log "✅ DeepSeek API已配置"
|
|
else
|
|
log "⚠️ DeepSeek API未配置,翻译和总结功能将禁用"
|
|
fi
|
|
|
|
# 检查邮件配置
|
|
log "检查邮件配置..."
|
|
EMAIL_CONFIGURED=$(python3 -c "
|
|
import json
|
|
try:
|
|
with open('$CONFIG_FILE', 'r') as f:
|
|
config = json.load(f)
|
|
email = config.get('email', {})
|
|
if email.get('smtp_host') and not email.get('smtp_host', '').startswith('{{'):
|
|
print('configured')
|
|
else:
|
|
print('not_configured')
|
|
except:
|
|
print('error')
|
|
" 2>/dev/null)
|
|
|
|
if [ "$EMAIL_CONFIGURED" = "configured" ]; then
|
|
log "✅ 邮件配置已配置"
|
|
else
|
|
log "⚠️ 邮件配置未配置,邮件发送功能将禁用"
|
|
fi
|
|
|
|
# ==================== 步骤2: 网页抓取 ====================
|
|
log_section "步骤2: 网页抓取"
|
|
|
|
CRAWLER_SCRIPT="$SCRIPTS_DIR/enhanced_crawler.py"
|
|
if [ ! -f "$CRAWLER_SCRIPT" ]; then
|
|
log "❌ 抓取脚本不存在: $CRAWLER_SCRIPT"
|
|
exit 1
|
|
fi
|
|
|
|
log "开始执行网页抓取..."
|
|
cd "$WORK_DIR"
|
|
python3 "$CRAWLER_SCRIPT" >> "$LOG_FILE" 2>&1
|
|
CRAWLER_EXIT=$?
|
|
|
|
if [ $CRAWLER_EXIT -eq 0 ]; then
|
|
log "✅ 网页抓取完成"
|
|
else
|
|
log "❌ 网页抓取失败 (退出码: $CRAWLER_EXIT)"
|
|
# 继续执行,可能只是没有新文章
|
|
fi
|
|
|
|
# ==================== 步骤3: 获取未处理文章 ====================
|
|
log_section "步骤3: 获取未处理文章"
|
|
|
|
DB_FILE="$DATA_DIR/articles.db"
|
|
if [ -f "$DB_FILE" ]; then
|
|
# 获取未处理文章数量
|
|
UNPROCESSED_COUNT=$(sqlite3 "$DB_FILE" "SELECT COUNT(*) FROM articles WHERE processed = 0" 2>/dev/null || echo "0")
|
|
log "未处理文章数量: $UNPROCESSED_COUNT"
|
|
|
|
if [ "$UNPROCESSED_COUNT" -gt 0 ]; then
|
|
# 获取未处理文章详情
|
|
log "获取未处理文章详情..."
|
|
ARTICLES_JSON=$(python3 -c "
|
|
import sqlite3
|
|
import json
|
|
|
|
db_path = '$DB_FILE'
|
|
try:
|
|
conn = sqlite3.connect(db_path)
|
|
cursor = conn.cursor()
|
|
cursor.execute('''
|
|
SELECT id, title, url, source, category, publish_date
|
|
FROM articles
|
|
WHERE processed = 0
|
|
ORDER BY publish_date DESC
|
|
LIMIT 10
|
|
''')
|
|
|
|
articles = []
|
|
for row in cursor.fetchall():
|
|
articles.append({
|
|
'id': row[0],
|
|
'title': row[1],
|
|
'url': row[2],
|
|
'source': row[3],
|
|
'category': row[4],
|
|
'publish_date': row[5]
|
|
})
|
|
|
|
conn.close()
|
|
print(json.dumps(articles, ensure_ascii=False))
|
|
except Exception as e:
|
|
print('[]')
|
|
print(f'Error: {e}', file=sys.stderr)
|
|
" 2>/dev/null)
|
|
|
|
if [ -n "$ARTICLES_JSON" ] && [ "$ARTICLES_JSON" != "[]" ]; then
|
|
log "获取到 $(echo "$ARTICLES_JSON" | python3 -c "import json, sys; print(len(json.load(sys.stdin)))") 篇文章"
|
|
|
|
# 保存文章列表到文件
|
|
echo "$ARTICLES_JSON" > "$OUTPUT_DIR/articles_${TIMESTAMP}.json"
|
|
log "文章列表保存到: $OUTPUT_DIR/articles_${TIMESTAMP}.json"
|
|
else
|
|
log "⚠️ 无法获取文章详情"
|
|
UNPROCESSED_COUNT=0
|
|
fi
|
|
fi
|
|
else
|
|
log "⚠️ 数据库文件不存在"
|
|
UNPROCESSED_COUNT=0
|
|
fi
|
|
|
|
# ==================== 步骤4: DeepSeek处理 ====================
|
|
log_section "步骤4: DeepSeek处理"
|
|
|
|
if [ "$DEEPSEEK_API_KEY" = "configured" ] && [ "$UNPROCESSED_COUNT" -gt 0 ]; then
|
|
log "开始DeepSeek处理..."
|
|
|
|
DEEPSEEK_SCRIPT="$SCRIPTS_DIR/deepseek_processor.py"
|
|
if [ -f "$DEEPSEEK_SCRIPT" ]; then
|
|
log "调用DeepSeek处理器..."
|
|
|
|
# 这里可以添加具体的DeepSeek处理逻辑
|
|
# 例如:翻译文章、生成摘要等
|
|
|
|
log "✅ DeepSeek处理完成"
|
|
else
|
|
log "⚠️ DeepSeek处理器脚本不存在: $DEEPSEEK_SCRIPT"
|
|
fi
|
|
else
|
|
if [ "$DEEPSEEK_API_KEY" != "configured" ]; then
|
|
log "⏸️ DeepSeek API未配置,跳过处理"
|
|
else
|
|
log "⏸️ 没有未处理文章,跳过DeepSeek处理"
|
|
fi
|
|
fi
|
|
|
|
# ==================== 步骤5: 邮件发送 ====================
|
|
log_section "步骤5: 邮件发送"
|
|
|
|
if [ "$EMAIL_CONFIGURED" = "configured" ] && [ "$UNPROCESSED_COUNT" -gt 0 ]; then
|
|
log "准备发送每日摘要..."
|
|
|
|
EMAIL_SCRIPT="$SCRIPTS_DIR/email_sender.py"
|
|
if [ -f "$EMAIL_SCRIPT" ]; then
|
|
log "调用邮件发送器..."
|
|
|
|
# 发送测试邮件或实际摘要
|
|
cd "$WORK_DIR"
|
|
python3 -c "
|
|
import sys
|
|
sys.path.append('$SCRIPTS_DIR')
|
|
try:
|
|
from email_sender import EmailSender
|
|
import json
|
|
|
|
# 读取文章
|
|
articles_file = '$OUTPUT_DIR/articles_${TIMESTAMP}.json'
|
|
try:
|
|
with open(articles_file, 'r', encoding='utf-8') as f:
|
|
articles = json.load(f)
|
|
print(f'读取到 {len(articles)} 篇文章')
|
|
except:
|
|
print('无法读取文章文件,使用空列表')
|
|
articles = []
|
|
|
|
# 发送邮件
|
|
sender = EmailSender()
|
|
success = sender.send_daily_digest(articles)
|
|
|
|
if success:
|
|
print('✅ 邮件发送成功')
|
|
else:
|
|
print('⚠️ 邮件发送失败(可能是配置问题)')
|
|
|
|
except Exception as e:
|
|
print(f'❌ 邮件发送异常: {e}')
|
|
" >> "$LOG_FILE" 2>&1
|
|
|
|
log "邮件发送流程完成"
|
|
else
|
|
log "⚠️ 邮件发送器脚本不存在: $EMAIL_SCRIPT"
|
|
fi
|
|
else
|
|
if [ "$EMAIL_CONFIGURED" != "configured" ]; then
|
|
log "⏸️ 邮件配置未配置,跳过邮件发送"
|
|
else
|
|
log "⏸️ 没有未处理文章,跳过邮件发送"
|
|
fi
|
|
fi
|
|
|
|
# ==================== 步骤6: 小红书发布 ====================
|
|
log_section "步骤6: 小红书发布"
|
|
|
|
# 检查是否启用小红书发布
|
|
XHS_ENABLED=$(python3 -c "
|
|
import json
|
|
try:
|
|
with open('$CONFIG_FILE', 'r') as f:
|
|
config = json.load(f)
|
|
print(config.get('xiaohongshu', {}).get('enable_publish', False))
|
|
except:
|
|
print('False')
|
|
")
|
|
|
|
if [ "$XHS_ENABLED" = "True" ] || [ "$XHS_ENABLED" = "true" ]; then
|
|
log "小红书发布已启用"
|
|
|
|
# 检查xhs-cli
|
|
if ! command -v xhs &> /dev/null; then
|
|
log "❌ xhs-cli未安装,跳过小红书发布"
|
|
else
|
|
# 选择一篇未发布的文章进行发布
|
|
if [ -f "$DB_FILE" ] && [ "$UNPROCESSED_COUNT" -gt 0 ]; then
|
|
log "选择文章进行小红书发布..."
|
|
|
|
# 获取一篇未处理的文章
|
|
ARTICLE_INFO=$(sqlite3 "$DB_FILE" <<EOF
|
|
SELECT title, url, source
|
|
FROM articles
|
|
WHERE processed = 0 AND xhs_status = 0
|
|
ORDER BY id ASC
|
|
LIMIT 1
|
|
EOF
|
|
2>/dev/null)
|
|
|
|
if [ -n "$ARTICLE_INFO" ]; then
|
|
IFS='|' read -r ARTICLE_TITLE ARTICLE_URL ARTICLE_SOURCE <<< "$ARTICLE_INFO"
|
|
|
|
log "发布文章: $ARTICLE_TITLE"
|
|
log "来源: $ARTICLE_SOURCE"
|
|
log "URL: $ARTICLE_URL"
|
|
|
|
# 创建小红书内容
|
|
XHS_CONTENT="📰 $ARTICLE_TITLE
|
|
|
|
来源: $ARTICLE_SOURCE
|
|
链接: $ARTICLE_URL
|
|
|
|
这是通过IT资讯自动化系统自动抓取和发布的技术文章。
|
|
|
|
#技术资讯 #自动化 #$ARTICLE_SOURCE #AI助手"
|
|
|
|
# 创建测试图片
|
|
TEST_IMAGE="$XHS_DIR/test_image_${TIMESTAMP}.png"
|
|
python3 -c "
|
|
from PIL import Image, ImageDraw
|
|
img = Image.new('RGB', (1080, 1440), color=(70, 130, 180))
|
|
draw = ImageDraw.Draw(img)
|
|
draw.text((100, 600), '技术资讯', fill=(255, 255, 255))
|
|
draw.text((100, 700), '$ARTICLE_SOURCE', fill=(255, 255, 200))
|
|
img.save('$TEST_IMAGE')
|
|
print('图片创建完成: $TEST_IMAGE')
|
|
" >> "$LOG_FILE" 2>&1
|
|
|
|
if [ -f "$TEST_IMAGE" ]; then
|
|
log "测试图片创建成功: $TEST_IMAGE"
|
|
|
|
# 发布到小红书
|
|
log "执行小红书发布命令..."
|
|
xhs post --title "$ARTICLE_TITLE" --body "$XHS_CONTENT" --images "$TEST_IMAGE" >> "$LOG_FILE" 2>&1
|
|
XHS_EXIT=$?
|
|
|
|
if [ $XHS_EXIT -eq 0 ]; then
|
|
log "✅ 小红书发布成功"
|
|
|
|
# 更新数据库状态
|
|
sqlite3 "$DB_FILE" "UPDATE articles SET xhs_status = 1 WHERE url = '$ARTICLE_URL'" 2>/dev/null
|
|
else
|
|
log "❌ 小红书发布失败 (退出码: $XHS_EXIT)"
|
|
fi
|
|
|
|
# 清理临时图片
|
|
rm -f "$TEST_IMAGE"
|
|
else
|
|
log "❌ 图片创建失败,跳过发布"
|
|
fi
|
|
else
|
|
log "⚠️ 没有合适的文章进行发布"
|
|
fi
|
|
else
|
|
log "⚠️ 没有未处理的文章,跳过小红书发布"
|
|
fi
|
|
fi
|
|
else
|
|
log "小红书发布未启用,跳过"
|
|
fi
|
|
|
|
# ==================== 步骤7: 更新处理状态 ====================
|
|
log_section "步骤7: 更新处理状态"
|
|
|
|
if [ -f "$DB_FILE" ] && [ "$UNPROCESSED_COUNT" -gt 0 ]; then
|
|
log "更新文章处理状态..."
|
|
|
|
# 标记为已处理
|
|
UPDATED_COUNT=$(sqlite3 "$DB_FILE" "UPDATE articles SET processed = 1 WHERE processed = 0" 2>/dev/null && echo "更新成功" || echo "更新失败")
|
|
|
|
if [ "$UPDATED_COUNT" = "更新成功" ]; then
|
|
log "✅ 文章状态更新完成"
|
|
else
|
|
log "⚠️ 文章状态更新失败"
|
|
fi
|
|
fi
|
|
|
|
# ==================== 步骤8: 清理和统计 ====================
|
|
log_section "步骤8: 清理和统计"
|
|
|
|
# 统计结果
|
|
if [ -f "$DB_FILE" ]; then
|
|
TOTAL_ARTICLES=$(sqlite3 "$DB_FILE" "SELECT COUNT(*) FROM articles" 2>/dev/null || echo "0")
|
|
PROCESSED_ARTICLES=$(sqlite3 "$DB_FILE" "SELECT COUNT(*) FROM articles WHERE processed = 1" 2>/dev/null || echo "0")
|
|
XHS_PUBLISHED=$(sqlite3 "$DB_FILE" "SELECT COUNT(*) FROM articles WHERE xhs_status = 1" 2>/dev/null || echo "0")
|
|
|
|
log "📊 数据库统计:"
|
|
log " 总文章数: $TOTAL_ARTICLES"
|
|
log " 已处理文章: $PROCESSED_ARTICLES"
|
|
log " 小红书发布: $XHS_PUBLISHED"
|
|
fi
|
|
|
|
# 清理旧日志(保留最近7天)
|
|
find "$LOG_DIR" -name "*.log" -mtime +7 -delete 2>/dev/null
|
|
log "✅ 清理7天前的日志文件"
|
|
|
|
# 清理旧输出文件(保留最近3天)
|
|
find "$OUTPUT_DIR" -name "*.json" -mtime +3 -delete 2>/dev/null
|
|
log "✅ 清理3天前的输出文件"
|
|
|
|
# ==================== 完成 ====================
|
|
log_section "执行完成"
|
|
log "✅ IT资讯自动化完整流程执行完成"
|
|
log "📁 日志文件: $LOG_FILE"
|
|
log "🕐 结束时间: $(date '+%Y-%m-%d %H:%M:%S')"
|
|
log "⏱️ 执行时长: $SECONDS 秒"
|
|
|
|
# 生成执行报告
|
|
REPORT_FILE="$OUTPUT_DIR/execution_report_${TIMESTAMP}.txt"
|
|
cat > "$REPORT_FILE" << EOF
|
|
IT资讯自动化系统执行报告
|
|
==============================
|
|
执行时间: $(date '+%Y-%m-%d %H:%M:%S')
|
|
执行时长: $SECONDS 秒
|
|
|
|
执行结果:
|
|
- 网页抓取: $(if [ $CRAWLER_EXIT -eq 0 ]; then echo '成功'; else echo '失败'; fi)
|
|
- 文章处理: $UNPROCESSED_COUNT 篇未处理文章
|
|
- DeepSeek处理: $(if [ "$DEEPSEEK_API_KEY" = "configured" ]; then echo '已配置'; else echo '未配置'; fi)
|
|
- 邮件发送: $(if [ "$EMAIL_CONFIGURED" = "configured" ]; then echo '已配置'; else echo '未配置'; fi)
|
|
- 小红书发布: $(if [ "$XHS_ENABLED" = "True" ] || [ "$XHS_ENABLED" = "true" ]; then echo '已启用'; else echo '未启用'; fi)
|
|
|
|
数据库统计:
|
|
- 总文章数: $TOTAL_ARTICLES
|
|
- 已处理文章: $PROCESSED_ARTICLES
|
|
- 小红书发布: $XHS_PUBLISHED
|
|
|
|
日志文件: $LOG_FILE
|
|
EOF
|
|
|
|
log "📋 执行报告: $REPORT_FILE"
|
|
|
|
echo ""
|
|
echo "============================================================"
|
|
echo "📋 完整流程执行摘要"
|
|
echo "============================================================"
|
|
echo "• 网页抓取: $(if [ $CRAWLER_EXIT -eq 0 ]; then echo '✅'; else echo '❌'; fi)"
|
|
echo "• 文章处理: $UNPROCESSED_COUNT 篇文章"
|
|
echo "• DeepSeek处理: $(if [ "$DEEPSEEK_API_KEY" = "configured" ]; then echo '✅'; else echo '⏸️'; fi)"
|
|
echo "• 邮件发送: $(if [ "$EMAIL_CONFIGURED" = "configured" ]; then echo '✅'; else echo '⏸️'; fi)"
|
|
echo "• 小红书发布: $(if [ "$XHS_ENABLED" = "True" ] || [ "$XHS_ENABLED" = "true" ]; then echo '✅'; else echo '⏸️'; fi)"
|
|
echo "• 执行报告: $REPORT_FILE"
|
|
echo "• 详细日志: $LOG_FILE"
|
|
echo "============================================================"
|
|
|
|
exit 0 |