From 8579e7f5242ed6d454bdf355794f214f8ba13f3b Mon Sep 17 00:00:00 2001 From: eric Date: Mon, 5 Jan 2026 03:34:09 -0600 Subject: [PATCH] s'' --- .env | 5 ++ main.py | 125 +++++++++++++++++++++++++++++++++++++++++++++++ requirements.txt | 13 +++++ 3 files changed, 143 insertions(+) create mode 100644 .env create mode 100644 main.py create mode 100644 requirements.txt diff --git a/.env b/.env new file mode 100644 index 0000000..94695ff --- /dev/null +++ b/.env @@ -0,0 +1,5 @@ +TWITTER_CONSUMER_KEY="nQ4HjC7oofnO809VSjvHn5v42" +TWITTER_CONSUMER_SECRET="LFvQGjUsSxeBwwBFAWvrLyWpVxyGCykcDrLfDZjICewmRlB4AZ" +TWITTER_ACCESS_TOKEN="2516769889-Sv8W6R1q9rV7a2GQBk2z3gpcI8jf8Iec96d2d4P" +TWITTER_ACCESS_TOKEN_SECRET="g0mCTwArcMEInFqwA2fLoBORBjvNWdqfptbNn4tuNkkZP" +TWITTER_BEARER_TOKEN="g0mCTwArcMEInFqwA2fLoBORBjvNWdqfptbNn4tuNkkZP" \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..cdadb4b --- /dev/null +++ b/main.py @@ -0,0 +1,125 @@ +from dotenv import load_dotenv +load_dotenv() # 加载 .env 文件中的环境变量 +import tweepy +import schedule +import time +import os +import logging + +# 配置日志 +logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') +logger = logging.getLogger(__name__) + +# 从环境变量读取密钥(安全实践) +consumer_key = os.environ.get('TWITTER_CONSUMER_KEY') +consumer_secret = os.environ.get('TWITTER_CONSUMER_SECRET') +access_token = os.environ.get('TWITTER_ACCESS_TOKEN') +access_token_secret = os.environ.get('TWITTER_ACCESS_TOKEN_SECRET') +bearer_token = os.environ.get('TWITTER_BEARER_TOKEN') + +if not all([consumer_key, consumer_secret, access_token, access_token_secret, bearer_token]): + raise ValueError("Missing Twitter API keys in environment variables.") + +# 创建 OAuth1 用户认证(用于 v1.1 端点,如媒体上传) +auth = tweepy.OAuth1UserHandler(consumer_key, consumer_secret, access_token, access_token_secret) +api_v1 = tweepy.API(auth, wait_on_rate_limit=True) + +# 创建 Client(用于 v2 端点,如发帖) +client = tweepy.Client( + bearer_token=bearer_token, + consumer_key=consumer_key, + consumer_secret=consumer_secret, + access_token=access_token, + access_token_secret=access_token_secret, + wait_on_rate_limit=True +) + +def translate_text(text, target_lang='en'): + """ + 简单文本自动翻译模拟(从中文到英语)。 + 这里使用字符串替换作为示例;实际可替换为 API 调用(如 Google Translate)或库(如 transformers)。 + """ + # 示例翻译映射(扩展这个字典以支持更多) + translations = { + '每日自动问候!当前时间:': 'Daily auto greeting! Current time:', + '每日自动带图问候!当前时间:': 'Daily auto greeting with image! Current time:', + '这是一条自动发帖测试。': 'This is an auto-post test.' + } + for cn, en in translations.items(): + if cn in text: + text = text.replace(cn, en) + return text + +def upload_media(image_paths, max_retries=3): + """上传媒体文件,支持重试""" + media_ids = [] + for image_path in image_paths[:4]: # 限制最多4张 + if not os.path.exists(image_path): + logger.error(f"图片文件不存在: {image_path}") + continue + for attempt in range(max_retries): + try: + media = api_v1.media_upload(filename=image_path) + media_ids.append(media.media_id) + logger.info(f"图片上传成功: {image_path} (Media ID: {media.media_id})") + break + except Exception as e: + logger.warning(f"图片上传失败 {image_path} (尝试 {attempt+1}/{max_retries}): {e}") + if attempt == max_retries - 1: + return [] # 失败后返回空列表 + return media_ids + +def post_tweet(text, image_paths=None): + """ + 通用发帖函数:支持纯文本或带图片。 + 自动翻译文本。 + """ + text = translate_text(text) # 自动翻译 + media_ids = [] + + if image_paths: + media_ids = upload_media(image_paths) + if not media_ids: + logger.error("没有图片上传成功,无法发帖") + return + + try: + response = client.create_tweet(text=text, media_ids=media_ids if media_ids else None) + tweet_id = response.data['id'] + logger.info(f"发帖成功!帖子 ID: {tweet_id}") + logger.info(f"链接: https://x.com/user/status/{tweet_id}") + except tweepy.TweepyException as e: + logger.error(f"发帖失败: {e}") + +def scheduled_post(with_images=False): + """定时任务函数""" + timestamp = time.strftime('%Y-%m-%d %H:%M:%S') + if with_images: + message = f"每日自动带图问候!当前时间: {timestamp}" + image_paths = ["path/to/your/daily_image.jpg"] # 可动态替换(如从文件夹随机选) + post_tweet(message, image_paths) + else: + message = f"每日自动问候!当前时间: {timestamp}" + post_tweet(message) + +if __name__ == "__main__": + import argparse + parser = argparse.ArgumentParser(description="Twitter Auto Poster") + parser.add_argument('--schedule', action='store_true', help="Run in scheduled mode") + args = parser.parse_args() + + if args.schedule: + # 设置定时任务:每天9:00发纯文本帖(可添加带图任务) + schedule.every().day.at("09:00").do(scheduled_post, with_images=False) + # 示例:每天10:00发带图帖 + # schedule.every().day.at("10:00").do(scheduled_post, with_images=True) + + logger.info("定时发帖程序已启动...") + while True: + schedule.run_pending() + time.sleep(60) # 每分钟检查一次 + else: + # 立即执行示例 + message = "Hello from Tweepy! 😊 date: 2026-01-05" + image_paths = ["path/to/your/image1.jpg", "path/to/your/image2.png"] + post_tweet(message, image_paths) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..84dd39a --- /dev/null +++ b/requirements.txt @@ -0,0 +1,13 @@ +# Twitter/X 自动发帖项目依赖 +tweepy>=4.14.0 +schedule>=1.2.2 +python-dotenv>=1.0.1 +# 可选:如果需要更高级的日志或重试机制 +requests>=2.32.3 +requests-oauthlib>=2.0.0 + +# 如果你未来想添加真实翻译功能(例如使用 Google Translate 非官方 API) +# googletrans==4.0.0-rc1 # 注意:非官方,易被封 + +# 如果需要更强大的日志记录 +# loguru>=0.7.2 \ No newline at end of file