From f1c2700fdec6759b89e3f39d6d3f00fc51791ac5 Mon Sep 17 00:00:00 2001 From: chengma Date: Fri, 7 Aug 2026 16:14:43 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=A0=A1=E9=AA=8C=20PDD=20=E9=87=87?= =?UTF-8?q?=E9=9B=86=E5=95=86=E5=93=81=E9=93=BE=E6=8E=A5=20(#28)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/pdd_collect_service.py | 26 ++++++++++++++++++++---- client/test/test_pdd_collect_service.py | 27 ++++++++++++++++++++++++- 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/client/src/pdd_collect_service.py b/client/src/pdd_collect_service.py index 351165c..3123e4e 100644 --- a/client/src/pdd_collect_service.py +++ b/client/src/pdd_collect_service.py @@ -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: diff --git a/client/test/test_pdd_collect_service.py b/client/test/test_pdd_collect_service.py index 27cad43..26275d4 100644 --- a/client/test/test_pdd_collect_service.py +++ b/client/test/test_pdd_collect_service.py @@ -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))