抖音自动点赞与评论爬虫项目

刷手机时总觉得手指不够快攒互动、技术入门想玩原生UI框架?这篇文章带你搭建一个可扩展、有防封逻辑、带本地数据盘的抖音UI自动化框架——但首先必须敲个最响的警钟

⚠️ 致命警告⚠️:本项目仅用于UI自动化技术学习与Python项目架构设计参考,抖音等短视频平台的自动化点赞、评论、关注操作违反其《用户协议》《社区规范》甚至部分法律条款,可能导致账号永久封禁、设备IP限流甚至法律追责,请切勿用于任何商业或违规用途,一切后果由使用者自行承担!


为什么选这个方案?

很多入门自动化的朋友一开始会选模拟器+群控脚本、或者第三方库爬取API,但这两种方案要么门槛高成本大、要么一用就封

  • 模拟器群控:设备指纹太统一(IMEI/MAC/CPU型号都是批量改的),抖音风控一秒识别
  • API爬取:需要破解复杂的加密算法(X-Gorgon、X-Ladon、A-Bogus),维护成本极高,而且API调用频率一超就凉

本项目采用 uiautomator2 原生UI桥接ADB 的方案,完美避开以上痛点:

  • ✅ 无需Root/越狱闲置安卓真机,指纹都是真实的
  • ✅ 完全模拟真人的“滑动-停留-点击-打字”操作,风控等级极低
  • ✅ Python代码好写好改,模块化设计方便后续扩展(比如加OCR识别元素、定时调度等)

项目极简架构

整个系统只有5个核心模块,新手也能看懂:

┌─────────────────────────────────────────────┐
│          DouyinAutoBot (大脑中枢)            │
│  - 设备连接/启动抖音  - 执行随机互动逻辑    │
│  - 真人化滑动调度        - 防封阈值预检查    │
└─────────────────────────────────────────────┘
                  ↓ ↓ ↓
┌──────────────────┬──────────────────┬──────────────────┐
│  ActionConfig    │  DatabaseManager │  (可选)Analytics │
│  (动作概率/文本库)│  (本地SQLite存储)│  (互动数据复盘)  │
└──────────────────┴──────────────────┴──────────────────┘
                  ↓ ↓ ↓
┌─────────────────────────────────────────────┐
│          本地SQLite3 (数据仓库)              │
│  - videos(刷到的视频信息)                    │
│  - interactions(点赞/评论/关注记录)          │
└─────────────────────────────────────────────┘

核心代码实现(精简可运行版)

0. 前置准备的坑先踩过

  1. 必须先开启安卓手机的USB调试+USB安装(不同品牌路径不同,搜“[你的品牌] 开发者选项”)
  2. 电脑上要装ADB驱动(Win10+一般插USB自动装,Mac/Linux直接装Android Studio工具包或者用Homebrew/APT)
  3. 验证设备能连上:
adb devices  # 能看到类似「emulator-5554」(模拟器)或「12345678」(真机)的序列号就对了

1. 动作配置与数据模型

把所有硬编码的东西(比如点赞概率、每日上限、评论语)拆出来,方便后续调整:

import logging
from enum import Enum
from dataclasses import dataclass
from typing import Optional, List

# 配置日志,方便看程序运行情况
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s - %(levelname)s - %(message)s"
)
logger = logging.getLogger(__name__)

# 动作类型枚举,避免字符串写错
class ActionType(Enum):
    LIKE = "like"
    COMMENT = "comment"
    FOLLOW = "follow"
    SCROLL = "scroll"

# 用Python 3.7+的dataclass写配置,不用手写__init__
@dataclass
class ActionConfig:
    # 互动概率(加起来不能超过1!剩下的就是只看视频不互动的概率)
    like_prob: float = 0.7
    comment_prob: float = 0.15
    follow_prob: float = 0.03
    # 防封核心:每日互动上限、单视频停留最短/最长时间
    daily_max_actions: int = 80  # 新手建议从50开始试
    min_watch_sec: float = 2.5
    max_watch_sec: float = 6.0
    # 多样化评论语(一定要加表情和不同长度的,别全是短词!)
    comment_pool: List[str] = None
    
    def __post_init__(self):
        if self.comment_pool is None:
            self.comment_pool = [
                "不错不错👍", "学到了学到了!", "默默收藏住", "内容太真实了哈哈哈哈",
                "画面感好强啊", "刚好需要这个方法", "666666", "支持支持",
                "这波操作绝了", "收藏等有空看", "写得好详细", "太棒了!"
            ]
        # 简单验证概率的合理性
        total = self.like_prob + self.comment_prob + self.follow_prob
        if total > 1:
            raise ValueError(f"互动概率总和({total})不能超过1!")

2. 本地数据持久化(SQLite3)

存互动记录和每日统计,后续可以用来复盘什么时候封号/为什么限流,也能防止重复互动(如果能拿到真实的aweme_id的话):

import sqlite3
import time

class DatabaseManager:
    def __init__(self, db_path: str = "douyin_local.db"):
        self.db_path = db_path
        self._init_tables()

    def _init_tables(self):
        """初始化两张核心表:刷过的视频、互动记录"""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        # 刷过的视频表(暂时只用aweme_id和时间,新手可以自己加其他字段)
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS videos (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                aweme_id TEXT UNIQUE,  # 抖音视频的唯一ID,后续用来防止重复互动
                watched_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
            )
        ''')
        
        # 互动记录表
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS interactions (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                aweme_id TEXT,
                action_type TEXT,
                is_success BOOLEAN,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
            )
        ''')
        
        conn.commit()
        conn.close()
        logger.info("✅ 本地数据库初始化完成")

    def get_today_action_count(self) -> int:
        """获取今天已经做了多少次互动,防封核心之一"""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        today_start = time.strftime("%Y-%m-%d 00:00:00")
        cursor.execute(
            'SELECT COUNT(*) FROM interactions WHERE created_at >= ? AND is_success = 1',
            (today_start,)
        )
        count = cursor.fetchone()[0]
        conn.close()
        return count

    def save_interaction(self, aweme_id: str, action_type: str, is_success: bool = True):
        """快速保存一条互动记录"""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        try:
            cursor.execute(
                'INSERT INTO interactions VALUES (NULL, ?, ?, ?, NULL)',
                (aweme_id, action_type, is_success)
            )
            conn.commit()
        except Exception as e:
            logger.error(f"❌ 保存互动记录失败: {e}")
        finally:
            conn.close()

3. 主控制机器人(uiautomator2核心应用)

这里是最关键的部分!注意:原代码用固定坐标点击仅作演示,实际生产/更稳定的学习中,建议结合 Airtest图像模板匹配uiautomator2的text/desc/id定位(但抖音元素id经常变,Airtest更靠谱):

import uiautomator2 as u2
import random
import time

class DouyinAutoBot:
    def __init__(self, device_id: Optional[str] = None):
        self.config = ActionConfig()
        self.db = DatabaseManager()
        self.device_id = device_id
        self.d = None
        self._connect_device()

    def _connect_device(self):
        """通过ADB连接真机/模拟器"""
        try:
            self.d = u2.connect(self.device_id) if self.device_id else u2.connect()
            logger.info(f"✅ 设备连接成功!序列号: {self.d.serial}")
        except Exception as e:
            logger.error(f"❌ 设备连接失败,请检查USB调试是否开启!错误: {e}")
            raise

    def launch_douyin(self):
        """启动抖音并冷启动等待(模拟真人打开APP的加载时间)"""
        self.d.app_start("com.ss.android.ugc.aweme", stop=True)
        time.sleep(random.uniform(7, 12))  # 冷启动别等太短!
        logger.info("✅ 抖音已启动并进入首页")

    def _swipe_to_next_video(self):
        """真人化向上滑动!别用固定坐标固定时长!"""
        w, h = self.d.window_size()
        # 滑动起点/终点随机偏移一点,时长也随机
        start_x = w // 2 + random.randint(-50, 50)
        start_y = h * 4 // 5 + random.randint(-30, 30)
        end_x = w // 2 + random.randint(-30, 30)
        end_y = h // 5 + random.randint(-30, 30)
        duration = random.uniform(0.5, 0.9)
        self.d.swipe(start_x, start_y, end_x, end_y, duration=duration)
        # 模拟观看视频的时间
        watch_time = random.uniform(self.config.min_watch_sec, self.config.max_watch_sec)
        logger.info(f"👀 观看下一个视频,停留{watch_time:.1f}秒")
        time.sleep(watch_time)

    def _click_like_btn(self, mock_aweme_id: str):
        """固定坐标点赞(演示用)"""
        w, h = self.d.window_size()
        # 点赞按钮一般在屏幕右侧中间偏上,随机偏移
        x = w * 4 // 5 + random.randint(-20, 20)
        y = h // 2 + 80 + random.randint(-15, 15)
        self.d.click(x, y)
        time.sleep(random.uniform(0.2, 0.4))
        self.db.save_interaction(mock_aweme_id, ActionType.LIKE.value)
        logger.info("❤️ 点赞成功")

    def run_single_session(self, max_videos: int = 15):
        """运行单个会话:刷指定数量的视频(新手别刷太多!)"""
        if not self.d:
            raise RuntimeError("请先连接设备!")
        
        # 先检查今日互动上限
        today_count = self.db.get_today_action_count()
        if today_count >= self.config.daily_max_actions:
            logger.warning(f"⚠️ 今日已互动{today_count}次,已达上限!")
            return
        
        self.launch_douyin()
        
        for i in range(max_videos):
            # 每次循环前再检查一次,防止刚好刷到一半到上限
            today_count = self.db.get_today_action_count()
            if today_count >= self.config.daily_max_actions:
                logger.warning(f"⚠️ 会话中途已达今日互动上限{today_count}次!")
                break
            
            # 模拟aweme_id(实际可以通过元素提取/OCR截图识别视频左上角的分享链接解析)
            mock_aweme_id = f"mock_{int(time.time())}_{i}"
            
            # 先滑动到下一个视频
            self._swipe_to_next_video()
            
            # 随机执行互动
            rand_num = random.random()
            if rand_num < self.config.like_prob:
                self._click_like_btn(mock_aweme_id)
            elif rand_num < self.config.like_prob + self.config.comment_prob:
                # 评论逻辑类似点赞,省略了点击评论框、输入文字、发送的固定坐标代码
                # 新手可以自己补:先点击右侧评论按钮,再点击输入框,用d.send_keys()发随机评论
                self.db.save_interaction(mock_aweme_id, ActionType.COMMENT.value)
                logger.info("💬 模拟评论成功")
        
        logger.info("✅ 单个会话结束")

关键防封策略(新手必须看!)

虽然代码里已经加了每日上限、随机滑动/等待,但要进一步降低封号风险,还要加这些贴近真实用户习惯的细节:

  1. 不要挂机刷一整天!:每天只在1-2个固定的休闲时段运行(比如19:00-20:30、22:00-22:40),单次会话不要超过30分钟
  2. 动作组合要随机!:不要每次只点赞,偶尔可以只看视频不互动、偶尔点赞后评论、偶尔评论后取消点赞
  3. 不要用纯模拟器!:模拟器的设备指纹太统一,用闲置的安卓旧手机最安全
  4. 不要用同一WiFi连多个账号!:如果有多个账号,建议用不同的WiFi/手机卡
  5. 评论语要更个性化!:可以加一点和视频内容相关的词(比如如果是美食视频,可以加“看起来好好吃!”“收藏食谱了”),当然这需要结合OCR识别视频内容

快速开始

  1. 新建一个文件夹,把上面的三个代码块合并成一个 douyin_bot.py 文件
  2. 新建一个 requirements.txt 文件,填入以下内容:
uiautomator2>=2.16.22
  1. 安装依赖:
pip install -r requirements.txt
  1. 验证设备连接:
adb devices
  1. 运行程序:
python douyin_bot.py

总结

本项目提供了一个入门门槛低、有防封基础、模块化设计的抖音UI自动化框架,核心价值在于学习:

  • uiautomator2原生UI框架的使用
  • Python项目的模块化设计
  • 基础的防封逻辑思路

再次强调:本项目仅用于技术学习,切勿用于任何商业或违规用途! 完整的项目代码(含Airtest图像匹配、定时调度、Docker部署脚本)可以根据需求自行整理扩展。