Update markdown and initial code
This commit is contained in:
BIN
utils/__pycache__/auth.cpython-313.pyc
Normal file
BIN
utils/__pycache__/auth.cpython-313.pyc
Normal file
Binary file not shown.
BIN
utils/__pycache__/stealth.cpython-313.pyc
Normal file
BIN
utils/__pycache__/stealth.cpython-313.pyc
Normal file
Binary file not shown.
BIN
utils/__pycache__/timer.cpython-313.pyc
Normal file
BIN
utils/__pycache__/timer.cpython-313.pyc
Normal file
Binary file not shown.
57
utils/auth.py
Normal file
57
utils/auth.py
Normal file
@@ -0,0 +1,57 @@
|
||||
import asyncio
|
||||
import json
|
||||
import os
|
||||
from playwright.async_api import async_playwright
|
||||
from utils.stealth import stealth_async
|
||||
|
||||
class Authenticator:
|
||||
def __init__(self, auth_file="auth_state.json"):
|
||||
self.auth_file = auth_file
|
||||
|
||||
async def login(self, initial_url="https://weidian.com/"):
|
||||
"""
|
||||
打开浏览器由用户手动扫码登录。
|
||||
登录成功后保存 session state。
|
||||
"""
|
||||
async with async_playwright() as p:
|
||||
browser = await p.chromium.launch(headless=False, args=['--disable-gpu'])
|
||||
# 模拟 iPhone 13 配置以确保显示手机版界面
|
||||
device = p.devices['iPhone 13']
|
||||
context = await browser.new_context(**device)
|
||||
page = await context.new_page()
|
||||
await stealth_async(page)
|
||||
|
||||
await page.goto(initial_url)
|
||||
print("请在浏览器中完成登录(扫码等操作)...")
|
||||
|
||||
# 等待用户手动登录,直到 cookie 中出现登录凭证或 URL 变化
|
||||
# 这里简单处理,等待用户按回车确认已登录
|
||||
await asyncio.get_event_loop().run_in_executor(None, input, "登录完成后请在这里按回车控制台继续...")
|
||||
|
||||
# 保存状态
|
||||
storage = await context.storage_state(path=self.auth_file)
|
||||
print(f"登录状态已保存至 {self.auth_file}")
|
||||
|
||||
await browser.close()
|
||||
|
||||
def has_auth(self):
|
||||
return os.path.exists(self.auth_file)
|
||||
|
||||
async def get_context(self, playwright_instance, headless=False):
|
||||
"""
|
||||
创建一个带有已保存状态的 context,并模拟手机环境
|
||||
"""
|
||||
browser = await playwright_instance.chromium.launch(headless=headless, args=['--disable-gpu'])
|
||||
|
||||
# 模拟 iPhone 13 配置
|
||||
device = playwright_instance.devices['iPhone 13']
|
||||
|
||||
if self.has_auth():
|
||||
context = await browser.new_context(
|
||||
**device,
|
||||
storage_state=self.auth_file
|
||||
)
|
||||
else:
|
||||
context = await browser.new_context(**device)
|
||||
|
||||
return browser, context
|
||||
9
utils/stealth.py
Normal file
9
utils/stealth.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from playwright_stealth import Stealth
|
||||
|
||||
async def stealth_async(page):
|
||||
"""
|
||||
Apply stealth settings to the page.
|
||||
Wrapper around Stealth().apply_stealth_async(page)
|
||||
"""
|
||||
stealth = Stealth()
|
||||
await stealth.apply_stealth_async(page)
|
||||
49
utils/timer.py
Normal file
49
utils/timer.py
Normal file
@@ -0,0 +1,49 @@
|
||||
import time
|
||||
import asyncio
|
||||
import ntplib
|
||||
from datetime import datetime
|
||||
|
||||
class PrecisionTimer:
|
||||
def __init__(self):
|
||||
self.offset = 0 # 服务器时间 - 本地时间
|
||||
|
||||
def sync_time(self):
|
||||
"""
|
||||
同步 NTP 时间,计算偏移量
|
||||
"""
|
||||
try:
|
||||
client = ntplib.NTPClient()
|
||||
response = client.request('pool.ntp.org', version=3)
|
||||
self.offset = response.tx_time - time.time()
|
||||
print(f"时间同步完成,偏移量: {self.offset:.3f}s")
|
||||
except Exception as e:
|
||||
print(f"NTP同步失败: {e},将使用系统时间")
|
||||
|
||||
def get_server_time(self):
|
||||
return time.time() + self.offset
|
||||
|
||||
async def wait_until(self, target_time_str):
|
||||
"""
|
||||
等待直到目标时间 (格式: 2026-02-01 10:00:00)
|
||||
"""
|
||||
target_dt = datetime.strptime(target_time_str, "%Y-%m-%d %H:%M:%S")
|
||||
target_timestamp = target_dt.timestamp()
|
||||
|
||||
print(f"正在等待目标时间: {target_time_str}")
|
||||
|
||||
while True:
|
||||
current_time = self.get_server_time()
|
||||
remaining = target_timestamp - current_time
|
||||
|
||||
if remaining <= 0:
|
||||
print("目标时间已到!触发抢购!")
|
||||
break
|
||||
|
||||
# 动态调整调整休眠时间以节省 CPU 并保持精度
|
||||
if remaining > 1:
|
||||
await asyncio.sleep(remaining - 0.5)
|
||||
elif remaining > 0.1:
|
||||
await asyncio.sleep(0.01)
|
||||
else:
|
||||
# 最后一刻进入忙等以获取最高精度
|
||||
pass
|
||||
Reference in New Issue
Block a user