두 팀이 비슷한 제품을 다룬 동영상을 올리지만, 각자 서로 다른 기준으로 수동 평가합니다. 한 팀은 조회수를 기억하고, 다른 팀은 댓글을 살피며, 또 다른 팀은 채팅방에 링크를 저장합니다. 일주일만 지나도 경쟁사에서 어떤 형식이 반복되는지, 어떤 게시물이 눈에 띄는 반응을 얻는지, 지난번 확인 이후 무엇이 달라졌는지 파악하기 어려워집니다.
해결책은 미리 정한 키워드로 공개 동영상을 제한적이고 재현 가능한 방식으로 수집하고, 원본 JSON을 보존한 다음 일관된 필드로 표를 만드는 것입니다. 이렇게 하면 우연히 마주친 관찰과 시장에 대한 결론을 뒤섞지 않고, 하나의 작업 흐름 안에서 동영상을 비교할 수 있습니다. 아래에서는 jsonscraper의 TikTok Scraper API를 이용해 Python으로 소규모 경쟁사 모니터링을 구성하는 방법을 소개합니다.
먼저 분석 질문을 정하세요
데이터 수집은 결과를 바탕으로 어떤 결정을 내릴지 미리 알고 있을 때 유용합니다. 예를 들어 스포츠 물병 제조사의 마케팅팀은 경쟁사들이 짧은 동영상에서 제품을 어떻게 보여주는지 알고 싶을 수 있습니다. 사용 장면 시연, 언박싱, 비교, 사용자 반응 중 어떤 방식인지 확인하려는 것입니다. TikTok 전체를 복사할 필요는 없습니다. API가 해당 검색어로 반환하는 동영상을 살펴보기 위해 몇 가지 목표 검색어를 정하고 반복해서 관찰하면 됩니다.
검증할 수 있도록 질문을 구체적으로 정리하세요. 예를 들어 “선정한 5개 핵심 문구로 검색했을 때 게시된 동영상에서 어떤 설명 및 시연 형식이 나타나며, 검색된 영상 중 현재 조회수와 반응이 가장 높은 것은 무엇인가?”라고 물을 수 있습니다. 이렇게 하면 분석의 두 층위가 분리됩니다. 텍스트와 설명은 크리에이티브 접근 방식을 분류하는 데 도움이 되고, 조회수·좋아요·댓글·공유 수는 수집 시점의 공개 반응을 보여줍니다.
이 스냅샷은 수동 검토의 우선순위를 정하고 변화를 추적하는 데 유용합니다. 다만 특정 검색어와 매개변수, 실행 시점에 반환된 동영상만을 설명합니다. 따라서 “우리 표본에서는 언박싱이 자주 보인다” 또는 “이 동영상 그룹의 현재 조회수 중앙값이 더 높다”와 같은 결론이 적절합니다. 이 정도 범위의 분석은 팀이 자체 콘텐츠 아이디어를 선택하는 데 도움이 됩니다.
소규모 데이터 파이프라인 설계하기
작업을 수집, 원본 응답 저장, 정규화, 분석의 네 단계로 나누세요. 수집 단계에서는 승인된 각 키워드로 API를 호출합니다. 원본 응답은 나중에 다시 확인할 수 있도록 전체를 저장합니다. 정규화 단계에서는 중첩된 JSON 구조를 표의 행으로 바꾸고, 분석 단계에서는 지표를 계산해 키워드나 수동으로 지정한 형식별로 동영상을 그룹화합니다.
- 수집. 각 키워드에 대해 동일한 지역과 정렬 기준으로 정해진 수의 결과를 요청합니다.
- 보관. 추출한 값을 확인할 수 있도록 원본 JSON과 수집 시각을 기록합니다.
- 정규화. 동영상 ID, 링크, 설명, 작성자, 게시 시각, 제공되는 카운터를 남깁니다.
- 품질 관리. ID 기준으로 중복을 제거하고 누락된 값을 표시하며, 해당 동영상을 찾은 키워드를 기록합니다.
- 비교. 제공된 원본 필드만으로 자체 지표를 계산하고 동일한 스냅샷 안에서 그룹을 비교합니다.
이 방식은 단순히 링크만 모아 두는 것보다 낫습니다. 각 행의 출처를 보존해 같은 동영상이 다시 나타난 경우와 새로운 콘텐츠를 구분할 수 있기 때문입니다. 수집 날짜도 저장하세요. 공개 카운터는 바뀔 수 있으므로 오늘 받은 값을 동영상의 고정된 특성으로 해석해서는 안 됩니다.
TikTok Scraper API가 지원하는 기능
텍스트 검색으로 동영상을 찾는 방법에 대해 jsonscraper 문서는 기본 주소 https://tiktok.evelode.com의 GET 경로 /searchVideo를 설명합니다. 필수 매개변수는 keyword이며, count, cursor, region, date_posted, sort_by, cache_timeout도 사용할 수 있습니다. 문서에는 most-liked, relevance, date-posted 정렬 옵션과 yesterday, this-week, this-month, last-3-months, last-6-months, all-time 게시 기간이 나와 있습니다. 매개변수 이름과 용도는 TikTok 엔드포인트 레퍼런스에서 확인하세요.
라이선스 키는 쿼리 매개변수 license_key로 전달합니다. 실제 스크립트에서는 키를 소스 파일, 표, 실행 로그에 넣지 말고 JSONSCRAPER_TIKTOK_LICENSE_KEY 환경 변수에 저장하세요. 응답의 최상위 status를 확인한 뒤 tiktok 객체를 파싱합니다. 검색 결과 구조에는 aweme_list 목록과 동영상 정보가 aweme_info 안에 들어 있는 search_item_list가 포함될 수 있습니다. 아래 코드는 두 구조를 모두 처리합니다.
확인된 검색 응답에는 동영상 ID, 설명, 게시 시각, 링크, 작성자 정보와 조회수·좋아요·댓글·저장·공유 수 같은 지표가 포함됩니다. 개별 레코드에서 일부 필드가 빠질 수도 있습니다. 이 경우 표에서는 해당 값을 0으로 바꾸지 말고 비워 두세요. 0은 측정된 값이고, 빈칸은 받은 객체에 값이 없었다는 뜻입니다.
Python 최소 예제
아래 스크립트는 각 키워드에 대해 한 번씩 요청하고, 전체 응답을 JSON 파일로 저장한 뒤 스프레드시트나 후속 처리에 사용할 CSV를 만듭니다. Python 3.8 이상을 대상으로 하며 표준 라이브러리만 사용합니다. 실행 전에 라이선스가 담긴 환경 변수를 설정하세요. 사용 사례에 맞게 키워드 목록과 결과 수를 조정합니다.
import csv
import json
import os
import time
from datetime import datetime, timezone
from pathlib import Path
from urllib.parse import urlencode
from urllib.request import urlopen
BASE_URL = "https://tiktok.evelode.com/searchVideo"
LICENSE_KEY = os.environ["JSONSCRAPER_TIKTOK_LICENSE_KEY"]
KEYWORDS = ["보온병", "스포츠 물병", "물병 언박싱"]
REGION = "US"
COUNT = 20
def request_search(keyword):
params = {
"license_key": LICENSE_KEY,
"keyword": keyword,
"count": COUNT,
"region": REGION,
"sort_by": "relevance",
"date_posted": "this-month",
}
url = BASE_URL + "?" + urlencode(params)
with urlopen(url, timeout=60) as response:
return json.loads(response.read().decode("utf-8"))
def extract_videos(payload):
if payload.get("status") != "ok":
raise RuntimeError("API returned a non-ok status")
tiktok = payload.get("tiktok") or {}
rows = []
for item in tiktok.get("aweme_list") or []:
if isinstance(item, dict):
rows.append(item)
for item in tiktok.get("search_item_list") or []:
video = item.get("aweme_info") if isinstance(item, dict) else None
if isinstance(video, dict):
rows.append(video)
return rows, tiktok
Path("raw").mkdir(exist_ok=True)
seen = set()
records = []
for keyword in KEYWORDS:
payload = request_search(keyword)
collected_at = datetime.now(timezone.utc).isoformat()
safe_name = keyword.replace(" ", "_")
raw_path = Path("raw") / (safe_name + ".json")
raw_path.write_text(json.dumps(payload, ensure_ascii=False, indent=2), encoding="utf-8")
videos, tiktok = extract_videos(payload)
for video in videos:
video_id = video.get("aweme_id")
if not video_id:
continue
dedupe_key = (keyword, video_id)
if dedupe_key in seen:
continue
seen.add(dedupe_key)
stats = video.get("statistics") or {}
author = video.get("author") or {}
records.append({
"collected_at": collected_at,
"keyword": keyword,
"video_id": video_id,
"url": video.get("share_url"),
"created_at_epoch": video.get("create_time"),
"description": video.get("desc"),
"author": author.get("nickname"),
"username": author.get("unique_id"),
"views": stats.get("play_count"),
"likes": stats.get("digg_count"),
"comments": stats.get("comment_count"),
"shares": stats.get("share_count"),
"saves": stats.get("collect_count"),
"cursor": tiktok.get("cursor"),
})
time.sleep(1)
fieldnames = [
"collected_at", "keyword", "video_id", "url", "created_at_epoch",
"description", "author", "username", "views", "likes", "comments",
"shares", "saves", "cursor",
]
with open("tiktok_creatives.csv", "w", newline="", encoding="utf-8") as output:
writer = csv.DictWriter(output, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(records)
print("Saved", len(records), "video rows to tiktok_creatives.csv")
스크립트는 동영상과 함께 키워드도 저장합니다. 한 동영상이 여러 검색어로 발견될 수 있기 때문에 중요합니다. 여기서는 각 키워드 안에서 중복을 제거하므로, 같은 ID가 서로 다른 검색어에 대해 별도의 행을 차지할 수 있습니다. 중복 없는 단일 표를 원한다면 (keyword, video_id) 키를 video_id로 바꾸고, 키워드는 목록이나 별도의 연결 테이블에 누적하세요.
이 코드는 의도적으로 단어마다 한 번만 요청하며 페이지를 자동으로 넘기지 않습니다. 다음 페이지가 필요한 경우 문서에서는 cursor를 이전 응답에서 얻는 결과 조회용 값으로 정의합니다. 이를 불투명한 값으로 취급하고 직접 계산하지 마세요. 실제 작업에서는 테스트 응답으로 페이지네이션 구조를 확인한 뒤, 새 결과나 다음 커서가 없을 때 중단하세요.
비교 가능한 표 만들기
CSV는 스프레드시트에서 열거나 데이터베이스에 적재하거나, Python에서 집계 계산에 사용할 수 있습니다. 첫 보고서에서는 수집 날짜, 키워드, 동영상 형식별로 행을 그룹화하세요. 설명과 동영상 자체를 검토한 뒤 형식을 분류하는 것이 좋습니다. 예를 들면 ‘시연’, ‘언박싱’, ‘후기’, ‘비교’가 있습니다. 소규모 표본은 수동으로 분류하거나, 모델에 초안 분류를 맡긴 다음 사람이 검토할 수 있습니다.
텍스트 분류를 자동화한다면 설명과 ID처럼 필요한 필드만 모델에 전달하고, 미리 승인한 목록에서 하나의 라벨을 반환하도록 요청하세요. 원본 설명은 분류 결과와 별도로 보관합니다. 그러면 분석가가 논란이 있는 라벨을 확인하고 분류 체계가 바뀐 뒤 보고서를 다시 계산할 수 있으며, API를 다시 호출할 필요가 없습니다.
비교 지표를 계산할 때는 동일한 수집 시점의 값을 사용하세요. 예를 들어 두 필드가 모두 있고 조회수가 0보다 클 때 likes / views로 좋아요 대 조회수 비율을 계산할 수 있습니다. 댓글이나 공유 비율도 비슷하게 계산할 수 있습니다. 이러한 비율은 해당 동영상의 현재 공개 카운터를 설명할 뿐, 특정 시청자의 도달 범위나 시청 완료율, 전환율을 측정하지는 않습니다. 비즈니스 결정을 내릴 때는 이를 자체 캠페인과 비교하고, 다른 형식을 따라 했을 때의 보장된 성과가 아니라 아이디어를 고르는 참고 자료로 활용하세요.
표본에 규모가 매우 큰 동영상이 몇 개 포함되어 있다면 평균보다 중앙값이 더 유용할 수 있습니다. 동일한 수집 규칙, 즉 같은 검색어 집합·지역·기간 필터와 비슷한 스냅샷 시점을 적용한 경우에만 그룹별 조회수 및 반응 중앙값을 비교하세요. 실행 매개변수를 날짜와 함께 기록합니다. 검색 방식이나 표본이 달라지면 행 구성이 바뀌므로, 두 보고서의 차이는 방법의 변화도 반영할 수 있습니다.
재실행 및 변화 관리
일회성 분석을 모니터링으로 전환하려면 스크립트를 예를 들어 매일 또는 매주 일정에 따라 실행하고 각 레코드에 수집 날짜를 추가하세요. 동영상마다 ‘스냅샷 시각—카운터 값’ 쌍을 저장하면 각 측정 지점을 별도로 보존하면서 관찰 사이에 공개 지표가 어떻게 바뀌었는지 확인할 수 있습니다. 이전 카운터를 최신 값으로 덮어쓰지 마세요. 그러면 변화 추이가 사라집니다.
운영 환경에서는 로컬 폴더의 원본 JSON을 객체 스토리지나 다른 보관 시스템으로 옮기고, 정규화된 행은 동영상 ID와 수집 시각의 조합처럼 고유한 키를 가진 데이터베이스에 저장하세요. 비밀 키를 포함하지 않는 오류 로그, 재시도 횟수 제한, 요청 실패 알림을 추가합니다. 일시적인 오류는 지연 후 재시도할 수 있습니다. 구조적 오류가 발생하면 응답을 저장하고 확인이 필요한 실행으로 표시하는 편이 좋습니다. 그래야 실패가 조용히 빈 보고서로 바뀌지 않습니다.
cursor를 연구의 영구 식별자로 사용하지 마세요. 이는 결과 조회를 이어 가기 위한 마커입니다. 해당 요청의 매개변수와 함께 저장하고, 그 조회를 이어 갈 때만 사용하며, 서로 다른 키워드의 페이지를 섞지 마세요. 실제 처리된 결과 수도 기록합니다. 요청한 count 값은 원하는 응답 크기를 지정할 뿐, 조건에 맞는 모든 게시물을 빠짐없이 가져온다는 보장은 아닙니다.
작업 흐름 확장하기
검색 표본에 잡음이 너무 많다면 공개 프로필이나 해시태그를 별도로 추적할 수 있습니다. 문서에는 쿼리 및 페이지네이션 매개변수를 사용하는 /getUserFeed와 /getHashtagFeed 경로가 있습니다. 이 경로들은 각자 다른 규칙을 따르는 별도 표본입니다. 프로필 피드에는 max_cursor, 해시태그에는 cursor가 사용됩니다. 이 경로를 별도 데이터 소스로 추가하고 소스 유형과 매개변수를 저장해 키워드 검색 결과와 프로필 또는 해시태그 게시물이 섞이지 않도록 하세요.
자체 인프라가 없는 팀은 CSV를 Google Sheets API를 통해 Google Sheets로 전송할 수 있습니다. Google Sheets API 문서에서는 셀 값 읽기와 쓰기를 설명합니다. 원본 실행 내역, 정규화된 동영상, 요약을 각각 별도의 시트에 두세요. 공동 분류 작업에 편리하며, 기록량이 표에서 다루기 어려워지면 동일한 필드와 데이터 출처를 유지한 채 SQL 저장소로 옮기면 됩니다.
AI 에이전트는 이미 수집하고 정규화한 레코드를 간략히 요약하는 역할을 맡기는 것이 합리적입니다. 설명을 그룹화하고, 형식을 제안하며, 특이한 값을 표시하도록 할 수 있습니다. 작은 검색 결과만으로 플랫폼 전체에 관한 사실을 만들도록 해서는 안 됩니다. 기간, 검색어 목록, 행 수를 함께 전달하고, 동영상 ID를 근거로 제시하며, 불확실하거나 누락된 필드는 빈 값으로 반환하도록 요청하세요. 그런 다음 분석가가 저장된 링크를 통해 사례를 확인합니다.
최종 결과
설정을 마치면 팀은 검색된 동영상의 ID, 링크, 설명, 작성자, 게시 시각, 제공되는 공개 카운터를 포함한 재현 가능한 목록을 얻게 됩니다. 저장된 원본 응답으로 변환 과정을 다시 확인할 수 있고, CSV를 이용해 동영상을 빠르게 정렬하거나 키워드로 필터링하고 날짜별 스냅샷을 비교할 수 있습니다. 이를 바탕으로 반복해서 나타난 형식, 검토할 만한 게시물, 자체 콘텐츠에서 시험해 볼 크리에이티브 가설을 정리한 주간 요약을 만들 수 있습니다.
실질적인 결과는 경쟁사 전체를 대상으로 하는 보편적 순위가 아니라, 출처가 명확한 체계적 표본입니다. 표본의 품질은 검색어, 필터, 관찰 기간에 따라 달라집니다. 따라서 수집 매개변수를 보관하고, 개별 동영상을 직접 확인하며, 이용 가능한 지표와 해석을 구분하세요. 이 과정을 통해 흩어진 북마크를 비교 가능한 데이터로 바꾸고 구체적인 사례를 바탕으로 크리에이티브를 논의할 수 있습니다.
검색 경로와 매개변수는 jsonscraper 공식 문서에서 확인할 수 있으며, 서비스 설명과 이용 방법은 TikTok Scraper API 페이지에 나와 있습니다. 몇 가지 검색 문구로 시작해 테스트 응답 하나를 저장하고, 예약 실행을 설정하기 전에 구조를 확인하세요.