├── .idea
├── .gitignore
├── vcs.xml
├── misc.xml
├── inspectionProfiles
│ ├── profiles_settings.xml
│ └── Project_Default.xml
├── modules.xml
└── piaoxingqiu.iml
├── README.md
├── __pycache__
├── config.cpython-311.pyc
└── request.cpython-311.pyc
├── config.py
├── main.py
└── request.py
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # piaoxingqiu
2 | 票星球自动抢票
3 |
4 | 1.配置config.py
5 | 2.运行main.py
6 |
--------------------------------------------------------------------------------
/__pycache__/config.cpython-311.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/senseek/piaoxingqiu/HEAD/__pycache__/config.cpython-311.pyc
--------------------------------------------------------------------------------
/__pycache__/request.cpython-311.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/senseek/piaoxingqiu/HEAD/__pycache__/request.cpython-311.pyc
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/piaoxingqiu.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/config.py:
--------------------------------------------------------------------------------
1 | # 输入自己的token
2 | token = 'your token'
3 | # 项目id,必填
4 | show_id = '644fcb2aca916100017dcfef'
5 | # 指定场次id,不指定则默认从第一场开始遍历
6 | session_id = '' # 644fcb7dca916100017dda3d
7 | # 购票数量,一定要看购票须知,不要超过上限
8 | buy_count = 2
9 | # 指定观演人,观演人序号从0开始,人数需与票数保持一致
10 | audience_idx = [0, 1]
11 | # 门票类型,不确定则可以不填,让系统自行判断。快递送票:EXPRESS,电子票:E_TICKET,现场取票:VENUE,电子票或现场取票:VENUE_E,目前只发现这四种,如有新发现可补充
12 | deliver_method = ''
13 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | import request
2 | import config
3 |
4 | '''
5 | 目前仅支持【无需选座】的项目
6 | '''
7 | show_id = config.show_id
8 | session_id = config.session_id
9 | buy_count = config.buy_count
10 | audience_idx = config.audience_idx
11 | deliver_method = config.deliver_method
12 | seat_plan_id = ''
13 | session_id_exclude = [] # 被排除掉的场次
14 | price = 0
15 |
16 | while True:
17 | try:
18 | # 如果没有指定场次,则默认从第一场开始刷
19 | if not session_id:
20 | # 如果项目不是在售状态就一直刷,直到变成在售状态拿到场次id,如果有多场,默认拿第一场
21 | while True:
22 | sessions = request.get_sessions(show_id)
23 | if sessions:
24 | for i in sessions:
25 | if i["sessionStatus"] == 'ON_SALE' and i["bizShowSessionId"] not in session_id_exclude:
26 | session_id = i["bizShowSessionId"]
27 | print("session_id:" + session_id)
28 | break
29 | if session_id:
30 | break
31 | else:
32 | print("未获取到在售状态且符合购票数量需求的session_id")
33 | session_id_exclude = [] # 再给自己一次机会,万一被排除掉的场次又放票了呢
34 | # 获取座位余票信息,默认从最低价开始
35 | seat_plans = request.get_seat_plans(show_id, session_id)
36 | seat_count = request.get_seat_count(show_id, session_id)
37 | print(seat_count)
38 |
39 | for i in seat_count:
40 | if i["canBuyCount"] >= buy_count:
41 | seat_plan_id = i["seatPlanId"]
42 | for j in seat_plans:
43 | if j["seatPlanId"] == seat_plan_id:
44 | price = j["originalPrice"] # 门票单价
45 | break
46 | break
47 | # 如果没有拿到seat_plan_id,说明该场次所有座位的余票都不满足购票数量需求,就重新开始刷下一场次
48 | if not seat_plan_id:
49 | print("该场次" + session_id + "没有符合条件的座位,将为你继续搜寻其他在售场次")
50 | session_id_exclude.append(session_id) # 排除掉这个场次
51 | session_id = ''
52 | continue
53 |
54 | if not deliver_method:
55 | deliver_method = request.get_deliver_method(show_id, session_id, seat_plan_id, price, buy_count)
56 | print("deliver_method:" + deliver_method)
57 |
58 | if deliver_method == "VENUE_E":
59 | request.create_order(show_id, session_id, seat_plan_id, price, buy_count, deliver_method, 0, None,
60 | None, None, None, None, [])
61 | else:
62 | # 获取观演人信息
63 | audiences = request.get_audiences()
64 | if len(audience_idx) == 0:
65 | audience_idx = range(buy_count)
66 | audience_ids = [audiences[i]["id"] for i in audience_idx]
67 |
68 | if deliver_method == "EXPRESS":
69 | # 获取默认收货地址
70 | address = request.get_address()
71 | address_id = address["addressId"] # 地址id
72 | location_city_id = address["locationId"] # 460102
73 | receiver = address["username"] # 收件人
74 | cellphone = address["cellphone"] # 电话
75 | detail_address = address["detailAddress"] # 详细地址
76 |
77 | # 获取快递费用
78 | express_fee = request.get_express_fee(show_id, session_id, seat_plan_id, price, buy_count,
79 | location_city_id)
80 |
81 | # 下单
82 | request.create_order(show_id, session_id, seat_plan_id, price, buy_count, deliver_method,
83 | express_fee["priceItemVal"], receiver,
84 | cellphone, address_id, detail_address, location_city_id, audience_ids)
85 | elif deliver_method == "VENUE" or deliver_method == "E_TICKET":
86 | request.create_order(show_id, session_id, seat_plan_id, price, buy_count, deliver_method, 0, None,
87 | None, None, None, None, audience_ids)
88 | else:
89 | print("不支持的deliver_method:" + deliver_method)
90 | break
91 | except Exception as e:
92 | print(e)
93 | session_id_exclude.append(session_id) # 排除掉这个场次
94 | session_id = ''
95 |
96 |
--------------------------------------------------------------------------------
/request.py:
--------------------------------------------------------------------------------
1 | import requests
2 |
3 | from config import token
4 |
5 |
6 | # 根据项目id获取所有场次和在售状态
7 | def get_sessions(show_id) -> list | None:
8 | headers = {
9 | 'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Mobile Safari/537.36',
10 | 'Content-Type': 'application/json'
11 | }
12 | url = "https://m.piaoxingqiu.com/cyy_gatewayapi/show/pub/v3/show/" + show_id + "/sessions_dynamic_data"
13 | response = requests.get(url=url, headers=headers).json()
14 | if response["statusCode"] == 200:
15 | return response["data"]["sessionVOs"]
16 | else:
17 | print("get_sessions异常:" + str(response))
18 | return None
19 |
20 |
21 | # 根据场次id获取座位信息
22 | def get_seat_plans(show_id, session_id) -> list:
23 | headers = {
24 | 'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Mobile Safari/537.36',
25 | 'Content-Type': 'application/json'
26 | }
27 | url = "https://m.piaoxingqiu.com/cyy_gatewayapi/show/pub/v3/show/" + show_id + "/show_session/" + session_id + "/seat_plans_static_data"
28 | response = requests.get(url=url, headers=headers).json()
29 | if response["statusCode"] == 200:
30 | return response["data"]["seatPlans"]
31 | else:
32 | raise Exception("get_seat_plans异常:" + str(response))
33 |
34 |
35 | # 获取座位余票
36 | def get_seat_count(show_id, session_id) -> list:
37 | headers = {
38 | 'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Mobile Safari/537.36',
39 | 'Content-Type': 'application/json'
40 | }
41 | url = "https://m.piaoxingqiu.com/cyy_gatewayapi/show/pub/v3/show/" + show_id + "/show_session/" + session_id + "/seat_plans_dynamic_data"
42 | response = requests.get(url=url, headers=headers).json()
43 | if response["statusCode"] == 200:
44 | return response["data"]["seatPlans"]
45 | else:
46 | raise Exception("get_seat_count异常:" + str(response))
47 |
48 |
49 | # 获取门票类型(快递送票EXPRESS,电子票E_TICKET,现场取票VENUE,电子票或现场取票VENUE_E)
50 | def get_deliver_method(show_id, session_id, seat_plan_id, price: int, qty: int) -> str:
51 | headers = {
52 | 'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Mobile Safari/537.36',
53 | 'Content-Type': 'application/json',
54 | 'access-token': token
55 | }
56 | data = {
57 | "items": [
58 | {
59 | "skus": [
60 | {
61 | "seatPlanId": seat_plan_id, # 644fcf080f4f4e0001f1519d
62 | "sessionId": session_id, # 644fcb7dca916100017dda3d
63 | "showId": show_id, # 644fcb2aca916100017dcfef
64 | "skuId": seat_plan_id,
65 | "skuType": "SINGLE",
66 | "ticketPrice": price, # 388
67 | "qty": qty # 2
68 | }
69 | ],
70 | "spu": {
71 | "id": show_id,
72 | "spuType": "SINGLE"
73 | }
74 | }
75 | ]
76 | }
77 | url = "https://m.piaoxingqiu.com/cyy_gatewayapi/trade/buyer/order/v3/pre_order"
78 | response = requests.post(url=url, headers=headers, json=data).json()
79 | if response["statusCode"] == 200:
80 | return response["data"]["supportDeliveries"][0]["name"]
81 | else:
82 | raise Exception("获取门票类型异常:" + str(response))
83 |
84 |
85 | # 获取观演人信息
86 | def get_audiences() -> list | None:
87 | headers = {
88 | 'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Mobile Safari/537.36',
89 | 'Content-Type': 'application/json',
90 | 'access-token': token
91 | }
92 | url = "https://m.piaoxingqiu.com/cyy_gatewayapi/user/buyer/v3/user_audiences"
93 | response = requests.get(url=url, headers=headers).json()
94 | if response["statusCode"] == 200:
95 | return response["data"]
96 | else:
97 | print("get_audiences异常:" + str(response))
98 | return None
99 |
100 |
101 | # 获取收货地址
102 | def get_address() -> dict | None:
103 | headers = {
104 | 'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Mobile Safari/537.36',
105 | 'Content-Type': 'application/json',
106 | 'access-token': token
107 | }
108 | url = "https://m.piaoxingqiu.com/cyy_gatewayapi/user/buyer/v3/user/addresses/default"
109 | response = requests.get(url=url, headers=headers).json()
110 | if response["statusCode"] == 200:
111 | return response["data"]
112 | else:
113 | print("get_address异常:" + str(response))
114 | return None
115 |
116 |
117 | # 获取快递费
118 | def get_express_fee(show_id, session_id, seat_plan_id, price: int, qty: int, location_city_id: str) -> dict:
119 | headers = {
120 | 'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Mobile Safari/537.36',
121 | 'Content-Type': 'application/json',
122 | 'access-token': token
123 | }
124 | data = {
125 | "items": [
126 | {
127 | "skus": [
128 | {
129 | "seatPlanId": seat_plan_id, # 644fcf080f4f4e0001f1519d
130 | "sessionId": session_id, # 644fcb7dca916100017dda3d
131 | "showId": show_id, # 644fcb2aca916100017dcfef
132 | "skuId": seat_plan_id,
133 | "skuType": "SINGLE",
134 | "ticketPrice": price, # 388
135 | "qty": qty, # 2
136 | "deliverMethod": "EXPRESS"
137 | }
138 | ],
139 | "spu": {
140 | "id": show_id,
141 | "spuType": "SINGLE"
142 | }
143 | }
144 | ],
145 | "locationCityId": location_city_id # 460102
146 | }
147 | url = "https://m.piaoxingqiu.com/cyy_gatewayapi/trade/buyer/order/v3/price_items"
148 | response = requests.post(url=url, headers=headers, json=data).json()
149 | if response["statusCode"] == 200:
150 | return response["data"][0]
151 | else:
152 | raise Exception("获取快递费异常:" + str(response))
153 |
154 |
155 | # 提交订单(快递送票EXPRESS,电子票E_TICKET,现场取票VENUE,电子票或现场取票VENUE_E)
156 | def create_order(show_id, session_id, seat_plan_id, price: int, qty: int, deliver_method, express_fee: int, receiver,
157 | cellphone,
158 | address_id, detail_address, location_city_id, audience_ids: list):
159 | headers = {
160 | 'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Mobile Safari/537.36',
161 | 'Content-Type': 'application/json',
162 | 'access-token': token
163 | }
164 | if deliver_method == "EXPRESS":
165 | data = {
166 | "priceItemParam": [
167 | {
168 | "applyTickets": [],
169 | "priceItemName": "票款总额",
170 | "priceItemVal": price * qty,
171 | "priceItemType": "TICKET_FEE",
172 | "priceItemSpecies": "SEAT_PLAN",
173 | "direction": "INCREASE",
174 | "priceDisplay": "¥" + str(price * qty)
175 | },
176 | {
177 | "applyTickets": [],
178 | "priceItemName": "快递费",
179 | "priceItemVal": express_fee,
180 | "priceItemId": show_id,
181 | "priceItemSpecies": "SEAT_PLAN",
182 | "priceItemType": "EXPRESS_FEE",
183 | "direction": "INCREASE",
184 | "priceDisplay": "¥" + str(express_fee)
185 | }
186 | ],
187 | "items": [
188 | {
189 | "skus": [
190 | {
191 | "seatPlanId": seat_plan_id,
192 | "sessionId": session_id,
193 | "showId": show_id,
194 | "skuId": seat_plan_id,
195 | "skuType": "SINGLE",
196 | "ticketPrice": price,
197 | "qty": qty,
198 | "deliverMethod": deliver_method
199 | }
200 | ],
201 | "spu": {
202 | "id": show_id,
203 | "spuType": "SINGLE"
204 | }
205 | }
206 | ],
207 | "contactParam": {
208 | "receiver": receiver, # 张三
209 | "cellphone": cellphone # 13812345678
210 | },
211 |
212 | "one2oneAudiences": [{"audienceId": i, "sessionId": session_id} for i in audience_ids],
213 | "addressParam": {
214 | "address": detail_address, # 星巴克咖啡门口
215 | "district": location_city_id[4:],
216 | "city": location_city_id[2:4],
217 | "province": location_city_id[0:2],
218 | "addressId": address_id
219 | }
220 | }
221 | elif deliver_method == "E_TICKET":
222 | data = {
223 | "priceItemParam": [
224 | {
225 | "applyTickets": [],
226 | "priceItemName": "票款总额",
227 | "priceItemVal": price * qty,
228 | "priceItemType": "TICKET_FEE",
229 | "priceItemSpecies": "SEAT_PLAN",
230 | "direction": "INCREASE",
231 | "priceDisplay": "¥" + str(price * qty)
232 | }
233 | ],
234 | "items": [
235 | {
236 | "skus": [
237 | {
238 | "seatPlanId": seat_plan_id,
239 | "sessionId": session_id,
240 | "showId": show_id,
241 | "skuId": seat_plan_id,
242 | "skuType": "SINGLE",
243 | "ticketPrice": price,
244 | "qty": qty,
245 | "deliverMethod": deliver_method
246 | }
247 | ],
248 | "spu": {
249 | "id": show_id,
250 | "spuType": "SINGLE"
251 | }
252 | }
253 | ],
254 | "many2OneAudience": {
255 | "audienceId": audience_ids[0],
256 | "sessionIds": [
257 | session_id
258 | ]
259 | }
260 | }
261 | elif deliver_method == "VENUE":
262 | data = {
263 | "priceItemParam": [
264 | {
265 | "applyTickets": [],
266 | "priceItemName": "票款总额",
267 | "priceItemVal": price * qty,
268 | "priceItemType": "TICKET_FEE",
269 | "priceItemSpecies": "SEAT_PLAN",
270 | "direction": "INCREASE",
271 | "priceDisplay": "¥" + str(price * qty)
272 | }
273 | ],
274 | "items": [
275 | {
276 | "skus": [
277 | {
278 | "seatPlanId": seat_plan_id,
279 | "sessionId": session_id,
280 | "showId": show_id,
281 | "skuId": seat_plan_id,
282 | "skuType": "SINGLE",
283 | "ticketPrice": price,
284 | "qty": qty,
285 | "deliverMethod": deliver_method
286 | }
287 | ],
288 | "spu": {
289 | "id": show_id,
290 | "spuType": "SINGLE"
291 | }
292 | }
293 | ],
294 | "one2oneAudiences": [{"audienceId": i, "sessionId": session_id} for i in audience_ids]
295 | }
296 | elif deliver_method == "VENUE_E":
297 | data = {
298 | "priceItemParam": [
299 | {
300 | "applyTickets": [],
301 | "priceItemName": "票款总额",
302 | "priceItemVal": price * qty,
303 | "priceItemType": "TICKET_FEE",
304 | "priceItemSpecies": "SEAT_PLAN",
305 | "direction": "INCREASE",
306 | "priceDisplay": "¥" + str(price * qty)
307 | }
308 | ],
309 | "items": [
310 | {
311 | "skus": [
312 | {
313 | "seatPlanId": seat_plan_id,
314 | "sessionId": session_id,
315 | "showId": show_id,
316 | "skuId": seat_plan_id,
317 | "skuType": "SINGLE",
318 | "ticketPrice": price,
319 | "qty": qty,
320 | "deliverMethod": deliver_method
321 | }
322 | ],
323 | "spu": {
324 | "id": show_id,
325 | "spuType": "SINGLE"
326 | }
327 | }
328 | ]
329 | }
330 | else:
331 | raise Exception("不支持的deliver_method:" + str(deliver_method))
332 |
333 | url = "https://m.piaoxingqiu.com/cyy_gatewayapi/trade/buyer/order/v3/create_order"
334 | response = requests.post(url=url, headers=headers, json=data).json()
335 | if response["statusCode"] == 200:
336 | print("下单成功!请尽快支付!")
337 | else:
338 | raise Exception("下单异常:" + str(response))
339 |
--------------------------------------------------------------------------------