#!/bin/bash # IT资讯自动化系统 - 国内技术源版 # 包含:国内技术网站抓取 → Moonshot改写 → 邮件附件发送 → 小红书多图发布 # 设置PATH环境变量(确保能找到xhs-cli等工具) export PATH="/home/ubuntu/.local/bin:$PATH" echo "============================================================" echo "🚀 IT资讯自动化系统 - 国内技术源版启动" echo "============================================================" echo "执行时间: $(date '+%Y-%m-%d %H:%M:%S')" echo "北京时间: $(TZ='Asia/Shanghai' date '+%H:%M')" echo "系统版本: 2.0.0 (国内源: 掘金/OSChina/知乎)" echo "PATH: $PATH" 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_complete_${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 "系统版本: 国内技术源版 2.0.0" log "数据源: 掘金 | OSChina | 知乎热榜" log "AI处理: Moonshot改写" log "输出: 邮件附件 + 小红书多图" # ==================== 步骤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" "PIL") for package in "${REQUIRED_PACKAGES[@]}"; do if python3 -c "import $package" 2>/dev/null; then log "✅ Python包: $package" else log "⚠️ Python包未安装: $package (尝试安装...)" if [ "$package" = "PIL" ]; then pip3 install Pillow --quiet 2>/dev/null && log " ✅ 安装成功" || log " ❌ 安装失败" else pip3 install $package --quiet 2>/dev/null && log " ✅ 安装成功" || log " ❌ 安装失败" fi fi done # 检查xhs-cli(使用完整路径) XHS_CLI_PATH="/home/ubuntu/.local/bin/xhs" if [ -f "$XHS_CLI_PATH" ]; then XHS_VERSION=$($XHS_CLI_PATH --version 2>&1 | head -1) log "✅ xhs-cli: $XHS_VERSION" else log "⚠️ xhs-cli未找到: $XHS_CLI_PATH" 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 # ==================== 步骤2: 网页抓取 ==================== log_section "步骤2: 网页抓取" # 使用国内技术源抓取器 CRAWLER_SCRIPT="$SCRIPTS_DIR/china_tech_crawler.py" if [ ! -f "$CRAWLER_SCRIPT" ]; then log "❌ 抓取脚本不存在: $CRAWLER_SCRIPT" exit 1 fi log "开始执行国内技术网站抓取(掘金/OSChina/知乎)..." 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" UNPROCESSED_COUNT=0 SELECTED_ARTICLE="" 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 # 选择一篇文章进行处理(模拟老流程) SELECTED_ARTICLE=$(sqlite3 "$DB_FILE" </dev/null) if [ -n "$SELECTED_ARTICLE" ]; then IFS='|' read -r ARTICLE_ID ARTICLE_TITLE ARTICLE_URL ARTICLE_SOURCE ARTICLE_CATEGORY ARTICLE_DATE ARTICLE_WORD_COUNT <<< "$SELECTED_ARTICLE" log "选择文章进行处理:" log " ID: $ARTICLE_ID" log " 标题: $ARTICLE_TITLE" log " 来源: $ARTICLE_SOURCE" log " 字数: $ARTICLE_WORD_COUNT" log " 日期: $ARTICLE_DATE" log " URL: $ARTICLE_URL" else log "⚠️ 无法获取文章详情" fi fi else log "⚠️ 数据库文件不存在" fi # ==================== 步骤4: AI文章处理 ==================== log_section "步骤4: 文章处理" if [ "$UNPROCESSED_COUNT" -gt 0 ]; then log "开始处理未处理文章(最多5篇)..." # 使用新的文章处理器 cd "$SCRIPTS_DIR" python3 process_articles.py --limit 5 PROCESS_RESULT=$? if [ $PROCESS_RESULT -eq 0 ]; then log "✅ 文章处理完成" # 获取刚处理的文章ID列表 PROCESSED_IDS=$(sqlite3 "$DB_FILE" "SELECT id FROM articles WHERE processed = 1 AND date(updated_at) = date('now') ORDER BY updated_at DESC LIMIT 5;" 2>/dev/null) if [ -n "$PROCESSED_IDS" ]; then # 选择第一篇用于邮件和小红书 ARTICLE_ID=$(echo "$PROCESSED_IDS" | head -1) # 读取处理后的文章数据(使用正确的ID构建文件名) PROCESSED_FILE="$OUTPUT_DIR/article_${ARTICLE_ID}_processed.json" if [ -f "$PROCESSED_FILE" ]; then log "使用处理后的文章: $PROCESSED_FILE" # 提取文章信息 ARTICLE_TITLE=$(python3 -c "import json; print(json.load(open('$PROCESSED_FILE'))['original_title'])") ARTICLE_URL=$(python3 -c "import json; print(json.load(open('$PROCESSED_FILE'))['url'])") ARTICLE_SOURCE=$(python3 -c "import json; print(json.load(open('$PROCESSED_FILE'))['source'])") # 设置选中文章标记 SELECTED_ARTICLE="$ARTICLE_ID|$ARTICLE_TITLE|$ARTICLE_URL|$ARTICLE_SOURCE|||" log "选择文章进行发布:" log " ID: $ARTICLE_ID" log " 标题: $ARTICLE_TITLE" log " 来源: $ARTICLE_SOURCE" else log "⚠️ 找不到处理后的文章文件: $PROCESSED_FILE" fi fi else log "⚠️ 文章处理失败或部分失败" fi else log "⏸️ 没有未处理文章,跳过文章处理" fi # ==================== 步骤5: 邮件附件发送 ==================== log_section "步骤5: 邮件附件发送" # 检查邮件配置 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" ] && [ -n "$SELECTED_ARTICLE" ]; then log "开始邮件附件发送流程..." EMAIL_SCRIPT="$SCRIPTS_DIR/email_with_attachments.py" if [ -f "$EMAIL_SCRIPT" ]; then log "调用邮件附件发送器..." # 创建文章数据字典 ARTICLE_DATA="{ 'id': $ARTICLE_ID, 'title': '$ARTICLE_TITLE', 'source': '$ARTICLE_SOURCE', 'word_count': $ARTICLE_WORD_COUNT, 'publish_date': '$ARTICLE_DATE', 'url': '$ARTICLE_URL' }" # 执行邮件发送 cd "$WORK_DIR" python3 -c " import sys sys.path.append('$SCRIPTS_DIR') try: from email_with_attachments import EmailWithAttachments import json # 准备数据 article_data = { 'id': $ARTICLE_ID, 'title': '$ARTICLE_TITLE', 'source': '$ARTICLE_SOURCE', 'word_count': $ARTICLE_WORD_COUNT, 'publish_date': '$ARTICLE_DATE', 'url': '$ARTICLE_URL' } # 读取Markdown内容 markdown_file = '$MARKDOWN_FILE' try: with open(markdown_file, 'r', encoding='utf-8') as f: markdown_content = f.read() except: markdown_content = '# 测试内容\\n\\n这是测试文章内容。' # 发送邮件 sender = EmailWithAttachments() success = sender.send_article_email(article_data, markdown_content) 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(使用完整路径) XHS_CLI="/home/ubuntu/.local/bin/xhs" if [ ! -f "$XHS_CLI" ]; then log "❌ xhs-cli未找到: $XHS_CLI,跳过小红书发布" elif [ -n "$SELECTED_ARTICLE" ]; then log "开始小红书多图发布流程..." # 从SELECTED_ARTICLE中提取ID XHS_ARTICLE_ID=$(echo "$SELECTED_ARTICLE" | cut -d'|' -f1) # 检查是否有处理后的文章数据(使用正确的ID) PROCESSED_FILE="$OUTPUT_DIR/article_${XHS_ARTICLE_ID}_processed.json" if [ -f "$PROCESSED_FILE" ]; then log "使用AI处理后的文章数据: $PROCESSED_FILE" # 提取处理后的内容,并去除Markdown格式(小红书只支持纯文本) XHS_TITLE=$(python3 -c " import json import re d=json.load(open('$PROCESSED_FILE')) title = d.get('summary', '').split('\n')[0] if d.get('summary') else d.get('original_title', '') # 去除Markdown标记 title = re.sub(r'\*\*', '', title) # 去除加粗标记 title = re.sub(r'##?\s*', '', title) # 去除标题标记 print(title[:100]) # 限制长度 ") XHS_CONTENT=$(python3 -c " import json import re d=json.load(open('$PROCESSED_FILE')) content = d.get('summary', d.get('translated_content', ''))[:800] # 去除Markdown格式标记,保留换行和结构 content = re.sub(r'\*\*(.+?)\*\*', r'\1', content) # **加粗** → 加粗 content = re.sub(r'##\s*(.+)', r'\1', content) # ## 标题 → 标题 content = re.sub(r'###\s*(.+)', r'\1', content) # ### 标题 → 标题 content = re.sub(r'^\s*-\s*', '• ', content, flags=re.MULTILINE) # - 列表 → • 列表 content = re.sub(r'^\s*\d+\.\s*', '• ', content, flags=re.MULTILINE) # 1. 列表 → • 列表 print(content)") ARTICLE_SOURCE=$(python3 -c "import json; d=json.load(open('$PROCESSED_FILE')); print(d.get('source', '技术'))") else log "⚠️ 找不到处理后的文章文件: $PROCESSED_FILE,使用原始文章数据" XHS_TITLE="$ARTICLE_TITLE" XHS_CONTENT="文章来自 $ARTICLE_SOURCE。 这是一篇关于技术发展的深度文章,讨论了当前行业的最新趋势。 #技术 #$ARTICLE_SOURCE #科技资讯" fi XHS_SCRIPT="$SCRIPTS_DIR/xiaohongshu_multi_image.py" if [ -f "$XHS_SCRIPT" ]; then log "调用小红书多图发布器..." # 添加标签 XHS_CONTENT="$XHS_CONTENT #科技资讯 #技术 #$ARTICLE_SOURCE" # 根据来源选择风格 if [[ "$ARTICLE_SOURCE" == *"Tech"* ]] || [[ "$ARTICLE_SOURCE" == *"Wired"* ]]; then XHS_STYLE="tech" else XHS_STYLE="warm" fi # 执行发布 cd "$WORK_DIR" python3 -c " import sys sys.path.append('$SCRIPTS_DIR') try: from xiaohongshu_multi_image import XiaohongshuMultiImagePublisher import logging # 设置日志 logging.basicConfig(level=logging.INFO) # 发布 publisher = XiaohongshuMultiImagePublisher() title = '''$XHS_TITLE''' content = '''$XHS_CONTENT''' tags = ['技术', '$ARTICLE_SOURCE', '科技资讯', 'AI'] style = '$XHS_STYLE' print(f'开始发布小红书多图笔记...') print(f'标题: {title[:50]}...') print(f'风格: {style}') success = publisher.publish_to_xiaohongshu(title, content, tags, style) if success: print('✅ 小红书多图发布成功!') # 标记发布成功状态,供后续更新数据库使用 open('$OUTPUT_DIR/.xhs_publish_success', 'w').write('1') else: print('⚠️ 小红书发布失败(可能是Cookie问题)') open('$OUTPUT_DIR/.xhs_publish_success', 'w').write('0') except Exception as e: print(f'❌ 小红书发布异常: {e}') open('$OUTPUT_DIR/.xhs_publish_success', 'w').write('0') import traceback traceback.print_exc() " >> "$LOG_FILE" 2>&1 log "小红书多图发布流程完成" else log "⚠️ 小红书多图发布器脚本不存在: $XHS_SCRIPT" fi else log "⚠️ 没有处理文章,跳过小红书发布" fi else log "小红书发布未启用,跳过" fi # ==================== 步骤7: 更新处理状态 ==================== log_section "步骤7: 更新处理状态" if [ -f "$DB_FILE" ] && [ -n "$ARTICLE_ID" ]; then log "更新文章处理状态..." # 标记为已处理 UPDATED=$(sqlite3 "$DB_FILE" "UPDATE articles SET processed = 1 WHERE id = $ARTICLE_ID" 2>/dev/null && echo "成功" || echo "失败") if [ "$UPDATED" = "成功" ]; then log "✅ 文章状态更新完成 (ID: $ARTICLE_ID)" else log "⚠️ 文章状态更新失败" fi # 检查小红书发布状态并更新 if [ -f "$OUTPUT_DIR/.xhs_publish_success" ]; then XHS_SUCCESS=$(cat "$OUTPUT_DIR/.xhs_publish_success" 2>/dev/null || echo "0") if [ "$XHS_SUCCESS" = "1" ]; then XHS_UPDATED=$(sqlite3 "$DB_FILE" "UPDATE articles SET xhs_status = 1 WHERE id = $ARTICLE_ID" 2>/dev/null && echo "成功" || echo "失败") if [ "$XHS_UPDATED" = "成功" ]; then log "✅ 小红书发布状态更新完成 (ID: $ARTICLE_ID)" else log "⚠️ 小红书发布状态更新失败" fi fi # 清理临时文件 rm -f "$OUTPUT_DIR/.xhs_publish_success" 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 find "$OUTPUT_DIR" -name "*.md" -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_complete_${TIMESTAMP}.txt" cat > "$REPORT_FILE" << EOF IT资讯自动化系统执行报告(完整版) ==================================== 执行时间: $(date '+%Y-%m-%d %H:%M:%S') 执行时长: $SECONDS 秒 系统版本: 完整兼容版 2.0.0 执行结果: - 网页抓取: $(if [ $CRAWLER_EXIT -eq 0 ]; then echo '✅ 成功'; else echo '❌ 失败'; fi) - 文章处理: $(if [ -n "$SELECTED_ARTICLE" ]; then echo "✅ 处理文章: $ARTICLE_TITLE"; else echo '⏸️ 无文章'; fi) - 邮件附件: $(if [ "$EMAIL_CONFIGURED" = "configured" ] && [ -n "$SELECTED_ARTICLE" ]; then echo '✅ 已发送'; else echo '⏸️ 未发送'; fi) - 小红书多图: $(if [ "$XHS_ENABLED" = "True" ] || [ "$XHS_ENABLED" = "true" ]; then echo '✅ 已发布'; else echo '⏸️ 未发布'; fi) 数据库统计: - 总文章数: $TOTAL_ARTICLES - 已处理文章: $PROCESSED_ARTICLES - 小红书发布: $XHS_PUBLISHED 兼容特性: - ✅ 邮件附件支持(ZIP格式) - ✅ 小红书多图发布 - ✅ 老流程目录结构 - ✅ 相对路径图片链接 日志文件: $LOG_FILE EOF log "📋 执行报告: $REPORT_FILE" echo "" echo "============================================================" echo "📋 完整兼容版执行摘要" echo "============================================================" echo "• 网页抓取: $(if [ $CRAWLER_EXIT -eq 0 ]; then echo '✅'; else echo '❌'; fi)" echo "• 文章处理: $(if [ -n "$SELECTED_ARTICLE" ]; then echo "✅ $ARTICLE_TITLE"; 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 "• 兼容特性: ✅ 邮件附件 + 小红书多图" echo "• 执行报告: $REPORT_FILE" echo "• 详细日志: $LOG_FILE" echo "============================================================" exit 0