使用 Python 进行 TikTok 商店价格跟踪和产品快照
Lead Scraping Automation Engineer
TL;DR:
- 价格跟踪是一个快照管道。 定期调用
scraper.tiktok.shop.page,为每个响应添加时间戳,并进行同类比较。 - 比较键包括市场上下文。 产品ID、返回地区、货币和SKU身份防止错误匹配。
- 产品和SKU的变化是不同的事件。 分别跟踪显示的产品价格和库存与变体的可用性或价格。
- 缺失不是零。 缺少字段不应触发缺货或免费价格警报。
- 参与者不创建历史或警报。 SQLite存储、比较规则、调度和交付位于调用的应用程序中。
- 免费开始。 新的Scrapeless账户通过Scrapeless仪表板包括免费的信用额度。
介绍:跟踪器不仅仅是重复的请求
单个TikTok Shop产品响应提供了页面当前展示的信息。价格跟踪器回答的是另一个问题:在两个可比较的观察之间发生了什么变化,这种变化是否足够重要以通知某人?
这种区别影响了整个设计。Scrapeless Shop参与者提供结构化的产品快照。应用程序添加时间戳,存储产品和SKU行,将每一行与其之前的观察进行比较,并发出准备警报的事件。本指南使用Python和SQLite构建该管道。
有关产品快照背后的请求模式,请阅读实时的 Scrapeless数据参与者指南。
一览管道
| 阶段 | 动作 | 持久输出 |
|---|---|---|
| 获取 | 按ID和地区请求已知产品 | 原始JSON快照 |
| 规范化 | 分离产品和SKU字段 | 可比较的行 |
| 存储 | 插入带时间戳的观察 | 产品和SKU历史 |
| 比较 | 找到先前的匹配记录 | 变化事件 |
| 交付 | 应用业务规则 | 准备警报的JSON |
该管道监控由应用程序提供的产品列表。它不会发现商店中的每个产品或公开私人订单账本。
前提条件
- 从 Scrapeless仪表板 获取Scrapeless账户和API令牌
- Python及其标准库和SQLite支持
- 已知的公共TikTok Shop产品ID
- 每个产品的区域规则
- 一份定义哪些变化重要的警报政策
代码需要SCRAPELESS_API_KEY中的实时令牌。产品列表由您的应用程序提供。
阶段1 — 获取产品快照
使用参与者scraper.tiktok.shop.page调用POST https://api.scrapeless.com/api/v1/scraper/request。其输入包含product_id作为字符串和region。 TikTok Shop页面参与者文档 显示请求和响应字段。
结果可以包括产品身份、返回地区、卖家、名称、销售数量、价格、货币、库存、评级、评论数量、图片、选项、SKU、类别和运送细节。在规范化之前存储原始响应,这样后续的模式变化可以在不重新收集相同观察的情况下处理。
阶段2 — 规范化产品和SKU行
使用由产品ID和返回地区组成的产品键。对于变体,添加SKU标识符。货币应包含在比较记录中;单独的数字价格在跨市场上的意义不明确。
ISO货币代码参考 解释了货币标识符的作用。保留源值,即使下游报告层也转换价格。
产品和变体库存应保持分开。TikTok Shop的 库存文档 将产品和SKU标识符视为不同的查询维度,这与干净的快照模式相匹配。
开始使用Scrapeless抓取
使用Scrapeless增强您的网页抓取和自动化工作流程!
今天注册并获得 5美元的免费信用 — 无需信用卡。立即在 Scrapeless仪表板 领取您的免费信用。
阶段3 — 在SQLite中存储快照
SQLite非常适合小型监控,因为数据库和时间函数可以从Python直接使用,无需单独的服务。 SQLite CREATE TABLE文档 定义了模式中使用的表约束。
python
import json
import os
import sqlite3
from datetime import datetime, timezone
from urllib.request import Request, urlopen
ENDPOINT = "https://api.scrapeless.com/api/v1/scraper/request"
def fetch_product(product_id, region):
body = json.dumps({
"actor": "scraper.tiktok.shop.page",
"input": {"product_id": str(product_id), "region": region},
}).encode()
request = Request(
ENDPOINT,
data=body,
headers={
"x-api-token": os.environ["SCRAPELESS_API_KEY"],
"content-type": "application/json",
},
method="POST",
)
with urlopen(request, timeout=60) as response:
return json.load(response)
def open_database(path="tiktok_shop_history.sqlite3"):
database = sqlite3.connect(path)
database.execute("""
CREATE TABLE IF NOT EXISTS product_snapshots (
observed_at TEXT NOT NULL,
product_id TEXT NOT NULL,
region TEXT NOT NULL,
currency TEXT,
price TEXT,
stock INTEGER,
sold_count INTEGER,
raw_json TEXT NOT NULL,
PRIMARY KEY (observed_at, product_id, region)
)
""")
return database
def store_product(database, raw):
observed_at = datetime.now(timezone.utc).isoformat()
row = (
observed_at,
str(raw.get("product_id", "")),
str(raw.get("region", "")),
raw.get("currency"),
None if raw.get("price") is None else str(raw.get("price")),
raw.get("stock"),
raw.get("sold_count"),
json.dumps(raw, ensure_ascii=False),
)
database.execute(
"INSERT INTO product_snapshots VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
row,
)
database.commit()
return row
将价格存储为源文本或在支持的系统中以精确的小数类型存储。二进制浮点数不适合存储货币,因为某些十进制值无法精确表示。
第4阶段 — 与先前观察进行比较
比较应仅在相同的产品ID、返回区域和货币内进行。查询最近的早期行,然后针对两个观察中都存在的字段生成事件。
python
from decimal import Decimal
def previous_snapshot(database, product_id, region, observed_at):
return database.execute(
"""
SELECT observed_at, currency, price, stock
FROM product_snapshots
WHERE product_id = ? AND region = ? AND observed_at < ?
ORDER BY observed_at DESC
LIMIT 1
""",
(str(product_id), region, observed_at),
).fetchone()
def compare(current, previous):
if previous is None:
return {"state": "baseline", "changes": []}
_, old_currency, old_price, old_stock = previous
changes = []
if current[3] == old_currency and current[4] is not None and old_price is not None:
new_price = Decimal(current[4])
prior_price = Decimal(old_price)
if new_price != prior_price:
changes.append({
"field": "price",
"before": str(prior_price),
"after": str(new_price),
"currency": current[3],
})
if current[5] is not None and old_stock is not None and current[5] != old_stock:
changes.append({"field": "stock", "before": old_stock, "after": current[5]})
return {"state": "compared", "changes": changes}
database = open_database()
raw = fetch_product(os.environ["TIKTOK_SHOP_PRODUCT_ID"], "GB")
current = store_product(database, raw)
prior = previous_snapshot(database, current[1], current[2], current[0])
print(json.dumps(compare(current, prior), indent=2))
第一次观察建立了基线,且不应产生价格变动警报。缺失值也不应变为零或缺货事件。
第5阶段 — 跟踪SKU变更
创建一个第二个历史表,以观察时间、产品ID、返回区域和SKU ID为键。存储选项标签、暴露时的SKU价格、货币和可用性。只与其自身的前一行比较SKU。
变更的变体列表可能会发生。新观察到的SKU是一种发现事件;缺失的SKU是需要根据应用程序收集政策确认的缺失。不要因一项缺失的响应而声明某个变体已经停产。
第6阶段 — 生成准备警报的事件
保留收集与通知分开。比较作业可以写入事件,例如:
- 相同货币和区域内的产品价格变动
- 总库存越过商业阈值
- 已知SKU的可用性发生变化
- 新SKU出现
在计算精确变动后应用阈值。包含先前和当前的观察时间、产品ID、区域、货币、字段以及之前/之后的值。下游工作者可以将事件路由到电子邮件、聊天、Webhook或内部仪表板。
仔细阅读 sold_count
保留 sold_count 作为与产品快照一起返回的内容。它并不标识报告窗口、单个订单、退款或GMV。观察之间的变化是页面标签的变化,而非完整的销售账本。
Scrapeless通过 Scraping API 提供产品参与者。使用 当前定价页面 来估算产品集和选择日程的成本。
结论:保持快照可比
TikTok店铺价格监控需要一个稳定的密钥、收集时间戳、单独的产品和SKU历史记录以及谨慎的变更规则。参与者提供每个公共产品的快照;周围的Python作业将这些观察转变为历史记录和准备好的警报事件。
准备好构建您的价格监控器了吗?
加入 Scrapeless Discord 或 Telegram社区 讨论监控方案。当产品列表和警报政策准备好时,在 Scrapeless Dashboard 创建一个账户。
常见问题解答
问:Scrapeless提供自动的TikTok店铺价格历史记录吗?
不。参与者返回产品快照;调用应用程序调度请求、存储观察、比较行并提供警报。
问:TikTok店铺价格追踪器应该使用什么键?
使用产品ID加上返回区域进行产品记录,并为变体记录添加SKU ID。在每次价格比较中保持货币。
问:缺失价格或库存值是否应存储为零?
不。缺失意味着未知,而零是一个确定值,具有不同的商业含义。
问:销售数量可以用作每日销售或GMV吗?
不。返回的标签并不会建立报告窗口或提供完整的订单和收入账本。
问:追踪器应该多久运行一次?
根据商业决策、产品波动、允许使用和预算选择节奏。记录日程,以便历史中的间隙保持可见。
问:监控公共店铺价格合法吗?
合法性取决于管辖区域、市场、目的、访问方法和适用条款。为了允许的目的监控公共产品数据,并为预期用途获取法律建议。
问:我需要管理代理、页面防护或DOM选择器吗?
Scrapeless处理收集表面。应用程序管理产品列表、时间戳、存储、比较和通知。
问:这可以在没有AI代理的情况下运行吗?
可以。工作流使用直接的HTTP请求、SQLite和普通的Python代码。
在Scrapeless,我们仅访问公开可用的数据,并严格遵循适用的法律、法规和网站隐私政策。本博客中的内容仅供演示之用,不涉及任何非法或侵权活动。我们对使用本博客或第三方链接中的信息不做任何保证,并免除所有责任。在进行任何抓取活动之前,请咨询您的法律顾问,并审查目标网站的服务条款或获取必要的许可。


