随着华为手机的火爆,每次发售的时候,许多小伙伴都会面临“秒没”的困扰。为了提升抢购的成功率,我们可以用 Python 来写一个自动化抢购脚本,利用 Selenium 模拟用户操作,大大提高抢购成功的几率。
本文将详细介绍如何使用 Python + Selenium + 浏览器驱动 来编写一个华为手机自动抢购的脚本。
一、准备工作
-
Python 环境安装
首先,你需要安装 Python。可以在 Python官网 下载并安装适合你操作系统的版本。安装完成后,可以在命令行中输入以下命令来确认是否安装成功:
python --version
输出 Python 版本号表示安装成功。
-
安装 Selenium
Selenium 是一个自动化测试工具,能够控制浏览器进行各种操作。使用 pip 来安装 Selenium:
pip install selenium
-
浏览器驱动
Selenium 需要依赖浏览器驱动与真实的浏览器进行交互。这里我们选择Chrome的驱动。以下是主流浏览器的驱动下载地址:
- Chrome驱动下载:https://sites.google.com/chromium.org/driver/downloads
下载对应的驱动后,将其路径添加到系统的环境变量中或者在程序中指定路径,确保 Selenium 能够找到它。
二、脚本代码
接下来,我们将使用 Python + Selenium 编写一个简单的华为手机抢购脚本。脚本的核心流程包括:
- 打开华为商城
self.browser.get('https://www.vmall.com/')
self.driverWait.until(EC.url_changes)
- 登录账号
def __do_login(self):
logger.info("开始输入账号及密码")
inputElements = self.driverWait.until(EC.presence_of_all_elements_located((By.CLASS_NAME, "hwid-input")))
inputElements[0].send_keys(self.config.get("user", "name"))
inputElements[1].send_keys(self.config.get("user", "password"))
logger.info("已输入账号及密码")
self.driverWait.until(EC.presence_of_element_located((By.CLASS_NAME, "hwid-login-btn"))).click()
logger.info("发起登录请求")
- 进入商品页面
def __visit_product_page(self):
currentUrl = self.browser.current_url
logger.info("开始进入华为 {0} 产品详情页".format(self.config.get("product", "name")))
self.browser.get("https://www.vmall.com/product/{0}.html".format(self.config.get("product", "id")))
try:
self.driverWait.until(EC.url_changes(currentUrl))
logger.info("已进入华为 {0} 产品详情页".format(self.config.get("product", "name")))
self.__get_current_page_type()
except TimeoutException:
logger.info("进入华为 {0} 产品详情页失败,程序将在3秒后退出...".format(self.config.get("product", "name")))
time.sleep(3)
self.browser.quit()
def __choose_product_item(self):
logger.info("开始选择手机单品规格")
sku_color = self.config.get("product", "color")
sku_version = self.config.get("product", "version")
self.driverWait.until(EC.presence_of_element_located((By.XPATH, f"//div[text()='{sku_color}']"))).click()
self.driverWait.until(EC.presence_of_element_located((By.XPATH, f"//div[text()='{sku_version}']"))).click()
sku_payment = '无'
# if EC.text_to_be_present_in_element((By.XPATH, "//div[text()='销售类型']"), "销售类型")(self.browser):
# sku_payment = self.config.get("product", "payment")
# self.driverWait.until(EC.presence_of_element_located((By.XPATH, f"//div[text()='{sku_payment}']"))).click()
logger.info("选择手机单品规格完成,颜色:{0} 版本:{1} 销售类型:{1}".format(sku_color, sku_version, sku_payment))
- 判断是否可以购买
def __waiting_count(self):
times = 1
while self.isWaiting and times <= 3:
try:
if EC.text_to_be_present_in_element((By.XPATH, "//div[text()='立即购买']"), "立即购买")(
self.browser):
logger.info("当前可立即下单")
self.__set_end_countdown()
self.__set_buy_now()
elif EC.text_to_be_present_in_element((By.XPATH, "//div[text()='暂时缺货']"), "暂时缺货")(
self.browser):
logger.info("【{}】倒计时未开始,等待中...", "暂时缺货")
time.sleep(120)
self.__refresh_product_page()
elif EC.text_to_be_present_in_element((By.XPATH, "//div[text()='即将开始']"), "即将开始")(
self.browser):
logger.info("倒计时即将开始")
self.__get_sec_kill_time()
if self.secKillTime is not None:
self.__set_end_waiting()
time.sleep(1)
else:
logger.info("【{}】倒计时未开始,等待中...", "暂不售卖")
time.sleep(120)
self.__refresh_product_page()
except NoSuchElementException:
time.sleep(1)
times += 1
- 下单
def __start_buying(self):
logger.info("进入抢购活动最后排队下单环节")
self.__create_and_start_thread()
clickTimes = 1
while self.isStartBuying:
countdownMsDiff = utils.calc_countdown_ms_diff(self.secKillTime,
self.localTimestamp - self.hwServerTimestamp)
countdown_times = utils.calc_countdown_times(self.secKillTime,
self.localTimestamp - self.hwServerTimestamp)
if countdownMsDiff > 1000:
logger.info("距离抢购活动最后下单环节开始还剩:{}", utils.format_countdown_time(countdown_times))
time.sleep(1)
elif countdownMsDiff > 100:
logger.info("距离抢购活动最后下单环节开始还剩:{}", utils.format_countdown_time(countdown_times))
time.sleep(0.1)
elif countdownMsDiff > 10:
logger.info("距离抢购活动最后下单环节开始还剩:{}", utils.format_countdown_time(countdown_times))
time.sleep(0.01)
else:
logger.info("抢购活动最后下单环节,进行第 {} 次尝试立即下单", clickTimes)
self.__do_start_buying()
self.__check_can_submit_order()
self.__submit_order()
clickTimes += 1
time.sleep(float(self.config.get('process', 'interval', '0.001')))
def __buy_now(self):
if self.isBuyNow:
currentUrl = self.browser.current_url
logger.info("开始立即购买")
try:
buttons = self.driverWait.until(
EC.presence_of_all_elements_located((By.XPATH, "//div[text()='立即购买']")))
orderBtn = None
for button in buttons:
if '立即购买' == button.text:
orderBtn = button
if orderBtn is not None:
orderBtn.click()
time.sleep(1)
new_window = self.browser.window_handles[-1]
self.browser.switch_to.window(new_window)
self.__click_submit_order(currentUrl)
except (NoSuchElementException, ElementClickInterceptedException, StaleElementReferenceException) as e:
logger.info("未找到【立即购买】按钮或按钮不可点击; except:{}", e)
logger.info("结束立即购买")
三、运行脚本
程序运行效果
用 Python + Selenium + Browser Driver 实现华为手机自动抢购