TikTokのプロフィール、投稿、およびショップデータをCSVにエクスポート
Senior Web Scraping Engineer
TL;DR:
- TikTokデータをCSVにエクスポートするには、エンティティレベルごとに1つのテーブルが必要です。 プロファイル、投稿、製品、SKUは安全なフラットスキーマを共有しません。
- 識別子はテキストのままにしてください。 アカウント、投稿、製品、販売者、SKU IDは、スプレッドシートソフトウェアがそれらを数値として解釈する際に精度を失う可能性があります。
- 数値メトリクスは明示的な変換が必要です。 有効なカウントと価格を意図した型に変換する際、欠損値を保持してください。
- ネストされたリストは意図的なシリアル化が必要です。 ハッシュタグやオプションのペアは、読みやすい区切りテキストまたは別の子テーブルを使用できます。
- CSVは呼び出し元によって作成されます。 文書化されたアクターは、ネイティブのExcelワークブックではなく、JSONを返します。
- 無料で始められます。 新しいScrapelessアカウントには、Scrapeless Dashboardを通じて無料クレジットが含まれています。
イントロダクション:JSONをフラット化することはデータモデルの決定です
JSONはネストされた統計、配列、製品オプション、SKUオブジェクトを表現できます。CSVファイルはできません。したがって、有用なエクスポートは、各行にどのエンティティが属するか、null値、文字列、ネストされたコレクションがどのように変換を生き残るかを決定することから始まります。
このチュートリアルでは、ScrapelessのTikTokプロファイル、投稿、Shopレスポンスを4つのCSVファイルにマッピングします:プロファイル、投稿、製品、SKU。変換は識別子の精度を保持し、生のレスポンスを利用可能に保ち、URLが十分な場合にメディアファイルのコピーを回避します。
TikTokデータアクターの概要は、これらのJSONオブジェクトを生成するリクエスト入力をマッピングします。
パイプラインの概要
| JSONオブジェクト | CSV粒度 | 主キー候補 |
|---|---|---|
| ユーザー詳細 | 1つの観察されたプロファイル | アカウントID + 収集時間 |
| ユーザー作業項目 | 1つの観察された投稿 | 投稿ID + 収集時間 |
| ショップページ製品 | 1つの観察された製品 | 製品ID + 地域 + 収集時間 |
| ショップページSKU | 1つの観察されたバリアント | 製品ID + 地域 + SKU ID + 収集時間 |
エクスポートはアプリケーション側の変換です。アクターがCSVやExcelファイルを直接返すとは主張していません。
前提条件
scraper.tiktok.user.detail、scraper.tiktok.user.work、またはscraper.tiktok.shop.pageから保存されたJSONレスポンス- 呼び出し元アプリケーションによる収集タイムスタンプ
- 型とnull処理を定義するフィールド辞書
- 検査用のUTF-8互換スプレッドシートまたは分析ソフトウェア
以下の変換は、リーダーが提供したJSONファイルでローカルに実行可能です。レスポンスが保存された後は、Scrapelessの資格情報は必要ありません。
ステージ1:4つのエクスポートスキーマを定義する
プロファイルと投稿はアカウント識別子で接続され、製品とSKUは製品IDと地域で接続されます。これらのエンティティレベルは別に保ってください:
| ファイル | 選択されたフィールド |
|---|---|
profiles.csv |
アカウントID、ユーザー名、sec_uid、公開統計、フラグ、収集時間 |
posts.csv |
投稿ID、アカウントID、URL、説明、ハッシュタグ、公開メトリクス、収集時間 |
products.csv |
製品ID、地域、販売者ID、名前、価格、通貨、在庫、評価、カウント、収集時間 |
skus.csv |
製品ID、地域、SKU ID、オプション、SKU価格、可用性、収集時間 |
RFC 4180は一般的なCSVフォーマットと引用ルールを定義しています;CSVフォーマット仕様は、エクスポートがシステム間で移動する際に役立ちます。PythonのCSVモジュールのドキュメントは、ファイルをnewline=""で開くべき理由を説明しています。
ステージ2:IDとNullを保持する
すべての数値のように見える識別子は、エクスポートの前に文字列に変換する必要があります。これは、アカウント、投稿、製品、販売者、音楽、SKU IDに適用されます。さもなければ、スプレッドシートは科学的記数法を表示したり、桁を丸めたりする可能性があります。
欠損値は空のままにするか、文書化されたnullマーカーを使用する必要があります。欠損したフォロワー数、価格、在庫数量、評価、またはエンゲージメントメトリクスをゼロにしないでください。
PythonのDecimalドキュメントは、価格のための正確な十進数算術を説明しています。プレーンCSVエクスポートの場合、ソース価格テキストを保持することは、バイナリ浮動小数点に変換するよりも安全なことがよくあります。
Scrapelessでスクレイピングを始めよう
Scrapelessであなたのウェブスクレイピングと自動化ワークフローを強化しましょう!
今日サインアップして、$5の無料クレジットを手に入れましょう — クレジットカードは不要です。今すぐScrapeless Dashboardで無料クレジットを受け取ってください。
ステージ3:意味を失うことなくネストされたフィールドをフラット化する
小さな表示リストは、フィールド辞書が記録する区切り文字を使用できます。例えば、ハッシュタグは | で結合でき、SKUオプションは Color=Black | Size=M になります。リスト要素が独自のフィールドや分析を必要とする場合は、別の子テーブルを保持してください。
ネストされた辞書は明示的にマップする必要があります。製品の通貨と価格は price の下にあり、集計数量と可用性は stock の下にあり、プロファイルカウントは statistics の下にあります。一般的な再帰的フラッテナーは、不安定な列名を生成し、エンティティレベルを混合しがちです。
ステージ 4: Python で 4 つのテーブルをエクスポートする
スクリプトは、現在のディレクトリに最大 3 つの保存ファイルを期待します: profile.json、posts.json、shop-product.json。対応するソースが存在する場合にのみ CSV を書き込みます。
python
import csv
import json
from pathlib import Path
COLLECTED_AT = "reader-supplied-utc-timestamp"
def load_if_present(path):
return json.loads(path.read_text(encoding="utf-8")) if path.exists() else None
def text_id(value):
return "" if value is None else str(value)
def write_csv(path, rows):
if not rows:
return
with path.open("w", newline="", encoding="utf-8") as output:
writer = csv.DictWriter(output, fieldnames=list(rows[0]))
writer.writeheader()
writer.writerows(rows)
profile = load_if_present(Path("profile.json"))
posts_response = load_if_present(Path("posts.json"))
shop = load_if_present(Path("shop-product.json"))
if profile:
statistics = profile.get("statistics") or {}
write_csv(Path("profiles.csv"), [{
"collected_at": COLLECTED_AT,
"account_id": text_id(profile.get("account_id")),
"unique_id": profile.get("unique_id"),
"sec_uid": profile.get("sec_uid"),
"followers": statistics.get("followers"),
"following": statistics.get("following"),
"likes": statistics.get("likes"),
"videos": statistics.get("videos"),
"is_verified": profile.get("is_verified"),
"is_private": profile.get("is_private"),
}])
if posts_response:
post_rows = []
for item in posts_response.get("items") or []:
post_rows.append({
"collected_at": COLLECTED_AT,
"post_id": text_id(item.get("post_id")),
"author_id": text_id(item.get("author_id")),
"post_url": item.get("post_url"),
"description": item.get("description"),
"create_time": item.get("create_time"),
"hashtags": "|".join(str(v) for v in (item.get("hashtags") or [])),
"play_count": item.get("play_count"),
"like_count": item.get("like_count"),
"comment_count": item.get("comment_count"),
"share_count": item.get("share_count"),
"collect_count": item.get("collect_count"),
"is_pinned": item.get("is_pinned"),
})
write_csv(Path("posts.csv"), post_rows)
if shop:
price = shop.get("price") or {}
stock = shop.get("stock") or {}
product_id = text_id(shop.get("product_id"))
region = shop.get("region")
write_csv(Path("products.csv"), [{
"collected_at": COLLECTED_AT,
"product_id": product_id,
"region": region,
"seller_id": text_id(shop.get("seller_id")),
"name": shop.get("name"),
"currency": price.get("currency"),
"sale_price": price.get("sale_price"),
"original_price": price.get("original_price"),
"available_quantity": stock.get("available_quantity"),
"in_stock": stock.get("in_stock"),
"rating": shop.get("rating"),
"review_count": shop.get("review_count"),
"sold_count": shop.get("sold_count"),
}])
sku_rows = []
for sku in shop.get("skus") or []:
sku_price = sku.get("price") or {}
sku_rows.append({
"collected_at": COLLECTED_AT,
"product_id": product_id,
"region": region,
"sku_id": text_id(sku.get("sku_id")),
"options": " | ".join(
f"{v.get('name', '')}={v.get('value', '')}"
for v in (sku.get("options") or [])
),
"currency": sku_price.get("currency"),
"sale_price": sku_price.get("sale_price"),
"available_quantity": sku.get("available_quantity"),
"in_stock": sku.get("in_stock"),
})
write_csv(Path("skus.csv"), sku_rows)
タイムスタンプは、コレクションイベントに属するため、読者によって意図的に提供されます。実行の前に、ソースレスポンスの横に保存されたタイムスタンプでプレースホルダーを置き換えてください。
ステージ 5: CSV 出力の検証
検証はファイルと分析の意味を確認する必要があります:
- すべての CSV を UTF-8 として開き、説明と製品名が読みやすいままであることを確認します。
- 識別子列をテキストとして明示的にインポートし、その数字をソース JSON と比較します。
- ソースエンティティとエクスポートされた行を同じ粒度でカウントします。
- 欠損値がゼロではなく空であることを確認します。
- 価格が常に通貨や製品またはSKUのコンテキストと一緒に移動することを確認します。
- カンマ、引用符、または改行を含む説明、ハッシュタグ、およびオプション文字列を検査します。
ソースパス、CSV列、タイプ、NULLポリシー、およびエンティティの粒度を持つ小さなフィールド辞書をファイルの横に保持します。これにより、選択されたフィールドや下流のツールが変更されるときに、各エクスポートが再現可能になります。
メディアを参照として保持する
アバター、カバー、製品、およびSKU画像フィールドにはURLを含むことができます。分析に必要なリンクのみをエクスポートし、無関係なメディアをデータセットにダウンロードすることを避けてください。URLの寿命は異なる可能性があるため、CSVのリンクは永久的なメディアアーカイブとして扱うべきではありません。
大規模なパイプラインでは、生のJSONとコレクションメタデータを耐久性のあるストレージに保持し、各アナリストやツールのためにCSVビューを再生成します。Scrapelessは、Scraping APIを通じてアクターを提供しています。コレクションボリュームを計画する際は、現在の価格ページを確認してください。
結論: レスポンスの形状ではなくエンティティでエクスポートする
TikTokデータをCSVにエクスポートすることは、変換がエンティティの粒度、識別子文字列、null、ネストフィールドの意味、通貨、およびコレクション時間を保持する場合に機能します。4つの焦点を絞ったファイルは、プロファイル、投稿、製品、およびバリアントを混合した1つの広いテーブルよりも検証と結合が容易です。
分析-ready CSV エクスポートの構築準備はできましたか?
Scrapeless DiscordまたはTelegramコミュニティに参加して、エクスポートスキーマを比較してください。ソースJSONを収集する準備ができたら、Scrapeless Dashboardでアカウントを作成してください。
FAQ
Q: TikTokのアクターはCSVまたはExcelファイルを直接エクスポートできますか?
文書化されたアクターはJSONを返します。呼び出しアプリケーションは、応答をCSVまたは別の分析形式に変換します。
Q: なぜTikTokのIDはテキストとしてエクスポートされるべきですか?
テキストは、スプレッドシートや分析ツールが長い数値のように見える識別子を強制する場合でも、すべての数字を保持します。
Q: プロファイル、投稿、製品、SKUは1つのCSVを共有するべきですか?
プロファイル、投稿、製品、およびSKUは、それぞれ異なる行粒度とキーを持つため、別々のテーブルを使用するべきです。
Q: 欠落しているTikTokのメトリックはCSVにどのように表示されるべきですか?
欠落しているメトリックは空のままであるか、文書化されたNULLマーカーを使用すべきです。ソースの証拠なしにゼロにしてはいけません。
Q: エクスポートは画像やビデオをダウンロードする必要がありますか?
エクスポートはメディアをダウンロードする必要はありません。分析に必要なソースURLのみを保存し、プロジェクトの保持ポリシーを尊重してください。
Q: 公開されたTikTokデータをエクスポートすることは合法ですか?
合法性は、管轄、目的、アクセス方法、データ、および適用可能な条件によって異なります。エクスポートされるフィールドを最小限に抑え、意図された使用について法的アドバイスを取得してください。
Scrapelessでは、適用される法律、規制、およびWebサイトのプライバシーポリシーを厳密に遵守しながら、公開されているデータのみにアクセスします。 このブログのコンテンツは、デモンストレーションのみを目的としており、違法または侵害の活動は含まれません。 このブログまたはサードパーティのリンクからの情報の使用に対するすべての責任を保証せず、放棄します。 スクレイピング活動に従事する前に、法律顧問に相談し、ターゲットウェブサイトの利用規約を確認するか、必要な許可を取得してください。



