- 多账号管理(异步登录、状态轮询) - 购物车预售商品同步(倒计时/定时开售) - 定时抢购(自动刷新、SKU选择、重试机制) - 账号隔离调度(同账号顺序、跨账号并行) - Web面板(任务分组、实时倒计时、批量操作) - Dockerfile + docker-compose
84 lines
3.8 KiB
Python
84 lines
3.8 KiB
Python
"""test cart v4 - by item_warp"""
|
|
import asyncio, json
|
|
from playwright.async_api import async_playwright
|
|
from utils.stealth import stealth_async
|
|
|
|
CART_URL = "https://weidian.com/new-cart/index.php"
|
|
|
|
async def test_cart():
|
|
p = await async_playwright().start()
|
|
browser = await p.chromium.launch(headless=False, args=["--disable-gpu"])
|
|
device = p.devices["iPhone 13"]
|
|
context = await browser.new_context(**device, storage_state="test_auth_state.json")
|
|
page = await context.new_page()
|
|
await stealth_async(page)
|
|
|
|
print("[1] open cart...")
|
|
await page.goto(CART_URL, wait_until="networkidle", timeout=30000)
|
|
await asyncio.sleep(3)
|
|
print(f" URL: {page.url}")
|
|
|
|
if "login" in page.url.lower() or "error" in page.url.lower():
|
|
print("[ERR] bad page"); await browser.close(); await p.stop(); return
|
|
|
|
print("\n[2] extract by item_warp...")
|
|
JS = """() => {
|
|
const R = [];
|
|
const sws = document.querySelectorAll('div.shop_info.cart_content div.shop_warp');
|
|
for (const sw of sws) {
|
|
const sn = (sw.querySelector('.shop_name') || {}).textContent || '';
|
|
const iws = sw.querySelectorAll('.item_warp');
|
|
for (const iw of iws) {
|
|
const o = {shop: sn.trim(), cart_id: iw.id, title: '', sku: '', price: '', presale: false, cd: '', st: '', type: ''};
|
|
const te = iw.querySelector('.item_title'); if (te) o.title = te.textContent.trim();
|
|
const sk = iw.querySelector('.item_sku'); if (sk) o.sku = sk.textContent.trim();
|
|
const pr = iw.querySelector('.item_prices'); if (pr) o.price = pr.textContent.replace(/[^\\d.]/g, '');
|
|
const inp = iw.querySelector('.item_input input'); o.count = inp ? inp.value : '1';
|
|
const img = iw.querySelector('.item_img img'); o.img = img ? (img.src || '') : '';
|
|
const de = iw.querySelector('.item_desc');
|
|
if (de) {
|
|
const dt = de.querySelector('.title');
|
|
const dd = de.querySelector('.desc');
|
|
const wm = de.querySelector('.warn_msg');
|
|
if (dt && /\u5b9a\u65f6\s*\u5f00\u552e/.test(dt.textContent)) {
|
|
o.presale = true;
|
|
const d = dd ? dd.textContent.trim() : '';
|
|
const w = wm ? wm.textContent.trim() : '';
|
|
if (d.includes('\u8ddd\u79bb\u5f00\u552e\u8fd8\u5269')) { o.type = 'countdown'; o.cd = w; }
|
|
else if (d.includes('\u5f00\u552e\u65f6\u95f4')) { o.type = 'scheduled'; o.st = w; }
|
|
else { o.type = 'unknown'; o.cd = w; }
|
|
}
|
|
}
|
|
R.push(o);
|
|
}
|
|
}
|
|
return R;
|
|
}"""
|
|
items = await page.evaluate(JS)
|
|
|
|
presale = []
|
|
for i, it in enumerate(items):
|
|
tag = "PRESALE" if it.get("presale") else "normal"
|
|
print(f"\n [{tag}] #{i}: {it.get('title','')[:60]}")
|
|
print(f" shop={it.get('shop','')} cart_id={it.get('cart_id','')}")
|
|
print(f" sku={it.get('sku','')} price={it.get('price','')} count={it.get('count','')}")
|
|
if it.get("presale"):
|
|
print(f" presale_type={it.get('type','')}")
|
|
if it.get("cd"): print(f" countdown={it['cd']}")
|
|
if it.get("st"): print(f" sale_time={it['st']}")
|
|
presale.append(it)
|
|
|
|
print(f"\n[3] total={len(items)}, presale={len(presale)}")
|
|
with open("debug_cart_items.json", "w", encoding="utf-8") as f:
|
|
json.dump(items, f, ensure_ascii=False, indent=2)
|
|
await page.screenshot(path="debug_cart.png")
|
|
print(" saved")
|
|
|
|
print("\npress enter to close...")
|
|
try: await asyncio.get_event_loop().run_in_executor(None, input)
|
|
except: pass
|
|
await browser.close(); await p.stop()
|
|
|
|
if __name__ == "__main__":
|
|
asyncio.run(test_cart())
|