├── .github └── workflows │ └── release.yml ├── .gitignore ├── LICENSE ├── README.md ├── config.txt ├── cookie.txt ├── main.py ├── requirements.txt ├── ticket_for_allcpp.spec └── timentp.py /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Python Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*' 7 | 8 | jobs: 9 | Windows-amd64: 10 | permissions: write-all 11 | runs-on: windows-latest 12 | name: Build Windows Binary 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@v4 16 | 17 | - name: Init Python 3.12 18 | uses: actions/setup-python@v4 19 | with: 20 | python-version: '3.12' 21 | cache: 'pip' 22 | 23 | - name: Install Dependent Packages 24 | run: | 25 | python -m pip install --upgrade pip 26 | pip install wheel pyinstaller 27 | pip install -r requirements.txt 28 | shell: pwsh 29 | 30 | - name: Pyinstaller 31 | run: | 32 | pyinstaller ticket_for_allcpp.spec 33 | shell: pwsh 34 | 35 | - name: Upload Windows File 36 | uses: actions/upload-artifact@v3 37 | with: 38 | name: ticket_for_allcpp-windows-amd64 39 | path: dist/ticket_for_allcpp.exe 40 | 41 | Linux-amd64: 42 | permissions: write-all 43 | runs-on: ubuntu-latest 44 | name: Build Linux Amd64 45 | steps: 46 | - name: Checkout 47 | uses: actions/checkout@v4 48 | 49 | - name: Init Python 3.12 50 | uses: actions/setup-python@v4 51 | with: 52 | python-version: '3.12' 53 | cache: 'pip' 54 | 55 | - name: Install Dependent Packages 56 | run: | 57 | python -m pip install --upgrade pip 58 | pip install wheel pyinstaller 59 | pip install -r requirements.txt 60 | 61 | - name: Pyinstaller 62 | run: | 63 | pyinstaller ticket_for_allcpp.spec 64 | mv dist/ticket_for_allcpp dist/ticket_for_allcpp-linux-amd64 65 | 66 | - name: Upload Linux File 67 | uses: actions/upload-artifact@v3 68 | with: 69 | name: ticket_for_allcpp-linux-amd64 70 | path: dist/ticket_for_allcpp-linux-amd64 71 | 72 | macos-amd64: 73 | permissions: write-all 74 | runs-on: macOS-latest 75 | name: Build macOS Amd64 76 | steps: 77 | - name: Checkout 78 | uses: actions/checkout@v4 79 | 80 | - name: Init Python 3.12 81 | uses: actions/setup-python@v4 82 | with: 83 | python-version: '3.12' 84 | cache: 'pip' 85 | 86 | - name: Install Dependent Packages 87 | run: | 88 | python -m pip install --upgrade pip 89 | pip install wheel pyinstaller 90 | pip install -r requirements.txt 91 | 92 | - name: Pyinstaller 93 | run: | 94 | pyinstaller ticket_for_allcpp.spec 95 | mv dist/ticket_for_allcpp dist/ticket_for_allcpp-macos-amd64 96 | 97 | - name: Upload macOS File 98 | uses: actions/upload-artifact@v3 99 | with: 100 | name: ticket_for_allcpp-macos-amd64 101 | path: dist/ticket_for_allcpp-macos-amd64 102 | 103 | Create-release: 104 | permissions: write-all 105 | runs-on: ubuntu-latest 106 | needs: [ Windows-amd64, Linux-amd64, macos-amd64] 107 | steps: 108 | - uses: actions/checkout@v4 109 | 110 | - name: Download Artifact 111 | uses: actions/download-artifact@v3 112 | 113 | - name: get release_informations 114 | shell: bash 115 | run: | 116 | mkdir releases 117 | mv ./ticket_for_allcpp-macos-amd64/ticket_for_allcpp-macos-amd64 ./releases/ticket_for_allcpp-macos-amd64 118 | mv ./ticket_for_allcpp-linux-amd64/ticket_for_allcpp-linux-amd64 ./releases/ticket_for_allcpp-linux-amd64 119 | mv ./ticket_for_allcpp-windows-amd64/ticket_for_allcpp.exe ./releases/ticket_for_allcpp-windows-amd64.exe 120 | cp config.txt ./releases/config.txt 121 | cp cookie.txt ./releases/cookie.txt 122 | 123 | - name: Create Release 124 | id: create_release 125 | uses: actions/create-release@latest 126 | env: 127 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 128 | with: 129 | tag_name: ${{ github.ref }} 130 | release_name: ${{ github.ref }} 131 | draft: false 132 | prerelease: false 133 | 134 | - name: Upload Release Asset 135 | uses: dwenegar/upload-release-assets@v1 136 | env: 137 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 138 | with: 139 | release_id: ${{ steps.create_release.outputs.id }} 140 | assets_path: | 141 | ./releases/ 142 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | dist/ 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Koileo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ticket_for_allcpp 2 | 3 | 开源免费,简单易用,多线程暴力 CPP 抢票工具。 4 | 5 | > [!NOTE] 6 | > 本程序仅供学习交流, 不得用于商业用途 7 | > 使用本程序进行违法操作产生的法律责任由操作者自行承担 8 | > 本次cp30最好使用b站会员购进行抢票,cp30有可能加入验证码,由于之前从未出现,我没办法在开票前保证程序可用性!!!!! 9 | 10 | ## 安装教程 11 | 12 | ### 1. 快速安装 13 | 14 | 前往 [Releases](https://github.com/Koileo/ticket_for_allcpp/releases) 下载最新可执行文件直接命令行运行。 15 | 16 | ### 2. 源码运行 17 | 18 | ```shell 19 | git clone https://github.com/Koileo/ticket_for_allcpp.git 20 | cd ticket_for_allcpp 21 | pip install -r requirements.txt 22 | python main.py 23 | ``` 24 | 25 | ## 使用说明 26 | 27 | ### cookie.txt 配置 28 | 29 | - 第一行为账号`cookie`值,浏览器登入CPP直接F12获取并全部复制即可。 30 | - 第二行为`ticketid`,同样也是F12查看 https://www.allcpp.cn/allcpp/ticket/getTicketTypeList.do?eventMainId=xxxx 的响应 一般为4位数字 31 | - 以此类推,第三行第四行也是这样 32 | 33 | ### config.txt 配置文件:包括ntp服务器,间隔时长,线程数 34 | 35 | - 本程序支持多线程,多账户(默认三线程)。 36 | - 默认实名票全部按照购票人设置数量购买,你绑定几个人买几份票,即默认全选 37 | - 同一账号支持同时购买不同票类,在第二行用“,"分开 38 | 39 | ## 其他可用脚本 40 | 41 | | 链接 | 主要特色 | 42 | | --------------------------------------------------------- | ---------------------- | 43 | | https://github.com/mikumifa/cppTickerBuy |图形化,对小白友好 | 44 | 45 | ## 未来功能 46 | 47 | - [ ] 微信通知 48 | - [x] 程序外部配置空隔时间和线程数 49 | - [x] Linux 和 MacOS 打包 50 | - [x] 时间校准 51 | 52 | ## 项目问题 53 | 54 | 反馈程序BUG或者提新功能建议:[点此链接向项目提出反馈BUG](https://github.com/Koileo/ticket_for_allcpp/issues) 55 | 56 | ## Star History 57 | 58 | [![Star History Chart](https://api.star-history.com/svg?repos=Koileo/ticket_for_allcpp&type=Date)](https://star-history.com/#Koileo/ticket_for_allcpp&Date) 59 | -------------------------------------------------------------------------------- /config.txt: -------------------------------------------------------------------------------- 1 | [time] 2 | ntp = ntp.aliyun.com 3 | 4 | [ticket] 5 | sleep = 1 6 | num_thread = 3 7 | -------------------------------------------------------------------------------- /cookie.txt: -------------------------------------------------------------------------------- 1 | 你的cookie 2 | ticketid -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | import requests 3 | import json 4 | import threading 5 | import time 6 | import secrets 7 | import string 8 | import hashlib 9 | import ntplib 10 | import configparser 11 | 12 | 13 | # 定义一个全局锁用于线程同步 14 | thread_dict = {} 15 | cookie_file_path = 'cookie.txt' 16 | config_file_path = 'config.txt' 17 | headers = { 18 | 'authority': 'www.allcpp.cn', 19 | 'accept': 'application/json, text/plain, */*', 20 | 'accept-language': 'zh-CN,zh;q=0.9', 21 | 'content-type': 'application/json;charset=UTF-8', 22 | 'origin': 'https://cp.allcpp.cn', 23 | 'referer': 'https://cp.allcpp.cn/', 24 | 'sec-ch-ua': '"Chromium";v="116", "Not)A;Brand";v="24", "Google Chrome";v="116"', 25 | 'sec-ch-ua-mobile': '?0', 26 | 'sec-ch-ua-platform': '"Windows"', 27 | 'sec-fetch-dest': 'empty', 28 | 'sec-fetch-mode': 'cors', 29 | 'sec-fetch-site': 'same-site', 30 | 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36', 31 | } 32 | 33 | 34 | # 读取配置文件 35 | def getConfig(filename, section, option): 36 | conf = configparser.ConfigParser() 37 | conf.read(filename) 38 | config = conf.get(section, option) 39 | return config 40 | 41 | 42 | def timeconvey(ntp): 43 | chec = ntplib.NTPClient() 44 | response = chec.request(ntp) 45 | timestamp = response.tx_time 46 | timestamp_local = time.time() 47 | #print(timestamp_local) 48 | #print(timestamp) 49 | differ= timestamp - timestamp_local 50 | return differ 51 | 52 | 53 | def sign_for_post(ticketid): 54 | timestamp = str(int(time.time())) ##"1682074579" 55 | ## 貌似并不校验 sign: a()(t + r + i + e + n) 56 | # nonce="jcFFFK4pPz2eNGBND3xDxTEyZ7PGCyzm" ## 32位随机值即可 57 | n = string.ascii_letters + string.digits 58 | nonce = ''.join(secrets.choice(n) for i in range(32)) 59 | sign=hashlib.md5(f"2x052A0A1u222{timestamp}{nonce}{ticketid}2sFRs".encode('utf-8')).hexdigest() 60 | # print(f"ticket_type_id={ticket_type_id}") 61 | # print(f"nonce={nonce}") 62 | # print(f"timestamp={timestamp}") 63 | # print(f"sign={sign}") 64 | vital='nonce='+nonce+'&timeStamp='+timestamp+'&sign='+sign 65 | return vital 66 | 67 | 68 | def cookie_string_to_dict(cookie_string): 69 | cookies = {} 70 | cookie_pairs = cookie_string.split("; ") 71 | 72 | for pair in cookie_pairs: 73 | key, value = pair.split("=", 1) 74 | cookies[key] = value 75 | 76 | return cookies 77 | 78 | 79 | def read_cookies_and_tickets_from_file(): 80 | cookies = [] 81 | ticket_id = [] 82 | ticket_ids = [] 83 | try: 84 | with open(cookie_file_path, 'r',encoding='utf-8') as file: 85 | lines = file.readlines() 86 | i = 0 87 | while i < len(lines): 88 | cookies.append(lines[i].strip()) # 使用append方法将元素添加到列表 89 | i += 1 90 | if i < len(lines): 91 | ticket_id.append(lines[i].strip()) # 使用append方法将元素添加到列表 92 | i += 1 93 | except FileNotFoundError: 94 | print(f"File '{cookie_file_path}' not found.") 95 | for item in ticket_id: 96 | # 使用逗号分割字符串并添加到输出列表 97 | ticket_ids.append(item.split(',')) 98 | return cookies, ticket_ids # 返回两个列表作为一个元组 99 | 100 | 101 | def getpurser(cookie_str): 102 | cookies = cookie_string_to_dict(cookie_str) 103 | pur = requests.get( 104 | url='https://www.allcpp.cn/allcpp/user/purchaser/getList.do', 105 | cookies=cookies, 106 | headers=headers, 107 | ) 108 | purrer = pur.content.decode("utf-8") 109 | purrer_data = json.loads(purrer) 110 | return purrer_data 111 | 112 | 113 | def check_success(cookies,ticketid): 114 | url = 'https://www.allcpp.cn/allcpp/user/getMyOrderList.do?pageindex=1&pagesize=10&enabled=0&orderby=0' 115 | list = requests.get( 116 | url=url, 117 | cookies=cookies, 118 | headers=headers, 119 | ) 120 | listing = list.content.decode("utf-8") 121 | data = json.loads(listing) 122 | # 遍历订单信息 123 | for order in data['result']['list']: 124 | if order['ticketTypeId'] == ticketid: 125 | return True 126 | else: 127 | return False 128 | 129 | 130 | def process_thread(ticketid,cookie_str): 131 | try: 132 | cookies = cookie_string_to_dict(cookie_str) 133 | try: 134 | pur = requests.get( 135 | url='https://www.allcpp.cn/allcpp/user/purchaser/getList.do', 136 | cookies=cookies, 137 | headers=headers, 138 | ) 139 | 140 | purrer = pur.content.decode("utf-8") 141 | purrer_data = json.loads(purrer) 142 | print(purrer_data) 143 | except json.decoder.JSONDecodeError as e: 144 | pass 145 | ids = [str(item["id"]) for item in purrer_data] 146 | ids_str = ",".join(ids) 147 | id_count = len(ids) 148 | print(f"IDs for ticket {ticketid}: {ids_str}") 149 | json_data = {} 150 | 151 | 152 | retn_params = sign_for_post(ticketid) 153 | url = 'https://www.allcpp.cn/allcpp/ticket/buyTicketAliWapPay.do?ticketTypeId=' + str(ticketid) + '&count=' + str( 154 | id_count) + '&' + retn_params + '&purchaserIds=' + ids_str 155 | print(url) 156 | try: 157 | response = requests.post( 158 | url=url, 159 | cookies=cookies, 160 | headers=headers, 161 | json=json_data, 162 | ) 163 | resp = response.content.decode("utf-8") 164 | parsed_resp = json.loads(resp) 165 | except json.decoder.JSONDecodeError as e: 166 | pass 167 | print(parsed_resp) 168 | except: 169 | pass 170 | 171 | i = 0 172 | if parsed_resp.get("isSuccess") == True: 173 | print(f"Thread for ticket {ticketid} succeeded") 174 | with open(f"output_ticket_{ticketid}_{ids_str}.txt", "a") as output_file: 175 | output_file.write(resp) 176 | print(f"Thread for ticket {ticketid} with cookies {cookies} succeeded, closing other two threads of the same type.") 177 | threads =[] 178 | threads_to_close = [thread for thread in threads if thread._target == process_thread and thread._args[0] == ticketid and thread._args[1] == cookies] 179 | for thread_to_close in threads_to_close[:2]: # 关闭同类型的前两个线程 180 | thread_to_close.join() 181 | return True 182 | else: 183 | while i < 2: 184 | try: 185 | with open(f"output_ticket_{ticketid}_{ids_str}_attempt_{i}.txt", "a") as output_file: 186 | output_file.write(resp) 187 | retn_params = sign_for_post(ticketid) 188 | url = 'https://www.allcpp.cn/allcpp/ticket/buyTicketAliWapPay.do?ticketTypeId=' + str(ticketid) + '&count=' + str( 189 | id_count) + '&' + retn_params +'&purchaserIds=' + ids_str 190 | print(url) 191 | try: 192 | response = requests.post( 193 | url=url, 194 | cookies=cookies, 195 | headers=headers, 196 | json=json_data, 197 | ) 198 | resp = response.content.decode("utf-8") 199 | parsed_resp = json.loads(resp) 200 | except json.decoder.JSONDecodeError as e: 201 | pass 202 | print(parsed_resp) 203 | is_success = parsed_resp["isSuccess"] 204 | if is_success == True: 205 | i = 3 206 | print(f"Thread for ticket {ticketid} succeeded") 207 | with open(f"output_ticket_{ticketid}_{ids_str}.txt", "a") as output_file: 208 | output_file.write(resp) 209 | threads_to_close = [thread for thread in threads if thread._target == process_thread and thread._args[0] == ticketid and thread._args[1] == cookies] 210 | for thread_to_close in threads_to_close[:2]: # 关闭同类型的前两个线程 211 | thread_to_close.join() 212 | return True 213 | else: 214 | with open(f"output_ticket_{ticketid}_{ids_str}_attempt.txt", "a") as output_file: 215 | output_file.write(resp) 216 | url = 'https://www.allcpp.cn/allcpp/ticket/buyTicketAliWapPay.do?ticketTypeId=' + str(ticketid) + '&count=' + str( 217 | id_count) + '&' + retn_params +'&purchaserIds=' + ids_str 218 | print(url) 219 | try: 220 | response = requests.post( 221 | url=url, 222 | cookies=cookies, 223 | headers=headers, 224 | json=json_data, 225 | ) 226 | resp = response.content.decode("utf-8") 227 | parsed_resp = json.loads(resp) 228 | is_success = parsed_resp["isSuccess"] 229 | except json.decoder.JSONDecodeError as e: 230 | pass 231 | if is_success == True: 232 | i = 3 233 | print(f"Thread for ticket {ticketid} succeeded") 234 | with open(f"output_ticket_{ticketid}_{ids_str}.txt", "a") as output_file: 235 | output_file.write(resp) 236 | threads_to_close = [thread for thread in threads if thread._target == process_thread and thread._args[0] == ticketid and thread._args[1] == cookies] 237 | for thread_to_close in threads_to_close[:2]: # 关闭同类型的前两个线程 238 | thread_to_close.join() 239 | return True 240 | else: 241 | with open(f"output_ticket_{ticketid}_{ids_str}_attempt.txt", "a") as output_file: 242 | output_file.write(resp) 243 | print(resp) 244 | print(type(resp)) 245 | time.sleep(sleep_time) 246 | except: 247 | pass 248 | 249 | 250 | def start(cookies, ticket_ids): 251 | thread_dict = {} 252 | 253 | for i in range(len(cookies)): 254 | for j in range(len(ticket_ids[i])): 255 | for _ in range(num_thread): 256 | ticket = ticket_ids[i][j] 257 | cook = cookies[i] 258 | thread = threading.Thread(target=process_thread, args=(ticket, cook)) 259 | thread.start() 260 | 261 | 262 | def schedule_script_at_timestamp(target_timestamp_ms,cookies, ticket_ids): 263 | current_timestamp_ms = int(time.time() * 1000) 264 | time_difference_ms = target_timestamp_ms - current_timestamp_ms 265 | 266 | if time_difference_ms <= 0: 267 | print("时间已经过去了主人") 268 | else: 269 | print(f"还有 {time_difference_ms / 1000} 秒喵~.") 270 | 271 | def delayed_execution(): 272 | time.sleep(time_difference_ms / 1000) 273 | start(cookies, ticket_ids) 274 | t = threading.Thread(target=delayed_execution) 275 | t.start() 276 | 277 | 278 | def main(): 279 | ntp = getConfig("config.txt", 'time', 'ntp') 280 | global sleep_time 281 | sleep_time = float(getConfig("config.txt", 'ticket', 'sleep')) 282 | global num_thread 283 | num_thread = int(getConfig("config.txt", 'ticket', 'num_thread')) 284 | 285 | differ = timeconvey(ntp) 286 | if differ > 0 : 287 | print(f"\033[1;31;47m主人你的时间慢了{abs(differ)}秒\033[0m") 288 | print("\033[1;31;47m主人你的时间滞后了哦,请同步时间\033[0m") 289 | else: 290 | print(f"\033[1;31;47m主人你的时间快了{abs(differ)}秒\033[0m") 291 | cookies, ticket_ids = read_cookies_and_tickets_from_file() 292 | print(ticket_ids) 293 | i=0 294 | while i