智能摘要 DeepSeek
Nodeseek是一个专注于服务器管理的技术论坛,提供云服务评测、运维实战经验及VPS优惠信息。近期有用户分享了用Python编写的自动AI回帖脚本,该脚本通过抓取论坛帖子内容,利用AI生成简短评论(不超过15字),并支持模仿已有评论风格或原创回复。脚本包含配置项(需填写API密钥和Cookie)、帖子列表抓取、内容解析、评论提交等功能,并设有防重复处理机制。开发者强调该代码仅供学习测试,实际使用可能导致封号风险。

Nodeseek论坛自动AI回复帖子python代码-易云博客

Nodeseek是有关于服务器的论坛,论坛提供AWS/阿里云/腾讯云等主流云服务评测,分享包括KVM虚拟化、Docker容器、LNMP环境搭建、服务器安全加固等实战经验,同时每日更新全球VPS优惠信息,是站长、开发者和运维人员提升服务器管理能力的社区。

近期有用户公布了其写的自动AI回复帖子python代码(仅用户学习与测试,实际使用可能被封号)

import requests
from bs4 import BeautifulSoup
import re
import time
import json
import random
import string
import base64
from datetime import datetime

# ==============================================================================
# 1. 配置项 - !! 请务必填写下面的机密信息 !!
# ==============================================================================

# 您的 API Key
AI_API_KEY = "" # <- 已为您清空,请重新填入

# 您的 NodeSeek Cookie
NODESEEK_COOKIE = "" # <- 已为您清空,请重新填入

# 循环运行配置
RUN_IN_LOOP = True
LOOP_INTERVAL_MINUTES = 2

# 文件和URL配置
HOMEPAGE_URL = "https://www.nodeseek.com/"
OUTPUT_FILE = "reply_with_ai_comments.txt"
PROCESSED_IDS_FILE = "id.txt"
USER_AGENT = "Mozilla/5.0 (Linux; Android 11; M2009A12C Build/QP1A.190711.021; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/139.0.7204.179 Mobile Safari/538.36"

# ==============================================================================
# 2. 全局变量和工具函数
# ==============================================================================
LOGGED_IN_USER_ID = None

def generate_csrf_token(length=16):
    characters = string.ascii_letters + string.digits
    return ''.join(random.choice(characters) for i in range(length))

def get_ai_comment(title, content, other_comments=None):
    """
    根据是否存在其他评论,动态调用AI生成评论。
    """
    if not AI_API_KEY:
        print("错误: AI_API_KEY 未设置。")
        return None

    # --- 修改点 ---
    # 根据 other_comments 列表是否为空来决定使用哪个 prompt
    if other_comments:
        # 情况一:存在其他评论,AI进行模仿
        print("检测到其他用户评论,AI将进入“模仿”模式...")
        comments_text = "\n- ".join(other_comments)
        prompt = f"""你是一个论坛评论模仿专家。请分析以下论坛帖子的标题、主楼内容以及已有的评论。然后,请模仿这些已有评论的风格、语气和讨论方向,生成一条全新的、意思相近的中文评论。新评论要自然地融入对话,就像是另一个用户发表的。直接输出评论内容,务必简短精炼,小于等于15个字。

帖子标题:{title}

主楼内容:
{content}

已有评论列表:
- {comments_text}
"""
    else:
        # 情况二:没有其他评论,AI进行原创
        print("未检测到其他用户评论,AI将进入“原创”模式...")
        prompt = f"""你的身份是Nodeseek论坛用户,请根据下面的帖子标题和内容,用中文生成一句精炼、地道、且口语化的评论。评论要简短,切中要点, 有幽默感,尽量模仿论坛老哥语气回复,不要说脏话。直接输出评论内容。务必小于等于15个字。

帖子标题:{title}

帖子内容:
{content}
"""

    try:
        print("正在请求 AI 生成评论...")
        response = requests.post(
            url="https://你的Api接口地址/v1/chat/completions",
            headers={"Authorization": f"Bearer {AI_API_KEY}"},
            data=json.dumps({
                "model": "qwen/qwen3-235b-a22b",
                "messages": [{"role": "user", "content": prompt}]
            }),
            timeout=45 # 增加超时以应对更复杂的prompt
        )
        response.raise_for_status()
        data = response.json()
        ai_reply = data['choices'][0]['message']['content'].strip().replace("\"", "")
        print(f"AI 生成的评论: {ai_reply}")
        return ai_reply
    except Exception as e:
        print(f"调用 AI 接口时出错: {e}")
        return None

def post_comment(post_id, comment_text):
    # (此函数无需修改)
    if not NODESEEK_COOKIE: print("错误: NODESEEK_COOKIE 未设置。"); return False
    comment_url = "https://www.nodeseek.com/api/content/new-comment"
    csrf_token = generate_csrf_token()
    headers = {"Content-Type": "application/json", "User-Agent": USER_AGENT, "Cookie": NODESEEK_COOKIE, "Origin": "https://www.nodeseek.com", "Referer": f"https://www.nodeseek.com/post-{post_id}-1", "Csrf-Token": csrf_token}
    payload = {"content": comment_text, "mode": "new-comment", "postId": int(post_id)}
    try:
        print(f"正在向帖子 {post_id} 提交评论...")
        response = requests.post(comment_url, headers=headers, data=json.dumps(payload), timeout=15)
        if response.status_code == 200: print("评论提交成功!"); return True
        else: print(f"评论提交失败。状态码: {response.status_code}, 响应: {response.text}"); return False
    except Exception as e: print(f"提交评论时出错: {e}"); return False

def load_processed_ids(filename):
    try:
        with open(filename, 'r', encoding='utf-8') as f: return set(line.strip() for line in f)
    except FileNotFoundError: return set()

def save_processed_id(filename, post_id):
    try:
        with open(filename, 'a', encoding='utf-8') as f: f.write(str(post_id) + '\n')
    except Exception as e: print(f"保存ID {post_id} 到文件时出错: {e}")

# ==============================================================================
# 3. 网页抓取函数
# ==============================================================================
COMMON_HEADERS = {"User-Agent": USER_AGENT, "Cookie": NODESEEK_COOKIE}

def get_post_list():
    # (此函数无需修改)
    global LOGGED_IN_USER_ID
    if not NODESEEK_COOKIE: print("错误:请先在脚本中填写 NODESEEK_COOKIE 变量。"); return None
    posts = []
    try:
        print("正在以登录状态请求首页...")
        response = requests.get(HOMEPAGE_URL, headers=COMMON_HEADERS, timeout=15)
        response.raise_for_status()
        soup = BeautifulSoup(response.text, 'html.parser')
        if LOGGED_IN_USER_ID is None:
            config_script = soup.find('script', id='temp-script')
            if config_script and config_script.string:
                try:
                    json_text = base64.b64decode(config_script.string).decode('utf-8')
                    config_data = json.loads(json_text)
                    LOGGED_IN_USER_ID = config_data.get('user', {}).get('member_id')
                    if LOGGED_IN_USER_ID: print(f"成功自动获取到登录用户ID: {LOGGED_IN_USER_ID}")
                except Exception as e: print(f"解析用户信息时出错: {e}")
        post_titles = soup.find_all('div', class_='post-title')
        for item in post_titles:
            link_tag = item.find('a')
            if link_tag and link_tag.has_attr('href'):
                match = re.search(r'/post-(\d+)-', link_tag['href'])
                if match: posts.append({'title': link_tag.get_text(strip=True), 'id': match.group(1)})
        return posts
    except Exception as e: print(f"抓取帖子列表时出错: {e}"); return None

def get_post_details(post_id):
    """
    获取帖子详情,并额外抓取其他用户的评论。
    返回: (主楼内容, 你是否已评论, 其他人评论的列表)
    """
    detail_url = f"https://www.nodeseek.com/post-{post_id}-1"
    try:
        response = requests.get(detail_url, headers=COMMON_HEADERS, timeout=15)
        response.raise_for_status()
        soup = BeautifulSoup(response.text, 'html.parser')

        # 1. 提取主楼内容
        detail_content = "未能提取到详细内容。"
        main_post_container = soup.find('div', class_='nsk-post')
        if main_post_container:
            content_article = main_post_container.find('article', class_='post-content')
            if content_article:
                detail_content = content_article.get_text(separator='\n', strip=True)
        
        # --- 修改点 ---
        # 2. 检查你是否评论过,并收集其他人的评论
        has_commented = False
        other_comments = []
        if LOGGED_IN_USER_ID:
            comment_items = soup.select('.comment-container .content-item') # 获取所有评论项
            for item in comment_items:
                author_link = item.find('a', class_='author-name')
                if not author_link: continue

                # 检查评论作者是否是自己
                href = author_link.get('href', '')
                is_self = str(LOGGED_IN_USER_ID) in href
                
                if is_self:
                    has_commented = True
                else:
                    # 如果不是自己,则收集该评论内容
                    comment_article = item.find('article', class_='post-content')
                    if comment_article:
                        other_comments.append(comment_article.get_text(strip=True))

        return detail_content, has_commented, other_comments # <- 返回三个值
        
    except Exception as e:
        print(f"抓取帖子 {post_id} 详情时出错: {e}")
        return "抓取详情页失败。", False, []

# ==============================================================================
# 4. 主流程
# ==============================================================================
def main():
    processed_post_ids = load_processed_ids(PROCESSED_IDS_FILE)
    print(f"已从 {PROCESSED_IDS_FILE} 加载 {len(processed_post_ids)} 个已处理的帖子ID。")
    with open(OUTPUT_FILE, 'w', encoding='utf-8') as f:
        f.write(f"脚本启动于 {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")

    while True:
        print(f"\n{'='*20} {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} {'='*20}")
        print("开始新一轮帖子检查...")
        posts = get_post_list()
        
        if posts:
            new_posts_found = False
            for post in posts:
                post_id = post['id']
                if post_id in processed_post_ids: continue
                new_posts_found = True
                
                print(f"\n--- 发现新帖子 ID: {post_id} - {post['title']} ---")
                
                # --- 修改点 ---
                # 更新函数调用以接收所有三个返回值
                detail_content, has_commented, other_comments = get_post_details(post_id)

                with open(OUTPUT_FILE, 'a', encoding='utf-8') as f:
                    f.write(f"\n--- [{datetime.now().strftime('%H:%M:%S')}] Post ---\n标题: {post['title']}\nID: {post_id}\n")
                    f.write(f"详细内容:\n{detail_content}\n")

                    if has_commented:
                        print("检测到您已在本帖评论,自动跳过。")
                        f.write("AI评论: 已评论,跳过\n")
                    elif "未能提取" in detail_content or "抓取失败" in detail_content:
                        f.write("AI评论: 跳过(内容抓取失败)\n")
                    else:
                        # 将所有信息传递给AI函数
                        ai_comment = get_ai_comment(post['title'], detail_content, other_comments)
                        if ai_comment:
                            # 更新长度检查
                            if len(ai_comment) <= 15:
                                print(f"评论内容(字数: {len(ai_comment)})符合要求(<=15),准备提交。")
                                f.write(f"AI评论: {ai_comment}\n")
                                post_comment(post_id, ai_comment)
                            else:
                                print(f"评论 '{ai_comment}' 字数过长 (>{len(ai_comment)}),已取消提交。")
                                f.write(f"AI评论: {ai_comment} (内容过长,已取消提交)\n")
                        else:
                            f.write("AI评论: 生成失败\n")
                    
                    save_processed_id(PROCESSED_IDS_FILE, post_id)
                    processed_post_ids.add(post_id)
                
                time.sleep(3)
            
            if not new_posts_found: print("本轮未发现新帖子。")
        else:
            print("未能获取到帖子列表,将在指定时间后重试。")

        if not RUN_IN_LOOP: print("\n单次运行模式完成,程序退出。"); break
        print(f"\n当前轮次处理完毕。等待 {LOOP_INTERVAL_MINUTES} 分钟后开始下一轮...")
        time.sleep(LOOP_INTERVAL_MINUTES * 60)

if __name__ == "__main__":
    main()