Douyin automatic likes and comments crawler project

If you get tired of watching videos, or want to learn how to use code to control the interface of a real mobile app, this article is for you. We will start from scratch, using a real Android phone, a data cable, and a few Python codes to build a scalable, anti-blocking logic, and built-in local data recording Douyin automation framework.

But before touching the keyboard, the most serious warning must be placed here.

⚠️ Fatal Warning This project** is only used to learn UI automation technology and Python project architecture design**. The automated like, comment, and follow operations of short video platforms such as Douyin directly violate their "User Agreement", "Community Standards" and even some laws and regulations**. If you use the code for any commercial or illegal purposes, your account may be permanently banned, your device IP may be restricted, and you may even face legal liability**. **Please do not take the law personally. All consequences are borne by the user. **


Why choose this solution?

Many friends who are new to automation will think of two common approaches:

  • Simulator + Group Control Script The advantage is that it can be operated in batches, but the device fingerprints (IMEI, MAC, CPU model, etc.) of the simulator are highly unified, and Douyin’s risk control system can identify them at a glance.
  • Packet Capture/Crack API Need researchX-GorgonX-LadonA-BogusThe maintenance cost is extremely high due to the ever-changing encryption algorithms, and even slightly frequent API calls will trigger risk control.

We chose the third route for this project: Use uiautomator2 to directly drive the native interface on a real Android phone. There are three major benefits to doing this:

  • ✅ No need to root or jailbreak, just any idle Android machine, the device fingerprint is completely authentic.
  • ✅ All operations simulate a real person's "swipe → stay → click → enter", and the behavioral characteristics are extremely difficult to identify as scripts.
  • ✅ All written in Python, the logic is clear, easy to modify and expand, and it is very convenient to add OCR recognition and scheduled tasks later.

Project structure: five modules to handle everything

The entire system is designed to be very streamlined. Even if you have just learned Python, you can still understand the relationship between each part.

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

We only need to focus on three core modules:

  • ActionConfig: Centrally manage parameters such as like probability, daily upper limit, and comments. Subsequent parameter adjustments only need to be changed in one place.
  • DatabaseManager: Use SQLite to record how many times you interacted today and which videos you interacted with, to prevent overshooting or repeated operations.
  • DouyinAutoBot: Communicate with the mobile phone through uiautomator2 to perform all sliding, clicking, and input actions.

From preparation to run-through: complete code disassembly

0. Preparation: Let the computer control the mobile phone

Before you start writing code, make sure the device can connect properly:

  1. Open the Developer Options of your phone, find USB Debugging and USB Installation, and turn them on. (Different brands have different entrances. Searching for "Developer Options" directly in the settings is the fastest.)
  2. Install the ADB driver on your computer.
  • Windows 10/11 is usually installed automatically after plugging in the USB;
  • macOS/Linux via Android Studio toolkit or directlybrew install android-platform-tools / apt install adbInstall.
  1. Connect the mobile phone with a data cable and enter in the terminal/command line:
adb devices

If you see something likeemulator-5554(emulator) or12345678The output of (real mobile phone) indicates that the connection is successful.

1. Configuration center: extract all changed parameters

Hard-coded numbers can make adjustments later very painful. We use PythondataclassCentrally manage probability, duration, and comment text.

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 写配置
@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. Data steward: Use SQLite to record every interaction

Recording interactions is not a “frills extra”. With it, you can check at any time how many operations have been performed today and whether it has exceeded the threshold. It can also be used for subsequent analysis of why it was risk controlled.

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,
                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. Control the mobile phone: Use uiautomator2 to simulate real-person operation

This is the most important part of the entire project. In order to avoid being recognized as a script by the platform, all swipes, clicks, and waiting times must be added with random offsets.

💡 In actual development, it is recommended to use Airtest image template matching or uiautomator2's text/desc positioning to replace fixed coordinates. However, Douyin's interface element IDs often change, and fixed coordinate demonstrations are more convenient to understand.

import uiautomator2 as u2
import random
import time
from typing import Optional

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 获取真实 ID
            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:
                # 评论逻辑:先点评论按钮 -> 点输入框 -> 输入随机文本 -> 点发送
                # 这里只记录一次模拟评论,具体点击坐标可根据你的设备调整
                self.db.save_interaction(mock_aweme_id, ActionType.COMMENT.value)
                logger.info("💬 模拟评论成功")
            # 其余情况只看视频,不做互动

        logger.info("✅ 单个会话结束")

Anti-blocking strategy: Don’t let the platform target you

Basic protections such as daily upper limit, random sliding, and random waiting have been added to the code, but if you want to be more secure, you have to work on your usage habits:

  1. Control usage period It only runs during 12 fixed leisure periods every day, such as 19:0020:30, 22:00~22:40 in the evening, and a single session does not exceed 30 minutes. Never run 24 hours a day.

  2. Diversified action combinations Don't like every time. You can occasionally just watch the interaction, occasionally like and then add comments, or even simulate a "like and then cancel" operation to make the behavior look more like real users.

  3. Hardware selection is important The device fingerprints of the simulator are highly unified, and the secret will be revealed as soon as the risk control checks. The safest thing is to use an old idle Android phone, each one has an independent fingerprint.

  4. Do not reuse network environments Do not connect multiple accounts to the same WiFi. Try to use different IPs or even different mobile phone cards to spread the risk.

  5. Comment content should be "Watch the video and then cook" If comments can be combined with video content, the authenticity will be greatly improved. For example, if you identify food keywords through OCR, you can post "It looks delicious" and "Favourite the recipe." This is an advanced gameplay, but it can take the anti-blocking ability to another two levels.


Run quickly

  1. Combine the above three code blocks into onedouyin_bot.pydocument.
  2. Create a new onerequirements.txt, write:
uiautomator2>=2.16.22
  1. Install dependencies:
pip install -r requirements.txt
  1. Verify after connecting to the mobile phone:
adb devices
  1. Start the program:
python douyin_bot.py

Summarize

This article takes you through a low threshold, modular, and built-in anti-blocking logic Douyin UI automation framework. You can learn:

  • How uiautomator2 controls a real phone
  • How to use dataclass and SQLite to build maintainable configuration and data layers
  • Basic anti-sealing design ideas in real projects

Again: **This project is only for technical learning and should not be used in any production environment or violation scenarios. ** If you want more stable image recognition positioning, Docker scheduled deployment and other advanced functions, you can continue to expand based on this framework.

I hope this tutorial can help you open the door to Android UI automation.