下载地址:https://www.pan38.com/yun/share.php?code=JCnzE 提取密码:1133
这个工具框架包含了小红书和抖音的批量发布功能,支持图片和视频处理、定时发布等功能。使用时需要先配置config.json文件,填入从平台获取的API凭证。代码包含了错误处理和请求间隔,避免被封禁。
import os
import time
import json
import requests
from typing import List, Dict
from datetime import datetime
from PIL import Image, ImageFilter
from moviepy.editor import VideoFileClip
class SocialMediaPoster:
def init(self, config_path: str = "config.json"):
self.config = self._load_config(config_path)
self.xiaohongshu_api = "https://api.xiaohongshu.com"
self.douyin_api = "https://open.douyin.com"
self.session = requests.Session()
def _load_config(self, path: str) -> Dict:
with open(path, 'r', encoding='utf-8') as f:
return json.load(f)
def _get_xiaohongshu_token(self) -> str:
url = f"{self.xiaohongshu_api}/oauth/access_token"
payload = {
"client_id": self.config["xiaohongshu"]["client_id"],
"client_secret": self.config["xiaohongshu"]["client_secret"],
"grant_type": "client_credentials"
}
response = self.session.post(url, data=payload)
return response.json().get("access_token")
def _get_douyin_token(self) -> str:
url = f"{self.douyin_api}/oauth/access_token/"
params = {
"client_key": self.config["douyin"]["client_key"],
"client_secret": self.config["douyin"]["client_secret"],
"grant_type": "client_credential"
}
response = self.session.get(url, params=params)
return response.json().get("access_token")
def _process_image(self, image_path: str) -> str:
img = Image.open(image_path)
if img.mode != 'RGB':
img = img.convert('RGB')
img = img.filter(ImageFilter.SHARPEN)
output_path = f"processed_{os.path.basename(image_path)}"
img.save(output_path)
return output_path
def _process_video(self, video_path: str) -> str:
clip = VideoFileClip(video_path)
if clip.duration > 60: # 超过60秒的视频需要裁剪
clip = clip.subclip(0, 60)
output_path = f"processed_{os.path.basename(video_path)}"
clip.write_videofile(output_path)
return output_path
def post_to_xiaohongshu(self, content: str, media_paths: List[str],
scheduled_time: datetime = None) -> Dict:
token = self._get_xiaohongshu_token()
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
}
processed_media = []
for path in media_paths:
if path.lower().endswith(('.png', '.jpg', '.jpeg')):
processed_media.append(self._process_image(path))
elif path.lower().endswith(('.mp4', '.mov')):
processed_media.append(self._process_video(path))
payload = {
"content": content,
"media_urls": processed_media,
"visibility": self.config["xiaohongshu"].get("visibility", "PUBLIC")
}
if scheduled_time:
payload["scheduled_publish_time"] = scheduled_time.isoformat()
url = f"{self.xiaohongshu_api}/api/v1/notes"
response = self.session.post(url, headers=headers, json=payload)
return response.json()
def post_to_douyin(self, content: str, video_path: str,
scheduled_time: datetime = None) -> Dict:
token = self._get_douyin_token()
headers = {
"access-token": token,
"Content-Type": "application/json"
}
processed_video = self._process_video(video_path)
payload = {
"text": content,
"video_url": processed_video,
"privacy_level": self.config["douyin"].get("privacy_level", 0)
}
if scheduled_time:
payload["publish_time"] = scheduled_time.timestamp()
url = f"{self.douyin_api}/api/v1/video/upload"
response = self.session.post(url, headers=headers, json=payload)
return response.json()
def batch_post(self, platform: str, posts: List[Dict]) -> List[Dict]:
results = []
for post in posts:
try:
if platform.lower() == "xiaohongshu":
result = self.post_to_xiaohongshu(
post["content"],
post["media_paths"],
post.get("scheduled_time")
)
elif platform.lower() == "douyin":
result = self.post_to_douyin(
post["content"],
post["video_path"],
post.get("scheduled_time")
)
else:
raise ValueError(f"Unsupported platform: {platform}")
results.append({
"status": "success",
"platform": platform,
"post_id": result.get("id"),
"response": result
})
time.sleep(5) # 防止请求过于频繁
except Exception as e:
results.append({
"status": "failed",
"platform": platform,
"error": str(e)
})
return results
’
‘from datetime import datetime, timedelta
from social_media_poster import SocialMediaPoster
def main():
poster = SocialMediaPoster()
# 小红书批量发布
xhs_posts = [
{
"content": "今天分享一个美食教程 #美食 #教程",
"media_paths": ["food1.jpg", "food2.jpg"],
"scheduled_time": datetime.now() + timedelta(hours=1)
},
{
"content": "旅行日记 #旅行 #摄影",
"media_paths": ["travel1.jpg", "travel2.jpg", "travel_video.mp4"]
}
]
xhs_results = poster.batch_post("xiaohongshu", xhs_posts)
print("小红书发布结果:", xhs_results)
# 抖音批量发布
dy_posts = [
{
"content": "搞笑视频来啦 #搞笑 #娱乐",
"video_path": "funny_video.mp4",
"scheduled_time": datetime.now() + timedelta(hours=2)
}
]
dy_results = poster.batch_post("douyin", dy_posts)
print("抖音发布结果:", dy_results)
if name == "main":
main()
from datetime import datetime, timedelta
from social_media_poster import SocialMediaPoster
def main():
poster = SocialMediaPoster()
# 小红书批量发布
xhs_posts = [
{
"content": "今天分享一个美食教程 #美食 #教程",
"media_paths": ["food1.jpg", "food2.jpg"],
"scheduled_time": datetime.now() + timedelta(hours=1)
},
{
"content": "旅行日记 #旅行 #摄影",
"media_paths": ["travel1.jpg", "travel2.jpg", "travel_video.mp4"]
}
]
xhs_results = poster.batch_post("xiaohongshu", xhs_posts)
print("小红书发布结果:", xhs_results)
# 抖音批量发布
dy_posts = [
{
"content": "搞笑视频来啦 #搞笑 #娱乐",
"video_path": "funny_video.mp4",
"scheduled_time": datetime.now() + timedelta(hours=2)
}
]
dy_results = poster.batch_post("douyin", dy_posts)
print("抖音发布结果:", dy_results)
if name == "main":
main()