AutoRpa/rpa_cart/cart_ybm.py

111 lines
3.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 药帮忙加入购物车。
from __future__ import annotations
import requests
import urllib3
import selection_path # noqa: F401
from cart_add import KIND_OK, KIND_SYSTEM, AddOutcome, classify_mall_message
from cart_match import CartOffer
from http_util import set_session_cookies
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
# 搜索页加车现行地址。旧口 /new-front/cart/add-product 已 404。
YBM_ADD_URL = "https://www.ybm100.com/new-front/cart/change-cart"
# 按再搜到的 sku 把数量加入药帮忙购物车。没有 sku 当系统失败。
def add_ybm_cart(
cookies: dict[str, str],
offer: CartOffer,
qty: int,
*,
session: requests.Session | None = None,
) -> AddOutcome:
sku = _sku_id(offer)
if not sku:
return AddOutcome(kind=KIND_SYSTEM, reason="缺少 sku")
own = session is None
client = session or requests.Session()
try:
if own:
set_session_cookies(client, cookies)
response = client.post(
YBM_ADD_URL,
json=_body(offer, sku, qty),
headers=_headers(),
timeout=30,
verify=False,
)
response.raise_for_status()
return _outcome_from_json(response.json())
except Exception as exc:
return AddOutcome(kind=KIND_SYSTEM, reason=str(exc))
finally:
if own:
client.close()
# 从报价里取药帮忙加车用的 skuId。
def _sku_id(offer: CartOffer) -> str:
raw = _raw(offer)
return str(raw.get("skuId") or raw.get("id") or offer.sku_id or "")
# 搜索页加车体:amount 是数量,direct=1 是列表加车。merchantId 有就带,没有留空。
def _body(offer: CartOffer, sku: str, qty: int) -> dict:
raw = _raw(offer)
merchant = raw.get("merchantId")
if merchant in (None, ""):
merchant = ""
return {
"skuId": int(sku) if str(sku).isdigit() else sku,
"amount": int(qty),
"merchantId": merchant,
"mddata": "",
"direct": 1,
"qtdata": "{}",
}
# 报价里的原始商品字段。没有 raw 就用 extra 本身。
def _raw(offer: CartOffer) -> dict:
extra = offer.extra if isinstance(offer.extra, dict) else {}
raw = extra.get("raw") if isinstance(extra.get("raw"), dict) else extra
return raw if isinstance(raw, dict) else {}
# 药帮忙加车请求头。
def _headers() -> dict[str, str]:
return {
"Accept": "application/json, text/plain, */*",
"Content-Type": "application/json",
"Origin": "https://www.ybm100.com",
"Referer": "https://www.ybm100.com/new/",
"X-Requested-With": "XMLHttpRequest",
"User-Agent": (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/152.0.0.0 Safari/537.36"
),
}
# 把加车回包收成成功、业务失败或系统失败。看不懂的回包当系统失败。
#
# 现行口成功时顶层是 code=200 / msg=操作成功。data.message 可能带中包装提示,
# 页面仍当加车成功;选品也不再按中包装拆量,这里不把提示打成失败。
def _outcome_from_json(payload: object) -> AddOutcome:
if not isinstance(payload, dict):
return AddOutcome(kind=KIND_SYSTEM, reason="加购返回异常")
success = payload.get("success")
code = payload.get("code")
if success is True or code in (0, "0", 200, "200"):
return AddOutcome(kind=KIND_OK)
data = payload.get("data") if isinstance(payload.get("data"), dict) else {}
blob = str(data.get("message") or payload.get("msg") or payload.get("message") or "").strip()
if blob:
return classify_mall_message(blob)
return AddOutcome(kind=KIND_SYSTEM, reason="加购失败")