בחיפוש סרטונים ב-TikTok דרך API, ייתכן שהסרטונים לא יופיעו במערך שהמעבד מצפה למצוא תחילה. בתשובת jsonscraper שנבדקה לבקשה אל `/searchVideo`, השדה `aweme_list` היה ריק, ואילו פריטי הנתונים של הסרטונים נמצאו ב-`search_item_list[].aweme_info`. אם הקוד קורא רק את `aweme_list`, הוא ישמור אפס סרטונים, אף שהתשובה מכילה סרטונים שנמצאו. עבור מפתחים, זהו אתגר אמינות ממוקד: לחלץ את שתי צורות הנתונים ולנרמל אותן לרשימה אחידה לפני כתיבה למסד נתונים או העברה לדוח.
![מאמר: איך לא לאבד תוצאות חיפוש של TikTok בעת ניתוח JSON
תקציר: מדריך מעשי לחיפוש ב-TikTok: נקודת הקצה `/searchVideo` עשויה להחזיר `aweme_list` ריק, בעוד הסרטונים שנמצאו מופיעים ב-`search_item_list[].aweme_info`. מדגימים נרמול של שתי התבניות ב-Python, כולל מניעת כפילויות לפי מזהה.
תפקיד התמונה: תמונת שער — הרעיון המרכזי
מקטע: איך לא לאבד תוצאות חיפוש של TikTok בעת ניתוח JSON
נושא חזותי: צילום מערכת הממחיש נרמול JSON של TikTok API: שני זרמי נתונים נפרדים](/assets/uploads/journal/2026/11/3f9ca6f48040b3044b8190c9a7b7a847.png.hero.webp)
אפשר לעיין בבדיקה של דוגמה חיה ובתיאור הנתיב במפרט ה-API של jsonscraper ובתיעוד נקודת הקצה של TikTok. תמונת המצב של הסכמה במפרט מתוארכת ל-25 באוקטובר 2026; היא מדגימה את המבנה של תשובה מסוימת ואינה מבטיחה שכל שדה יופיע בכל בקשה עתידית.
למה המנתח עלול להחזיר רשימה ריקה
הנתיב `GET https://tiktok.evelode.com/searchVideo` מחפש סרטונים לפי הפרמטר החובה `keyword`. בתיעוד מפורטים גם `cursor`, `count`, `cache_timeout`, `date_posted`, `sort_by` ו-`region`. בסכמת התשובה שנצפתה, האובייקט העליון מכיל את `status` ואובייקט מקונן בשם `tiktok`; בתוכו נמצאים `cursor`, `has_more`, `status_code`, `aweme_list` ו-`search_item_list`.
בבדיקה מסוימת, בבקשה עם מילת מפתח ו-`count=3`, המערך `aweme_list` היה ריק. במקביל, `search_item_list` כלל פריטים שבהם פרטי הסרטון נמצאו ב-`aweme_info`. האובייקטים האלה עשויים לכלול מזהה סרטון, כיתוב, כתובת URL של הפרסום, מחבר ונתונים סטטיסטיים, למשל מספר צפיות, סימוני אהבתי או תגובות. השדות המתוארים משקפים את הסכמה שנצפתה; על המעבד בכל זאת להיות מסוגל להתמודד עם ערכים חסרים.
המסקנה המעשית היא שבקשת HTTP מוצלחת ומערך לא ריק בשדה יחיד שהמעבד ציפה לו הם שתי בדיקות שונות. תחילה בדקו את הסטטוס החיצוני ואת קיומו של `tiktok`, ואז אספו סרטונים מכל אחד מהמקומות המתועדים. לצורכי ניתוח, שמרו את המזהים ואת התשובה המקורית: כך אפשר לעקוב אחר האופן שבו רשומה מסוימת חולצה ונורמלה.
נרמלו את התשובה לפני שמירתה באחסון
גבול נוח בין ה-API למערכת שלכם הוא פונקציה שמקבלת את האובייקט המקונן `tiktok` ומחזירה פריטים במבנה אחיד. עליה לעבד את שני המערכים, לדלג על פריטים ריקים או שאינם מילונים, ולמנוע כפילות של סרטון לפי `aweme_id`. השאירו מונים ריקים כשהספק לא החזיר אותם: אפס מציין ערך שנמדד, ואילו `None` מעיד שהשדה חסר.
להלן דוגמה מינימלית ל-Python 3.8 ומעלה. היא שולחת בקשה אחת, בודקת את סטטוס התעבורה ואת הסטטוס העליון, מנרמלת את שתי צורות התוצאה ומדפיסה את השדות שנבחרו. המפתח נקרא ממשתנה סביבה ואינו נכתב ליומן.
import os
import requests
BASE_URL = "https://tiktok.evelode.com"
def extract_videos(tiktok):
candidates = []
aweme_list = tiktok.get("aweme_list") or []
if isinstance(aweme_list, list):
candidates.extend(aweme_list)
search_items = tiktok.get("search_item_list") or []
if isinstance(search_items, list):
for item in search_items:
if isinstance(item, dict):
candidates.append(item.get("aweme_info"))
unique = {}
for video in candidates:
if not isinstance(video, dict):
continue
video_id = video.get("aweme_id")
if video_id:
unique[video_id] = video
return list(unique.values())
license_key = os.environ["JSONSCRAPER_TIKTOK_LICENSE_KEY"]
response = requests.get(
BASE_URL + "/searchVideo",
params={
"license_key": license_key,
"keyword": "python tutorial",
"count": 10,
"region": "US",
},
timeout=30,
)
response.raise_for_status()
payload = response.json()
if payload.get("status") != "ok":
raise RuntimeError("TikTok API returned a non-ok status")
tiktok = payload.get("tiktok")
if not isinstance(tiktok, dict):
raise RuntimeError("Response has no tiktok object")
for video in extract_videos(tiktok):
stats = video.get("statistics") or {}
author = video.get("author") or {}
print({
"aweme_id": video.get("aweme_id"),
"desc": video.get("desc"),
"share_url": video.get("share_url"),
"author": author.get("unique_id"),
"play_count": stats.get("play_count"),
"digg_count": stats.get("digg_count"),
"comment_count": stats.get("comment_count"),
})
התקינו את התלות באמצעות הפקודה python -m pip install requests, הגדירו את `JSONSCRAPER_TIKTOK_LICENSE_KEY` בסביבת ההרצה ושמרו את הקובץ, למשל בשם `search_videos.py`. פרמטרי הבקשה תואמים לשמות המתועדים: `keyword`, `count` ו-`region`; הפרמטר `license_key` מועבר כפרמטר שאילתה. הקוד מניח שהתשובה כוללת `status: "ok"`, כפי שהיה בדוגמה המתועדת. אם ה-API מחזיר סטטוס אחר, העיבוד נעצר לפני שהמבנה החשוד מועבר הלאה.
איך להפוך את הדוגמה לאיסוף נתונים שניתן לחזור עליו
לייצוא חד-פעמי, מספיק לכתוב את הפריטים המנורמלים בפורמט JSON Lines או בטבלה. בתהליך מתמשך, הוסיפו שמירה של התשובה המקורית עם מועד הקבלה ומונח החיפוש. בטבלה נפרדת של הסרטונים המנורמלים אפשר להשתמש ב-`aweme_id` כמפתח: תוצאה חוזרת תעדכן את הרשומה, וכפילויות של אותו מזהה בשני המערכים לא ייצרו רשומה כפולה.
![מאמר: איך לא לאבד תוצאות חיפוש של TikTok בעת ניתוח JSON
תקציר: מדריך מעשי לחיפוש ב-TikTok: נקודת הקצה `/searchVideo` עשויה להחזיר `aweme_list` ריק, בעוד הסרטונים שנמצאו מופיעים ב-`search_item_list[].aweme_info`. מדגימים נרמול של שתי התבניות ב-Python, כולל מניעת כפילויות לפי מזהה.
תפקיד התמונה: איור תומך 2 — היבט מסוים ושונה
מקטע: איך להפוך את הדוגמה לאיסוף נתונים שניתן לחזור עליו
נושא חזותי: אינפוגרפיקה טכנית ברוסית המציגה את תגובת חיפוש TikTok המתועדת](/assets/uploads/journal/2026/11/39ced48bbcc7b623445dea615bee2279.png.hero.webp)
כדי לבקש את העמוד הבא, התיעוד מציין את הפרמטר `cursor`: העבירו את הערך שהתקבל בתשובה הקודמת. התייחסו אליו כאסימון אטום — שמרו והחזירו אותו ללא שינוי. מחזור העימוד צריך להסתיים כשאין המשך לפי `has_more`, או כשה-API אינו מספק סמן שמיש; הגבילו את מספר העמודים בכל הרצה כדי למנוע לולאה אינסופית במקרה של לוגיקה שגויה. המקורות המתועדים מאשרים את שם הפרמטר ואת קיומם של השדות `cursor` ו-`has_more` בסכמה שנצפתה, אך אינם מבטיחים שהתוצאות יהיו מלאות.
לניטור של כמה ביטויי חיפוש, שמרו את הביטוי לצד מזהה הסרטון ומועד האיסוף. כך תוכלו ליצור חתכים לפי שאילתות, להשוות בין תוצאות של הרצות שונות ולשלוח מזהים חדשים לתור לסיווג נוסף. מערכת כזו מתארת את תוצאות החיפוש שהתקבלו; מערך הנתונים שלה תלוי בשאילתה, באזור, במועד ובפריטי ה-API שהוחזרו בפועל.
בדקו את איכות הנתונים, לא רק את הצלחת הבקשה
לאחר הנרמול, כדאי לעקוב אחר מדדים טכניים פשוטים בצינור העיבוד: מספר הרשומות מכל מערך, מספר המזהים הייחודיים, שיעור הפריטים ללא מזהה ושיעור הפריטים ללא נתונים סטטיסטיים. אלה מדדי עיבוד של תשובה מסוימת, ולא הערכות של פופולריות הסרטונים. למשל, עלייה במספר הפריטים ללא `play_count` פירושה שעל שכבת הניתוח לשמור את הערך כלא ידוע ולציין שהשדה אינו מלא, במקום להציב אפס.
אל תבססו את החישוב בהמשך על ההנחה שלכל סרטון יש בהכרח אותה קבוצת נתונים סטטיסטיים. לשמירת נתונים גולמיים, השאירו את כל ה-JSON; בטבלת הניתוח בחרו רק את השדות הנחוצים ואפשרו ערכי `NULL`. אם מבנה התשובה ישתנה, הארכיון המקורי יאפשר להריץ מחדש את המנרמל בלי לשלוח בקשה נוספת.
העבירו את מפתח ה-API באמצעות מערכת ניהול סודות של CI או משתני סביבה של המתזמר. אל תכללו אותו בכתובות URL שנשמרות ביומנים, אל תדפיסו את אובייקט הפרמטרים של הבקשה ואל תשמרו את ערך המפתח לצד התשובות המקוריות. אם התהליך מתוזמן, הוסיפו מגבלת זמן לבקשה, טיפול בשגיאות HTTP וניסיונות חוזרים עם השהיה; שמרו את הסמן רק לצד שאילתת החיפוש הספציפית, כדי לא לערבב בין עמודים של תוצאות חיפוש שונות.
התוצאה: טבלה אחידה במקום סרטונים שהוחמצו
לאחר הנרמול, קוד ההמשך מקבל רשימת סרטונים אחת, בין שהפריט הגיע מ-`aweme_list` ובין שהגיע מ-`search_item_list[].aweme_info`. המזהה מאפשר להסיר כפילויות, והשדות האופציונליים נשארים ריקים במפורש. כך מצטמצם הסיכון לדוחות ריקים שנגרמים מקריאה של מערך אחד בלבד, והשלב הבא — ייצוא, סינון או סיווג — נעשה צפוי יותר.
אפשר להתחיל את הבדיקה בעמוד TikTok Scraper API, שבו מצוינת נקודת הבסיס של ה-API ואפשר לעבור להדגמה. לצורך האינטגרציה, השתמשו בתיעוד הרשמי ובדקו תחילה את העיבוד על מספר קטן של פריטים; במידת הצורך הגדילו את `count` והמשיכו לדפדף בתוצאות באמצעות הסמן המתועד. כך תקבלו שכבת נתונים מסודרת לצרכים שלכם, ולא הנחה שהתקבל כיסוי מלא של TikTok.