《贴吧精灵Pro开发实录:从逆向分析到完整落地的全过程》

《贴吧精灵Pro开发实录:从逆向分析到完整落地的全过程》

之前写了很多篇贴吧逆向的拆解文章,这次把它们全部整合成 「贴吧精灵Pro」 这个可运行的软件。从接口分析到代码实现,这款工具已经能稳定完成发帖、回帖、顶贴、分组轮询、代理切换、图片上传等全套自动化操作。下面分享完整源码和开发过程中踩过的坑。

本文目录

  1. 目录结构
  2. 数据文件说明
  3. 数据模块(data_manager)
  4. 线程模块(task_manager)
  5. 功能模块(tieba_client)
  6. 主窗口与界面交互(main_window)
  7. 踩坑记录
  8. 获取软件与源码
  9. 后续计划

一、目录结构

先来看一下目录结构,核心代码主要集中在 core 目录,分别是 task_manager(线程模块)、data_manager(数据模块)以及处理贴吧请求的 tieba_client(功能模块)。

去年写过一款类似的但那是控制台程序,这次进行了优化并加入了图形界面。界面相关的代码主要集中在 ui 目录下,主窗口的核心逻辑在 main_window.py 中,包括各种事件响应和界面初始化。

贴吧精灵Pro/
│
├── core/                          # 核心代码目录
│   ├── __init__.py                # 模块初始化
│   ├── data_manager.py            # 数据管理模块(加载/保存配置)
│   ├── license.py                 # 授权验证模块
│   ├── task_manager.py            # 线程管理模块(任务调度)
│   └── tieba_client.py            # 贴吧功能模块(接口封装)
│
├── data/                          # 数据存储目录
│   ├── _license/                  # 授权数据目录
│   │   ├── device.dat             # 设备指纹
│   │   ├── fail.dat               # 授权失败记录
│   │   ├── last_license.txt       # 最后授权信息
│   │   └── license.dat            # 授权文件
│   ├── accounts/                  # 账号数据
│   │   └── account_config.json    # 账号配置(Cookie、备注、状态)
│   ├── content/                   # 内容库
│   │   ├── contents.txt           # 发帖内容库
│   │   ├── replys.txt             # 回复内容库
│   │   ├── titles.txt             # 标题库
│   │   └── upvotes.txt            # 顶贴内容库
│   ├── groups/                    # 分组数据
│   │   └── groups.json            # 分组配置(账号列表、轮询索引)
│   ├── posts/                     # 发布记录
│   │   └── posts.json             # 帖子记录(链接、时间、账号)
│   ├── proxies/                   # 代理数据
│   │   └── proxy_config.json      # 代理配置(IP列表、缓存、有效期)
│   ├── system/                    # 系统配置
│   │   ├── reply_emojis.txt       # 回复表情库
│   │   ├── reply_identifiers.txt  # 回复标识符库
│   │   ├── settings.json          # 系统设置(概率、超时等)
│   │   └── title_identifiers.txt  # 标题标识符库
│   ├── tasks/                     # 任务数据
│   │   └── tasks.json             # 任务配置(发帖/回复/顶贴)
│   └── tiebas/                    # 贴吧库
│       └── tiebas.txt             # 随机贴吧列表
│
├── logs/                          # 日志目录
│   ├── task_execution/            # 任务执行日志
│   │   ├── task_发帖任务_xxx.log  # 发帖任务日志
│   │   ├── task_回复任务_xxx.log  # 回复任务日志
│   │   └── task_顶贴任务_xxx.log  # 顶贴任务日志
│   ├── app.log                    # 应用日志
│   └── error.log                  # 错误日志
│
├── models/                        # 数据模型目录
│   ├── __init__.py                # 模块初始化
│   ├── account.py                 # 账号模型
│   ├── content.py                 # 内容模型
│   ├── group.py                   # 分组模型
│   ├── proxy.py                   # 代理模型
│   ├── system.py                  # 系统模型
│   └── task.py                    # 任务模型
│
├── ui/                            # 界面目录
│   ├── dialogs/                   # 对话框目录
│   │   ├── __init__.py
│   │   ├── add_account_dialog.py  # 添加账号对话框
│   │   ├── add_account_dialog.ui  # 添加账号UI文件
│   │   ├── add_proxy_dialog.py    # 添加代理对话框
│   │   ├── add_proxy_dialog.ui    # 添加代理UI文件
│   │   ├── post_task_dialog.py    # 发帖任务对话框
│   │   ├── post_task_dialog.ui    # 发帖任务UI文件
│   │   ├── reply_task_dialog.py   # 回复任务对话框
│   │   ├── reply_task_dialog.ui   # 回复任务UI文件
│   │   ├── upvote_task_dialog.py  # 顶贴任务对话框
│   │   └── upvote_task_dialog.ui  # 顶贴任务UI文件
│   ├── __init__.py
│   ├── main_window.py             # 主窗口逻辑(事件、初始化)
│   └── main_window.ui             # 主窗口UI文件
│
├── utils/                         # 工具目录
│   ├── __init__.py
│   ├── logger.py                  # 日志工具
│   └── proxy_api_client.py        # 代理API客户端
│
├── logo.png                       # 软件图标
├── mian.py                        # 程序入口(注意拼写为mian)
├── 使用文档.md                     # 使用说明
├── 功能介绍.md                     # 功能介绍
├── 常见问题.md                     # FAQ
└── 贴吧精灵Pro.spec                # PyInstaller打包配置

二、数据文件说明

data/ 目录下存放了软件运行所需的所有配置文件,下面逐一说明每个文件的用途:

文件路径用途说明
data/accounts/account_config.json存储账号信息,包括 Cookie、备注、账号状态、最后使用时间等
data/tasks/tasks.json存储发帖/回复/顶贴任务的完整配置
data/groups/groups.json分组信息 + 分组内的账号列表 + 轮询索引指针
data/proxies/proxy_config.json代理列表、IP缓存、有效期配置
data/posts/posts.json发布记录,包含帖子链接、发布时间、使用的账号等
data/system/settings.json系统设置:关注概率、签到概率、超时时间、重试次数等
data/system/reply_emojis.txt回复时可随机插入的表情库,每行一个表情
data/system/reply_identifiers.txt回复标识符库(前缀/后缀),每行一个
data/system/title_identifiers.txt标题标识符库,每行一个
data/content/contents.txt发帖内容库,随机取用
data/content/replys.txt回复内容库
data/content/titles.txt标题库
data/content/upvotes.txt顶贴内容库
data/tiebas/tiebas.txt贴吧库,用于随机贴吧发帖
data/_license/授权相关文件(设备指纹、授权状态等)

💡 提示:所有 JSON 文件在程序首次启动时会自动创建默认结构,TXT 文件会生成空文件,用户可自行编辑填充内容。

三、数据模块(data_manager)

data_manager 主要负责加载和管理各类配置数据,包括任务、账号、内容库、分组、代理、系统设置等。它会统一加载所有数据,如果数据文件不存在则自动创建默认数据。

核心方法是 setup_directories(),负责创建完整的数据目录结构:

  def setup_directories(self):
        """创建数据目录结构"""
        self.data_dir = Path("data")
        self.accounts_dir = self.data_dir / "accounts"
        self.tasks_dir = self.data_dir / "tasks"
        self.content_dir = self.data_dir / "content"
        self.tiebas_dir = self.data_dir / "tiebas"
        self.proxies_dir = self.data_dir / "proxies"
        self.posts_dir = self.data_dir / "posts"  # 帖子数据目录
        self.groups_dir = self.data_dir / "groups"  # 新增
        self.system_dir = self.data_dir / "system"  # 👈 添加这一行
        directories = [
            self.data_dir,
            self.accounts_dir,
            self.tasks_dir,
            self.content_dir,
            self.proxies_dir,
            self.posts_dir,
            self.groups_dir,
            self.system_dir
        ]

        for directory in directories:
            directory.mkdir(parents=True, exist_ok=True)

        self.logger.info("数据目录结构创建完成")

load_all_data() 方法则负责批量加载所有配置:

    def load_all_data(self):
        """加载所有数据"""
        try:
            self.load_tasks()
            self.load_accounts()
            self.load_groups()  # 👈 添加这一行
            self.load_content_library()
            self.load_proxy()  # 改为加载代理配置
            self.load_posts()
            self.load_settings()
            self.load_system_identifiers()  # 👈 添加这一行
            # 加载完成后同步默认分组
        except Exception as e:
            self.logger.error(f"加载数据失败: {e}")
            raise
图2:数据模块加载流程图

四、线程模块(task_manager)

task_manager 根据启动的任务从数据模块读取配置,根据不同任务类型执行相应逻辑,同时根据任务配置调度账号、代理、内容库等资源。处理结果通过信号传递给主窗口进行界面刷新。

每个任务默认独立运行在一个线程中,支持多个不同类型任务同时执行,启动多少个任务就对应多少个线程。

核心运行逻辑:

    def run(self):
        timeout = self.data_manager.settings.proxy_connection_timeout
        self.tieba_client.set_timeout(timeout)

        """任务执行主循环"""
        self.is_running = True
        self.task_config.status = TaskStatus.RUNNING
        self.data_manager.update_task(self.task_config)

        # 延迟启动
        if self.task_config.delay_start_enabled and self.task_config.delay_seconds > 0:
            self.data_manager.log_ui_info(f"延迟启动 {self.task_config.delay_seconds} 秒")
            self._wait_with_pause(self.task_config.delay_seconds)

        # 检查生效时间段
        if not self._check_time_range():
            self.stop()
            return

        try:
            if self.task_config.type == TaskType.POST:
                self._run_post_task()
            elif self.task_config.type == TaskType.REPLY:
                self._run_reply_task()
            else:
                self._run_upvote_task()
        except Exception as e:
            self.logger.error(f"任务异常: {e}", exc_info=True)
            self.task_config.status = TaskStatus.STOPPED
            self.data_manager.update_task(self.task_config)

        finally:
            self.is_running = False

五、功能模块(tieba_client)

这是整个软件的核心模块,封装了贴吧的各种接口操作,包括:获取贴吧信息、获取帖子信息、签到、关注、发帖、回复、图片上传等功能。

下面以签到函数为例,它会根据贴吧返回的状态码进行不同级别的处理:

    def sign_forum(self, tieba_base, cookie=None, proxy=None):
        """贴吧签到"""
        url = "https://tieba.baidu.com/c/c/forum/sign_pc"

        kw = tieba_base.get('kw', '')  # 贴吧名称
        fid = tieba_base.get('fid', '')  # 贴吧ID

        headers = {
            "Accept": "application/json, text/plain, */*",
            "Accept-Language": "zh-CN,zh-TW;q=0.9,zh;q=0.8",
            "Connection": "keep-alive",
            "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
            "Origin": "https://tieba.baidu.com",
            "Referer": "https://tieba.baidu.com/",
            "Cookie": cookie,
            "Sec-Fetch-Dest": "empty",
            "Sec-Fetch-Mode": "cors",
            "Sec-Fetch-Site": "same-origin",
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36",
            "sec-ch-ua": "\"Chromium\";v=\"146\", \"Not-A.Brand\";v=\"24\", \"Google Chrome\";v=\"146\"",
            "sec-ch-ua-mobile": "?0",
            "sec-ch-ua-platform": "\"Windows\"",
            "x-requested-with": "XMLHttpRequest"
        }

        data = {
            "kw": kw,
            "fid": fid,
            "sign_from": "pb",
            "sample_id": "",
            "tbs": self.get_tbs(),  # 需要动态获取
            "subapp_type": "pc",
            "_client_type": "20",
        }

        data['sign'] = self.get_sign(self.create_new_url(data))

        try:
            response = requests.post(url, data=data, headers=headers, proxies=proxy, timeout=self.timeout)
            if response.status_code == 200:
                result = response.json()
                if result.get("error_code") == "0" and "签到成功" in result.get("msg", ""):
                    return True, result.get("msg", "签到成功")
                elif result.get("error_code") == "1":
                    raise Exception(result.get("error_msg"))
                elif result.get("error_code") == "5":
                    raise Exception("验证码校验")
                elif result.get("error_code") == '3250001':
                    raise Exception("账号封禁")
                elif result.get("error_code") == "160002":
                    return False, "今日已签到"
                else:
                    error_msg = result.get('msg', f'{result.get("error_msg")}(错误码{result.get("error_code")})')
                    return False, error_msg
            else:
                return False, f"签到失败:(状态码 {response.status_code})"
        except requests.exceptions.ProxyError as e:
            raise Exception(f"代理错误: {str(e)}")
        except requests.exceptions.Timeout as e:
            raise Exception(f"请求超时: {str(e)}")
        except requests.exceptions.ConnectionError as e:
            raise Exception(f"网络连接错误: {str(e)}")
        except requests.exceptions.RequestException as e:
            raise Exception(f"网络请求异常: {str(e)}")
        except Exception as e:
            raise Exception(f"签到异常: {str(e)}")

六、主窗口与界面交互(main_window)

主窗口负责所有界面事件的处理,其中任务列表的刷新逻辑较为关键。每个任务的「启动/暂停/恢复」按钮会根据当前任务状态动态变化:

  • 停止状态 → 显示绿色「▶」开始按钮
  • 运行状态 → 显示橙色「⏸」暂停按钮
  • 暂停状态 → 显示绿色「▶」恢复按钮

同时每个任务还配有停止、配置、删除等操作按钮。

核心的按钮状态逻辑:

            state_btn = None
            if task.status == TaskStatus.STOPPED:
                state_btn = QPushButton("▶")
                state_btn.setToolTip("开始任务")
                state_btn.setStyleSheet(button_style_green)
                state_btn.clicked.connect(lambda checked, t=task: self.run_tasks(t))
            elif task.status == TaskStatus.RUNNING:
                state_btn = QPushButton("⏸")
                state_btn.setToolTip("暂停任务")
                state_btn.setStyleSheet(button_style_orange)
                state_btn.clicked.connect(lambda checked, t=task: self.pause_tasks(t))
            elif task.status == TaskStatus.PAUSED:
                state_btn = QPushButton("▶")
                state_btn.setToolTip("恢复任务")
                state_btn.setStyleSheet(button_style_green)
                state_btn.clicked.connect(lambda checked, t=task: self.resume_tasks(t))
图5:任务列表与按钮状态

七、踩坑记录

开发期间遇到的最大问题是:带图片回复时偶尔出现「楼中楼解析失败」的错误

这个问题不是每次都出现,只是偶尔复现,反复测试了很久都没定位到原因。最后索性直接把要发送的文本和图片在网页端手动发送,经过几次对比测试才发现:

楼中楼和回复别人时不能带图片,只有评论帖子和发帖时可以带图片。

八、获取源码

⚠️ 免责声明:本文仅用于学习交流,请勿用于非法用途。

为了防止被恶意滥用,同时也尊重贴吧平台的反爬策略,本次不提供「贴吧精灵Pro」完整图形化版本的源码

但考虑到学习需求,我整理了之前写的控制台版本供大家参考学习。需要注意的是,由于贴吧近期进行了接口大更新(新增了 sign 等加密参数),控制台版本中的接口目前已全部失效,无法正常使用。

不过,其中的逆向思路、代码结构、请求封装方式仍然具有学习价值,可以作为你自行修复接口或开发新脚本的参考模板。


控制台版本包含的核心内容

模块说明
签到模块批量签到、签到状态检测
发帖模块标题/内容随机、贴吧随机
回复模块帖子抓取、内容库调用
Cookie管理多账号加载、有效性验证
代理支持代理IP轮换、超时重试

源码获取方式

  • 关注公众号:孤狼网络科技 回复:贴吧精灵pro基础版

学习建议

拿到控制台版本源码后,你可以:

  1. 理解代码结构:看明白数据模块、请求模块、任务模块是如何组织的
  2. 逆向新接口:参考本系列之前的逆向文章,自行修复失效的接口
  3. 二次开发:在控制台版本基础上,加入自己的功能或界面

💡 提示:如果你想要完整图形化版本的源码,建议先掌握逆向技能,自行逆向出新版接口后再移植到框架中。授人以鱼不如授人以渔。

九、后续计划

  • 验证码识别模块(对接打码平台)
  • 帖子监控与自动回复
  • 云端配置同步

总结
从逆向分析到落地成「贴吧精灵Pro」这款完整的图形化工具,整个过程涉及接口逆向、多线程调度、数据持久化、GUI 开发等多个技术点。希望这篇文章的源码和踩坑记录能为同样在做贴吧自动化的朋友提供一些参考。

相关搜索:贴吧逆向全集 · JS逆向教程 · Python二次开发

本文由林石工作室提供技术支持,转载请注明出处。

Comments

No comments yet. Why don’t you start the discussion?

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注