本文目录导读:

我来详细介绍如何编写自动发布文章的脚本,包括多种方案和完整示例。
整体架构设计
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
使用步骤
- 安装依赖
# Python pip install requests python-schedule pyyaml
Node.js
npm install axios node-cron
2. **配置文件**
```bash
cp config.example.json config.json
# 编辑配置,填入各平台信息
-
准备文章
mkdir articles # 将markdown文件放入articles目录
-
运行脚本
# 测试连接 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. **频率控制**:设置合理的发布间隔,避免被屏蔽
这个脚本可以根据需求扩展支持更多平台和功能。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播