Export Douyin comments to Excel with Python

Pull every comment on a Douyin video and the replies under them through an API, deduplicate them and save a CSV that opens cleanly in Excel. Full Python code.

DouyinUpdated

Douyin (抖音), the Chinese version of TikTok, puts some of the most candid product feedback in China into its comment sections. This guide pulls every comment on one video, and the replies under them, into a file you can open in Excel. There is no packet capture, no cookies and no account to log in with.

How it works

Douyin's open platform is for approved apps acting with their users' permission. It does not hand out the comments on any video. Qovia's Douyin endpoints do, as plain HTTPS calls with an API key. You need:

  • Python 3.8 or later and requests: pip install requests.
  • A Qovia API key from the console, in an environment variable:
Shell
export QOVIA_KEY="sk-qovia-..."

Step 1: find the video ID

The video ID (Douyin calls it aweme_id) is the long number in a video link: douyin.com/video/<video ID>. A share link (v.douyin.com/...) redirects to an address with the same number in it; open it in a browser and copy the number.

Check that you have the right video with video detail:

Python
import os
import requests

API = "https://api.qovia.ai/v1/raw/douyin"
HEADERS = {"Authorization": f"Bearer {os.environ['QOVIA_KEY']}"}


def call(endpoint, **params):
    resp = requests.get(f"{API}/{endpoint}", headers=HEADERS, params=params, timeout=60)
    if not resp.ok:
        raise RuntimeError(f"{endpoint}: HTTP {resp.status_code} {resp.text[:300]}")
    return resp.json()["data"] or {}


VIDEO = "7681194457378688292"
video = call("video", item_id=VIDEO)
print(video["text"][:80], video["metrics"])

Step 2: page through the comments

Video comments returns up to 50 comments a page. Pass each page's cursor back to get the next one, and stop when has_more is false. Douyin can reorder comments between pages, so neighbouring pages may repeat a comment: keep them in a dict keyed by cid and the duplicates disappear.

Python
def all_comments(item_id, max_pages=40):
    comments, cursor = {}, 0
    for _ in range(max_pages):
        page = call("comments", item_id=item_id, cursor=cursor, count=50)
        for c in page.get("items", []):
            comments[c["cid"]] = c
        if not page.get("has_more"):
            break
        cursor = page["cursor"]
    return list(comments.values())


comments = all_comments(VIDEO)
print(len(comments), "comments")

Each comment has cid, text, likes, reply_count, ip_location, created_at, is_hot and the author's nickname.

Step 3: add the replies

Replies to a comment (the threads under it) come from comment replies, paged the same way. Each call is charged, so fetch replies only where they matter, for example the comments with the most replies:

Python
def replies(item_id, comment_id, max_pages=10):
    out, cursor = [], 0
    for _ in range(max_pages):
        page = call("comment_replies", item_id=item_id, comment_id=comment_id, cursor=cursor, count=50)
        out += page.get("items", [])
        if not page.get("has_more"):
            break
        cursor = page["cursor"]
    return out


busiest = sorted(comments, key=lambda c: c["reply_count"], reverse=True)[:20]
reply_rows = []
for c in busiest:
    if c["reply_count"]:
        for r in replies(VIDEO, c["cid"]):
            r["parent"] = c["cid"]
            reply_rows.append(r)

Step 4: export for Excel

A CSV written as utf-8-sig opens in Excel with the Chinese text intact. One sheet holds the comments and the replies; parent is empty for top-level comments.

Python
import csv

with open("douyin_comments.csv", "w", newline="", encoding="utf-8-sig") as f:
    writer = csv.writer(f)
    writer.writerow(["cid", "parent", "created_at", "likes", "replies", "ip_location", "nickname", "text"])
    for c in comments + reply_rows:
        writer.writerow([
            c["cid"], c.get("parent", ""), c["created_at"], c["likes"], c.get("reply_count", 0),
            c["ip_location"], c["author"]["nickname"], c["text"],
        ])

Prefer a real .xlsx? With pandas and openpyxl installed, pandas.DataFrame(comments + reply_rows).to_excel("comments.xlsx", index=False) does it in one line.

Costs and limits

  • Each call that returns data is charged once at the endpoint's price (see pricing). Empty pages, errors and timeouts are not charged, and every response says what it cost in meta.charged_usd.
  • max_pages keeps a run's cost predictable; raise it for videos with tens of thousands of comments.
  • Too many requests in a minute gets a 429 with a Retry-After header: wait that long and retry.

Next

Endpoints in this guide

More guides

Your agent only knows what you give it

Give it Douyin, Xiaohongshu (RedNote), WeChat and product reviews: structured, per call, nothing charged for failures.