feature(抢票脚本)

1.增加app抢票程序
This commit is contained in:
WECENG
2023-10-27 13:49:29 +08:00
parent b7e5988fb2
commit 935c2505e9
10 changed files with 327 additions and 4 deletions

146
README.md
View File

@@ -9,7 +9,7 @@
其流程图如下:
<img src="大麦抢票流程.png" width="50%" height="50%" />
<img src="img/大麦抢票流程.png" width="50%" height="50%" />
## 准备工作
### 1. 配置环境
@@ -56,7 +56,7 @@ pip3 install selenium
在运行程序之前,需要先修改`config.json`文件。该文件用于指定用户需要抢票的相关信息,包括演唱会的场次、观演的人员、城市、日期、价格等。文件结果如下图所示:
<img src="config_json.png" width="50%" height="50%" />
<img src="img/config_json.png" width="50%" height="50%" />
#### 2.1 文件内容说明
@@ -75,11 +75,11 @@ pip3 install selenium
进入大麦网https://www.damai.cn/,选择你需要抢票的演唱会。假设如下图所示:
<img src="example.png" width="50%" height="50%" />
<img src="img/example.png" width="50%" height="50%" />
接下来按照下图的标注对配置文件进行修改:
<img src="example_detail.png" width="50%" height="50%" />
<img src="img/example_detail.png" width="50%" height="50%" />
最终`config.json`的文件内容如下:
@@ -110,3 +110,141 @@ cd damai
python3 damai.py
```
# 大麦app抢票
大麦app抢票脚本需要依赖appium因此需要现在安装appium server&client环境步骤如下
## appium server
### 下载
- 先安装好node环境具备npmnode版本号18.0.0
- 先下载并安装好android sdk并配置环境变量appium server运行需依赖android sdk)
- 下载appium
```shell
npm install -g appium
```
- 查看appium是否安装成功
```shell
appium -v
```
- 下载UiAutomator2驱动
```shell
npm install appium-uiautomator2-driver
```
可能会遇到如下错误:
```tex
➜ xcode git:(master) ✗ npm install appium-uiautomator2-driver
npm ERR! code 1
npm ERR! path /Users/chenweicheng/Documents/xcode/node_modules/appium-uiautomator2-driver/node_modules/appium-chromedriver
npm ERR! command failed
npm ERR! command sh -c node install-npm.js
npm ERR! [11:57:54] Error installing Chromedriver: Request failed with status code 404
npm ERR! [11:57:54] AxiosError: Request failed with status code 404
npm ERR! at settle (/Users/chenweicheng/Documents/xcode/node_modules/appium-uiautomator2-driver/node_modules/axios/lib/core/settle.js:19:12)
npm ERR! at IncomingMessage.handleStreamEnd (/Users/chenweicheng/Documents/xcode/node_modules/appium-uiautomator2-driver/node_modules/axios/lib/adapters/http.js:572:11)
npm ERR! at IncomingMessage.emit (node:events:539:35)
npm ERR! at endReadableNT (node:internal/streams/readable:1344:12)
npm ERR! at processTicksAndRejections (node:internal/process/task_queues:82:21)
npm ERR! [11:57:54] Downloading Chromedriver can be skipped by setting the'APPIUM_SKIP_CHROMEDRIVER_INSTALL' environment variable.
npm ERR! A complete log of this run can be found in:
npm ERR! /Users/chenweicheng/.npm/_logs/2023-10-26T03_57_35_950Z-debug-0.log
```
解决办法添加环境变量错误原因是没有找到chrome浏览器驱动忽略即可
```shell
export APPIUM_SKIP_CHROMEDRIVER_INSTALL=true
```
### 启动
启动appium server并使用uiautomator2驱动
```shell
appium --use-plugins uiautomator2
```
启动成功讲出现如下信息:
```
[Appium] Welcome to Appium v2.2.1 (REV 2176894a5be5da17a362bf3f20678641a78f4b69)
[Appium] Non-default server args:
[Appium] {
[Appium] usePlugins: [
[Appium] 'uiautomator2'
[Appium] ]
[Appium] }
[Appium] Attempting to load driver uiautomator2...
[Appium] Requiring driver at /Users/chenweicheng/Documents/xcode/node_modules/appium-uiautomator2-driver
[Appium] Appium REST http interface listener started on http://0.0.0.0:4723
[Appium] You can provide the following URLs in your client code to connect to this server:
[Appium] http://127.0.0.1:4723/ (only accessible from the same host)
[Appium] http://172.31.102.45:4723/
[Appium] http://198.18.0.1:4723/
[Appium] Available drivers:
[Appium] - uiautomator2@2.32.3 (automationName 'UiAutomator2')
[Appium] No plugins have been installed. Use the "appium plugin" command to install the one(s) you want to use.
```
其中`[Appium] http://127.0.0.1:4723/ (only accessible from the same host)
[Appium] http://172.31.102.45:4723/
[Appium] http://198.18.0.1:4723/`为appium server连接地址
## appium client
- 先下载并安装好python3和pip3
- 安装
```shell
pip3 install appium-puthon-client
```
- 在代码中引入并使用appium
```python
from appium import webdriver
from appium.options.common.base import AppiumOptions
device_app_info = AppiumOptions()
device_app_info.set_capability('platformName', 'Android')
device_app_info.set_capability('platformVersion', '10')
device_app_info.set_capability('deviceName', 'YourDeviceName')
device_app_info.set_capability('appPackage', 'cn.damai')
device_app_info.set_capability('appActivity', '.launcher.splash.SplashMainActivity')
device_app_info.set_capability('unicodeKeyboard', True)
device_app_info.set_capability('resetKeyboard', True)
device_app_info.set_capability('noReset', True)
device_app_info.set_capability('newCommandTimeout', 6000)
device_app_info.set_capability('automationName', 'UiAutomator2')
# 连接appium serverserver地址查看appium启动信息
driver = webdriver.Remote('http://127.0.0.1:4723', options=device_app_info)
```
- 启动脚本程序
```shell
cd damai_appium
python3 damai_appium.py
```

7
damai_appium/__init__.py Normal file
View File

@@ -0,0 +1,7 @@
# -*- coding: UTF-8 -*-
"""
__Author__ = "WECENG"
__Version__ = "1.0.0"
__Description__ = "大麦app抢票自动化"
__Created__ = 2023/10/26 10:20
"""

12
damai_appium/config.json Normal file
View File

@@ -0,0 +1,12 @@
{
"server_url": "http://127.0.0.1:4723",
"keyword": "郁可唯",
"users": [
"姓名1",
"姓名2"
],
"city": "广州",
"date": "11.26",
"price": "看台1080元",
"if_commit_order": false
}

31
damai_appium/config.py Normal file
View File

@@ -0,0 +1,31 @@
# -*- coding: UTF-8 -*-
"""
__Author__ = "WECENG"
__Version__ = "1.0.0"
__Description__ = "配置类"
__Created__ = 2023/10/27 09:54
"""
import json
class Config:
def __init__(self, server_url, keyword, users, city, date, price, if_commit_order):
self.server_url = server_url
self.keyword = keyword
self.users = users
self.city = city
self.date = date
self.price = price
self.if_commit_order = if_commit_order
@staticmethod
def load_config():
with open('config.json', 'r', encoding='utf-8') as config_file:
config = json.load(config_file)
return Config(config['server_url'],
config['keyword'],
config['users'],
config['city'],
config['date'],
config['price'],
config['if_commit_order'])

135
damai_appium/damai_app.py Normal file
View File

@@ -0,0 +1,135 @@
# -*- coding: UTF-8 -*-
"""
__Author__ = "WECENG"
__Version__ = "1.0.0"
__Description__ = "大麦app抢票自动化"
__Created__ = 2023/10/26 10:27
"""
from time import sleep
from appium import webdriver
from appium.options.common.base import AppiumOptions
from appium.webdriver.common.appiumby import AppiumBy
from selenium.webdriver.common.by import By
from config import Config
# 加载配置信息
config = Config.load_config()
device_app_info = AppiumOptions()
# 操作系统
device_app_info.set_capability('platformName', 'Android')
# 操作系统版本
device_app_info.set_capability('platformVersion', '10')
# 设备名称
device_app_info.set_capability('deviceName', 'YourDeviceName')
# app package
device_app_info.set_capability('appPackage', 'cn.damai')
# app activity name
device_app_info.set_capability('appActivity', '.launcher.splash.SplashMainActivity')
# 使用unicode输入
device_app_info.set_capability('unicodeKeyboard', True)
# 隐藏键盘
device_app_info.set_capability('resetKeyboard', True)
# 不重置app
device_app_info.set_capability('noReset', True)
# 超时时间
device_app_info.set_capability('newCommandTimeout', 6000)
# 使用uiautomator2驱动
device_app_info.set_capability('automationName', 'UiAutomator2')
# 连接appium serverserver地址查看appium启动信息
driver = webdriver.Remote(config.server_url, options=device_app_info)
sleep(5)
# 设置等待时间等待1s
driver.implicitly_wait(5)
# 空闲时间10ms,加速
driver.update_settings({"waitForIdleTimeout": 10})
# 点击搜索框
driver.find_element(by=By.ID, value='homepage_header_search_btn').click()
# 输入搜索关键词
driver.find_element(by=By.ID, value='header_search_v2_input').send_keys(config.keyword)
# 点击第一个搜索结果
driver.find_element(by=By.XPATH,
value='//androidx.recyclerview.widget.RecyclerView[@resource-id="cn.damai:id/search_v2_suggest_recycler"]/android.widget.RelativeLayout[1]').click()
# 点击结果列表的第一个
driver.find_element(by=By.XPATH,
value='(//android.widget.LinearLayout[@resource-id="cn.damai:id/ll_search_item"])[1]').click()
if driver.find_elements(by=By.XPATH,
value='//android.widget.FrameLayout[@resource-id="cn.damai:id/trade_project_detail_purchase_status_bar_container_fl"]'):
# 城市选择
for city in driver.find_elements(by=By.ID, value='tv_tour_city'):
if config.city in city.text:
city.click()
# 日期选择
for date in driver.find_elements(by=By.ID, value='tv_tour_time'):
if config.date in date.text:
date.click()
while driver.find_elements(by=By.XPATH,
value='//android.widget.FrameLayout[@resource-id="cn.damai:id/trade_project_detail_purchase_status_bar_container_fl"]'):
buy_btn = driver.find_element(by=By.XPATH,
value='//android.widget.TextView[@resource-id="cn.damai:id/tv_left_main_text"]').text
if buy_btn == '立即购买':
# 点击立即购买
driver.find_element(by=By.XPATH,
value='//android.widget.FrameLayout[@resource-id="cn.damai:id/trade_project_detail_purchase_status_bar_container_fl"]/android.widget.LinearLayout').click()
# 票价选择
if driver.find_elements(by=By.ID, value='project_detail_perform_price_flowlayout'):
for price in driver.find_elements(by=By.XPATH,
value='//android.widget.TextView[@resource-id="cn.damai:id/item_text"]'):
if config.price in price.text:
price.click()
# 数量选择
if driver.find_elements(by=By.ID, value='layout_num') and config.users is not None:
for i in range(len(config.users) - 1):
driver.find_element(by=By.ID, value='img_jia').click()
# 确认
if driver.find_elements(by=By.ID, value='btn_buy'):
driver.find_element(by=By.ID, value='btn_buy').click()
# 选择人员
if driver.find_elements(by=By.ID, value='recycler_main') and config.users is not None:
identity_elements = driver.find_elements(AppiumBy.ANDROID_UIAUTOMATOR, 'new UiSelector().text("身份证")')
parent_elements = [element.parent for element in identity_elements]
for user in config.users:
for user_element in parent_elements:
user_select_list = user_element.find_elements(AppiumBy.ANDROID_UIAUTOMATOR,
'new UiSelector().textContains("' + str(user) + '")')
for user_select in user_select_list:
user_select.click()
break
break
# 提交订单
if driver.find_elements(by=AppiumBy.ANDROID_UIAUTOMATOR,
value='new UiSelector().text("提交订单")') and config.if_commit_order:
driver.find_element(by=AppiumBy.ANDROID_UIAUTOMATOR, value='new UiSelector().text("提交订单")').click()
if buy_btn == '预约抢票':
# 预约购票
driver.find_element(by=By.XPATH,
value='//android.widget.FrameLayout[@resource-id="cn.damai:id/trade_project_detail_purchase_status_bar_container_fl"]/android.widget.LinearLayout').click()
# 票价选择
if driver.find_elements(by=By.ID, value='project_detail_perform_price_flowlayout'):
for price in driver.find_elements(by=By.XPATH,
value='//android.widget.TextView[@resource-id="cn.damai:id/item_text"]'):
if config.price in price.text:
price.click()
# 提交
if driver.find_elements(by=By.ID, value='btn_buy_bottom_div_line'):
driver.find_element(by=By.XPATH,
value='//android.view.View[@resource-id="cn.damai:id/btn_buy_bottom_div_line"]/..').click()
if buy_btn == '已预约':
break
else:
# 模拟下拉刷新
driver.swipe(500, 400, 500, 2000, 300)
sleep(0.1)
driver.quit()

View File

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 47 KiB

View File

Before

Width:  |  Height:  |  Size: 357 KiB

After

Width:  |  Height:  |  Size: 357 KiB

View File

Before

Width:  |  Height:  |  Size: 481 KiB

After

Width:  |  Height:  |  Size: 481 KiB

View File

Before

Width:  |  Height:  |  Size: 253 KiB

After

Width:  |  Height:  |  Size: 253 KiB