如何编写自动发布文章的脚本

wen 实用脚本 2

本文目录导读:

如何编写自动发布文章的脚本

  1. Node.js
  2. 立即发布
  3. 定时发布(每天)

我来详细介绍如何编写自动发布文章的脚本,包括多种方案和完整示例。

整体架构设计

graph LR
    A[文章内容源] --> B[内容处理]
    B --> C[发布平台适配]
    C --> D[自动发布]
    D --> E[发布监控]

Python完整示例

基础发布脚本

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
自动发布文章脚本
支持:WordPress、CSDN、掘金、知乎
"""
import os
import time
import json
import logging
import requests
from datetime import datetime
from typing import Dict, List, Optional
import argparse
# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('publish_log.txt', encoding='utf-8'),
        logging.StreamHandler()
    ]
)
logger = logging.getLogger(__name__)
class ArticlePublisher:
    """文章发布器基类"""
    def __init__(self, config: Dict):
        self.config = config
        self.session = requests.Session()
        self.session.headers.update({
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
        })
    def publish(self, article: Dict) -> bool:
        """发布文章(子类实现)"""
        raise NotImplementedError
class WordPressPublisher(ArticlePublisher):
    """WordPress发布器"""
    def publish(self, article: Dict) -> bool:
        """通过REST API发布到WordPress"""
        try:
            url = f"{self.config['site_url']}/wp-json/wp/v2/posts"
            auth = (self.config['username'], self.config['password'])
            data = {
                'title': article['title'],
                'content': article['content'],
                'status': 'publish',  # draft, publish, pending
                'categories': article.get('categories', []),
                'tags': article.get('tags', []),
            }
            response = self.session.post(url, json=data, auth=auth)
            response.raise_for_status()
            logger.info(f"✅ WordPress发布成功: {article['title']}")
            return True
        except Exception as e:
            logger.error(f"❌ WordPress发布失败: {e}")
            return False
class CSDNPublisher(ArticlePublisher):
    """CSDN发布器(需要Cookie)"""
    def publish(self, article: Dict) -> bool:
        """发布到CSDN"""
        try:
            # 准备CSDN的API接口
            url = "https://blog.csdn.net/community/home-api/v1/article"
            headers = {
                'Cookie': self.config['cookie'],
                'Content-Type': 'application/json',
                'Referer': 'https://editor.csdn.net/',
                'Origin': 'https://editor.csdn.net'
            }
            data = {
                'title': article['title'],
                'markdowncontent': article['content'],
                'categories': article.get('categories', []),
                'tags': article.get('tags', ['']),
                'readType': 'public',
                'hideOriginal': False,
                'type': 'original',
            }
            response = self.session.post(url, json=data, headers=headers)
            response.raise_for_status()
            logger.info(f"✅ CSDN发布成功: {article['title']}")
            return True
        except Exception as e:
            logger.error(f"❌ CSDN发布失败: {e}")
            return False
class ArticleManager:
    """文章管理器"""
    def __init__(self, config_path: str = 'config.json'):
        with open(config_path, 'r', encoding='utf-8') as f:
            self.config = json.load(f)
        self.publishers = self._init_publishers()
    def _init_publishers(self) -> Dict:
        """初始化各平台发布器"""
        publishers = {}
        if 'wordpress' in self.config:
            publishers['wordpress'] = WordPressPublisher(self.config['wordpress'])
        if 'csdn' in self.config:
            publishers['csdn'] = CSDNPublisher(self.config['csdn'])
        return publishers
    def read_articles(self, path: str) -> List[Dict]:
        """读取文章目录"""
        articles = []
        for filename in os.listdir(path):
            if filename.endswith(('.md', '.txt', '.html')):
                filepath = os.path.join(path, filename)
                with open(filepath, 'r', encoding='utf-8') as f:
                    content = f.read()
                # 解析文章信息
                article = self._parse_article(content, filename)
                if article:
                    articles.append(article)
        return articles
    def _parse_article(self, content: str, filename: str) -> Optional[Dict]:
        """解析文章内容"""
        # 支持简单的前置元数据格式
        if content.startswith('---'):
            # 解析YAML front matter
            import re
            match = re.match(r'^---\s*\n(.*?)\n---\s*\n(.*)', content, re.DOTALL)
            if match:
                meta_text = match.group(1)
                content_body = match.group(2)
                # 简单解析 meta
                meta = {}
                for line in meta_text.split('\n'):
                    if ':' in line:
                        key, value = line.split(':', 1)
                        meta[key.strip()] = value.strip()
                return {
                    'title': meta.get('title', filename),
                    'content': content_body,
                    'categories': meta.get('categories', '').split(',') if meta.get('categories') else [],
                    'tags': meta.get('tags', '').split(',') if meta.get('tags') else [],
                }
        # 默认处理
        return {
            'title': filename.split('.')[0],
            'content': content,
            'categories': [],
            'tags': []
        }
    def publish_to_all(self, article: Dict) -> Dict:
        """发布到所有平台"""
        results = {}
        for platform, publisher in self.publishers.items():
            results[platform] = publisher.publish(article)
            time.sleep(2)  # 间隔2秒,避免过快
        return results
    def batch_publish(self, articles_dir: str = 'articles') -> Dict:
        """批量发布文章"""
        all_results = {}
        articles = self.read_articles(articles_dir)
        logger.info(f"📝 找到 {len(articles)} 篇文章")
        for article in articles:
            logger.info(f"📄 正在发布: {article['title']}")
            result = self.publish_to_all(article)
            all_results[article['title']] = result
            # 保存成功/失败状态
            if all(result.values()):
                self._mark_published(article['title'])
            else:
                logger.warning(f"⚠️ 部分平台发布失败: {result}")
            # 随机延迟,3-5分钟
            delay = 180 + int(time.time() % 120)
            logger.info(f"⏳ 等待 {delay/60:.1f} 分钟后下一篇")
            time.sleep(delay)
        return all_results
    def _mark_published(self, title: str):
        """标记文章已发布"""
        state_file = 'publish_state.json'
        state = {}
        if os.path.exists(state_file):
            with open(state_file, 'r') as f:
                state = json.load(f)
        state[title] = datetime.now().isoformat()
        with open(state_file, 'w') as f:
            json.dump(state, f, ensure_ascii=False, indent=2)
    def schedule_publish(self, articles_dir: str, interval_hours: int = 24):
        """定时发布"""
        import schedule
        def job():
            self.batch_publish(articles_dir)
        # 每天在指定时间发布
        schedule.every(interval_hours).hours.do(job)
        # 立即执行第一次
        job()
        while True:
            schedule.run_pending()
            time.sleep(60)
def main():
    """主函数"""
    parser = argparse.ArgumentParser(description='自动发布文章脚本')
    parser.add_argument('--action', choices=['publish', 'schedule', 'test'],
                       default='publish', help='操作类型')
    parser.add_argument('--dir', default='articles', help='文章目录')
    parser.add_argument('--config', default='config.json', help='配置文件路径')
    parser.add_argument('--interval', type=int, default=24, help='发布时间间隔(小时)')
    args = parser.parse_args()
    # 创建发布管理器
    manager = ArticleManager(args.config)
    if args.action == 'publish':
        # 立即发布
        results = manager.batch_publish(args.dir)
        logger.info(f"📊 发布结果: {results}")
    elif args.action == 'schedule':
        # 定时发布
        manager.schedule_publish(args.dir, args.interval)
    elif args.action == 'test':
        # 测试连接
        test_article = {
            'title': '测试文章',
            'content': '这是一篇测试文章。',
            'categories': ['测试'],
            'tags': ['test']
        }
        results = manager.publish_to_all(test_article)
        logger.info(f"🧪 测试结果: {results}")
if __name__ == '__main__':
    main()

配置文件示例 (config.json)

{
  "wordpress": {
    "site_url": "https://your-site.com",
    "username": "your-username",
    "password": "your-application-password"
  },
  "csdn": {
    "cookie": "your-csdn-cookie"
  },
  "juejin": {
    "cookie": "your-juejin-cookie"
  }
}

文章模板示例

--- 我的新文章
categories: 技术,Python
tags: 编程,自动化
---
内容...

其他语言版本

Node.js 版本

// publish.js
const axios = require('axios');
const fs = require('fs');
const path = require('path');
const cron = require('node-cron');
class Publisher {
    constructor(config) {
        this.config = config;
    }
    async publishToWordPress(article) {
        try {
            const response = await axios.post(
                `${this.config.wordpress.url}/posts`,
                {
                    title: article.title,
                    content: article.content,
                    status: 'publish'
                },
                {
                    auth: {
                        username: this.config.wordpress.username,
                        password: this.config.wordpress.password
                    }
                }
            );
            console.log(`✅ WordPress published: ${article.title}`);
            return true;
        } catch (error) {
            console.error('❌ WordPress publish failed:', error.message);
            return false;
        }
    }
    // 从文件读取文章
    readArticles(directory) {
        const articles = [];
        const files = fs.readdirSync(directory);
        for (const file of files) {
            if (file.endsWith('.md') || file.endsWith('.txt')) {
                const content = fs.readFileSync(path.join(directory, file), 'utf8');
                articles.push({
                    title: file.replace(/\.(md|txt)$/, ''),
                    content: content
                });
            }
        }
        return articles;
    }
}
// 定时任务
async function schedulePublish() {
    const publisher = new Publisher(config);
    // 每天8点发布
    cron.schedule('0 8 * * *', async () => {
        console.log('⏰ Publishing scheduled articles...');
        const articles = publisher.readArticles('./articles');
        for (const article of articles) {
            await publisher.publishToWordPress(article);
            await sleep(300000); // 5分钟间隔
        }
    });
}
function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}
// 主入口
const config = require('./config.json');
schedulePublish();

Bash 脚本版本

#!/bin/bash
# publish.sh - 简单的发布脚本
PUBLISH_LOG="publish.log"
ARTICLES_DIR="./articles"
CONFIG_FILE="./publish.conf"
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a $PUBLISH_LOG
}
# 加载配置
source $CONFIG_FILE
# 检查文章目录
if [ ! -d "$ARTICLES_DIR" ]; then
    log "❌ 文章目录不存在: $ARTICLES_DIR"
    exit 1
fi
# 发布单篇文章
publish_article() {
    local file="$1"
    local title=$(basename "$file" | sed 's/\.[^.]*$//')
    local content_file="$file"
    # 使用curl发布到WordPress
    curl -X POST "${WP_URL}/wp-json/wp/v2/posts" \
         -u "${WP_USER}:${WP_PASS}" \
         -H "Content-Type: application/json" \
         -d "{
             \"title\": \"$title\",
             \"content\": \"$(cat $content_file | python3 -c 'import sys,json; print(json.dumps(sys.stdin.read()))')\",
             \"status\": \"publish\"
         }" >> $PUBLISH_LOG 2>&1
    if [ $? -eq 0 ]; then
        log "✅ 发布成功: $title"
        # 移动文章到已发布目录
        mkdir -p "$ARTICLES_DIR/published"
        mv "$file" "$ARTICLES_DIR/published/"
    else
        log "❌ 发布失败: $title"
    fi
}
# 批量发布
publish_all() {
    for file in $ARTICLES_DIR/*.{md,txt,html}; do
        if [ -f "$file" ]; then
            publish_article "$file"
            sleep 300  # 5分钟间隔
        fi
    done
}
# 主逻辑
case "$1" in
    publish)
        publish_all
        ;;
    schedule)
        # 使用cron定时执行
        log "📝 计划任务启动"
        while true; do
            publish_all
            sleep 86400  # 24小时
        done
        ;;
    *)
        echo "用法: $0 {publish|schedule}"
        exit 1
        ;;
esac

使用步骤

  1. 安装依赖
    # Python
    pip install requests python-schedule pyyaml

Node.js

npm install axios node-cron


2. **配置文件**
```bash
cp config.example.json config.json
# 编辑配置,填入各平台信息
  1. 准备文章

    mkdir articles
    # 将markdown文件放入articles目录
  2. 运行脚本

    # 测试连接
    python publish.py --action test

立即发布

python publish.py --action publish --dir articles

定时发布(每天)

python publish.py --action schedule --interval 24


## 五、注意事项
1. **API限制**:各平台API调用频率有限制
2. **安全认证**:使用API密钥而不是明文密码
3. **错误处理**:完善重试机制和日志记录
4. **合规性**:遵守各平台的内容政策
5. **频率控制**:设置合理的发布间隔,避免被屏蔽
这个脚本可以根据需求扩展支持更多平台和功能。

抱歉,评论功能暂时关闭!