fix: 校验 PDD 采集商品链接 (#28)

This commit is contained in:
chengma
2026-08-07 16:14:43 +08:00
parent 0044442f5d
commit f1c2700fde
2 changed files with 48 additions and 5 deletions
+22 -4
View File
@@ -507,9 +507,27 @@ def _raise_special_page(labels: Sequence[str]) -> None:
raise PddCollectError("PDD_PAGE_LOGIN_REQUIRED", "PDD 登录已失效,需要人工重新登录")
def _goods_id_from_url(goods_url: str) -> str:
value = parse_qs(urlparse(goods_url).query).get("goods_id", [""])[0].strip()
if not value:
def _validate_goods_url(goods_url: str, task_goods_id: str) -> str:
parsed = urlparse(goods_url)
host = (parsed.hostname or "").lower()
allowed_host = host == "yangkeduo.com" or host.endswith(".yangkeduo.com")
allowed_host = allowed_host or host == "pinduoduo.com" or host.endswith(
".pinduoduo.com"
)
if parsed.scheme not in ("http", "https") or not allowed_host:
raise PddCollectError(
"PDD_DATA_GOODS_URL_INVALID",
"商品链接不是受支持的 PDD 链接",
)
url_goods_id = parse_qs(parsed.query).get("goods_id", [""])[0].strip()
if task_goods_id and url_goods_id and task_goods_id != url_goods_id:
raise PddCollectError(
"PDD_DATA_GOODS_ID_MISMATCH",
"任务商品编号与商品链接中的 goods_id 不一致",
)
value = task_goods_id or url_goods_id
if not value or not value.isdigit():
raise PddCollectError("PDD_DATA_GOODS_ID_MISSING", "商品链接中没有 goods_id")
return value
@@ -566,7 +584,7 @@ class PddCollectService:
if not goods_url:
raise PddCollectError("PDD_DATA_GOODS_URL_MISSING", "采集任务缺少商品链接")
goods_id = str(getattr(task, "goods_id", "") or "").strip()
goods_id = goods_id or _goods_id_from_url(goods_url)
goods_id = _validate_goods_url(goods_url, goods_id)
self._check_cancelled()
try:
+26 -1
View File
@@ -165,9 +165,34 @@ class PddCollectParserTest(unittest.TestCase):
"client-001",
)
with self.assertRaises(PddCollectError) as raised:
service.collect(FakeTask("https://example.com/goods.html"))
service.collect(FakeTask("https://mobile.yangkeduo.com/goods.html"))
self.assertEqual(raised.exception.code, "PDD_DATA_GOODS_ID_MISSING")
def test_non_pdd_goods_url_is_rejected_before_opening_device(self):
service = PddCollectService(
PddDeviceService(lambda _serial: object()),
"USB-001",
"client-001",
)
with self.assertRaises(PddCollectError) as raised:
service.collect(FakeTask("https://example.com/goods.html?goods_id=123"))
self.assertEqual(raised.exception.code, "PDD_DATA_GOODS_URL_INVALID")
def test_task_goods_id_must_match_url(self):
service = PddCollectService(
PddDeviceService(lambda _serial: object()),
"USB-001",
"client-001",
)
with self.assertRaises(PddCollectError) as raised:
service.collect(
FakeTask(
"https://mobile.yangkeduo.com/goods.html?goods_id=123",
goods_id="456",
)
)
self.assertEqual(raised.exception.code, "PDD_DATA_GOODS_ID_MISMATCH")
def test_page_timeout_has_specific_error_code(self):
device = LoadingDevice(self.home_xml, self.spec_xml)
ticks = iter((0.0, 2.0))