├── .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 | 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 | 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 | --------------------------------------------------------------------------------