├── Console Version ├── JDAutoBuyTool.py ├── Please fill out this document.txt ├── Please fill out this document.txt.old ├── __pycache__ │ ├── JDAutoBuyTool.cpython-37.pyc │ ├── JDAutoBuyTool.cpython-38.pyc │ ├── my_test.cpython-37.pyc │ └── test.cpython-37.pyc ├── jQuery3078854.dat ├── jQuery3078854.txt ├── jdAutoBuyGood.log ├── my_test.py ├── requirements.txt ├── test.py └── test2.py ├── GUI Version ├── autobuy.py ├── image │ ├── down.png │ ├── left.png │ └── right.png ├── jdAutoBuyGood.log ├── qr.png └── window.qss ├── LICENSE ├── README.md └── assets ├── 1580963259089.png ├── 1580963623908.png ├── 1581038258274.png ├── 1581218076866.png ├── 1581218537205.png ├── 1581249279630.png ├── 1581508416184.png ├── 1581508444771.png ├── 1581768204211.png ├── 1581768213048.png └── 1583151909197.png /Console Version/JDAutoBuyTool.py: -------------------------------------------------------------------------------- 1 | # -*- coding=utf-8 -*- 2 | import requests 3 | import logging 4 | import logging.handlers 5 | import time 6 | import json 7 | import sys 8 | import random 9 | from bs4 import BeautifulSoup 10 | import smtplib 11 | import re 12 | import getpass,socket 13 | from email.mime.text import MIMEText 14 | from email.header import Header 15 | 16 | import traceback 17 | 18 | 19 | def setLogger(logFileName, logger): 20 | """ 创建日志文件 21 | 22 | 23 | """ 24 | logger.setLevel(logging.INFO)#在logger这个记录器上记录info级别的消息 25 | formatter = logging.Formatter('%(asctime)s %(levelname)s: %(message)s') 26 | 27 | console_handler = logging.StreamHandler() #返回日志记录流,这里是输出在终端上 28 | console_handler.setFormatter(formatter) 29 | logger.addHandler(console_handler) 30 | 31 | # 打开指定的文件并将其用作日志记录流 32 | file_handler = logging.handlers.RotatingFileHandler( 33 | logFileName, maxBytes=10485760, backupCount=5, encoding="utf-8") 34 | file_handler.setFormatter(formatter) 35 | logger.addHandler(file_handler) 36 | 37 | 38 | def sendMail(url, isOrder, sendTo): 39 | if len(sendTo) == 0 or sendTo == '$$$$$$$@qq.com': 40 | return 41 | 42 | mailRe = re.compile('^\w{1,15}@\w{1,10}\.(com|cn|net)$') 43 | if not re.search(mailRe, sendTo): 44 | return 45 | 46 | sendFrom = '645064582@qq.com' 47 | 48 | smtp_server = 'smtp.qq.com' 49 | if isOrder: 50 | msg = MIMEText(url + ' 商品已下单, 请在尽快付款', 'plain', 'utf-8') 51 | else: 52 | msg = MIMEText(url + ' 商品下单失败.', 'plain', 'utf-8') 53 | 54 | msg['From'] = Header(sendFrom) 55 | msg['To'] = Header(sendTo) 56 | msg['Subject'] = Header('买到啦') 57 | 58 | server = smtplib.SMTP_SSL(host=smtp_server) 59 | server.connect(smtp_server, 465) 60 | server.login(sendFrom, 'nkrzicfjkzznbehi') 61 | server.sendmail(sendFrom, sendTo, msg.as_string()) 62 | server.quit() 63 | 64 | 65 | def sendError(sendTo): 66 | if len(sendTo) == 0 or sendTo == '$$$$$$$@qq.com': 67 | return 68 | 69 | mailRe = re.compile('^\w{1,15}@\w{1,10}\.(com|cn|net)$') 70 | if not re.search(mailRe, sendTo): 71 | return 72 | 73 | sendFrom = '841915343@qq.com' 74 | username = getpass.getuser() 75 | hostname = socket.gethostname() 76 | 77 | # 发信服务器 78 | smtp_server = 'smtp.qq.com' 79 | # 邮箱正文内容, 第一个参数为内容, 第二个参数为格式(plain 为纯文本), 第三个参数为编码 80 | msg = MIMEText('main()函数出错嘞!(from {}.{})\n程序运行时间:{}'.format(hostname,username,time.asctime()), 'plain', 'utf-8') 81 | 82 | # 邮件头信息 83 | msg['From'] = Header(sendFrom) 84 | msg['To'] = Header(sendTo) 85 | msg['Subject'] = Header('ERROR!') 86 | # 开启发信服务, 加密传输 87 | server = smtplib.SMTP_SSL(host=smtp_server) 88 | server.connect(smtp_server, 465) 89 | server.login(sendFrom, 'hqxzxgownfyabfib') #邮箱授权码 90 | server.sendmail(sendFrom, sendTo, msg.as_string()) 91 | server.quit() 92 | 93 | 94 | def get_tag_value(tag, key='', index=0): 95 | if key: 96 | value = tag[index].get(key) 97 | else: 98 | value = tag[index].text 99 | return value.strip(' \t\r\n') 100 | 101 | 102 | def responseStatus(resp): 103 | if resp.status_code != requests.codes.OK: 104 | print('Status: %u, Url: %s' % (resp.status_code, resp.url)) 105 | return False 106 | return True 107 | def validateCookies(logger, session): 108 | """ 验证cookies并尝试登陆 """ 109 | for flag in range(1, 3): 110 | try: 111 | targetURL = 'https://order.jd.com/center/list.action' #这是京东订单页面 112 | payload = { 113 | 'rid': str(int(time.time() * 1000)) #时间戳 114 | } 115 | resp = session.get(url=targetURL, params=payload, allow_redirects=False) 116 | if resp.status_code == requests.codes.OK: 117 | logger.info('登录成功!') 118 | return True 119 | else: 120 | logger.info('第[%s]次请重新获取cookie...', flag) 121 | time.sleep(5) 122 | continue 123 | except Exception as e: 124 | logger.info('第[%s]次请重新获取cookie...', flag) 125 | time.sleep(5) 126 | continue 127 | 128 | 129 | def getUsername(logger, session): 130 | userName_Url = 'https://passport.jd.com/new/helloService.ashx?callback=jQuery339448&_=' + str( 131 | int(time.time() * 1000)) 132 | session.headers = { 133 | "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36", 134 | "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", 135 | "Referer": "https://order.jd.com/center/list.action", 136 | "Connection": "keep-alive" 137 | } 138 | resp = session.get(url=userName_Url, allow_redirects=True) 139 | resultText = resp.text 140 | resultText = resultText.replace('jQuery339448(', '') 141 | resultText = resultText.replace(')', '') 142 | usernameJson = json.loads(resultText) 143 | logger.info('登录账号名称: ' + usernameJson['nick']) 144 | 145 | 146 | def cancelSelectCartItem(session): 147 | url = "https://cart.jd.com/cancelAllItem.action" 148 | data = { 149 | 't': 0, 150 | 'outSkus': '', 151 | 'random': random.random() 152 | } 153 | resp = session.post(url, data=data) 154 | if resp.status_code != requests.codes.OK: 155 | print('Status: %u, Url: %s' % (resp.status_code, resp.url)) 156 | return False 157 | return True 158 | 159 | def cart_detail(session, logger, isOutput=False): 160 | url = 'https://cart.jd.com/cart.action' 161 | headers = { 162 | "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36", 163 | "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", 164 | "Referer": "https://order.jd.com/center/list.action", 165 | "Host": "cart.jd.com", 166 | "Connection": "keep-alive" 167 | } 168 | resp = session.get(url, headers=headers) 169 | soup = BeautifulSoup(resp.text, "html.parser") 170 | 171 | cartDetail = dict() 172 | for item in soup.find_all(class_='item-item'): 173 | sku_id = item['skuid'] # 商品id 174 | try: 175 | # 例如: ['increment', '8888', '100001071956', '1', '13', '0', '50067652554'] 176 | # ['increment', '8888', '100002404322', '2', '1', '0'] 177 | item_attr_list = item.find(class_='increment')['id'].split('_') 178 | p_type = item_attr_list[4] 179 | promo_id = target_id = item_attr_list[-1] if len(item_attr_list) == 7 else 0 180 | 181 | cartDetail[sku_id] = { 182 | 'name': get_tag_value(item.select('div.p-name a')), # 商品名称 183 | 'verder_id': item['venderid'], # 商家id 184 | 'count': int(item['num']), # 数量 185 | 'unit_price': get_tag_value(item.select('div.p-price strong'))[1:], # 单价 186 | 'total_price': get_tag_value(item.select('div.p-sum strong'))[1:], # 总价 187 | 'is_selected': 'item-selected' in item['class'], # 商品是否被勾选 188 | 'p_type': p_type, 189 | 'target_id': target_id, 190 | 'promo_id': promo_id 191 | } 192 | except Exception as e: 193 | logger.error("商品%s在购物车中的信息无法解析, 报错信息: %s, 该商品自动忽略", sku_id, e) 194 | 195 | if isOutput == True: 196 | logger.info('当前购物车信息: %s', cartDetail) 197 | return cartDetail 198 | 199 | def change_item_num_in_cart(sku_id, vender_id, num, p_type, target_id, promo_id, session): 200 | url = "https://cart.jd.com/changeNum.action" 201 | data = { 202 | 't': 0, 203 | 'venderId': vender_id, 204 | 'pid': sku_id, 205 | 'pcount': num, 206 | 'ptype': p_type, 207 | 'targetId': target_id, 208 | 'promoID': promo_id, 209 | 'outSkus': '', 210 | 'random': random.random(), 211 | # 'locationId' 212 | } 213 | session.headers = { 214 | "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36", 215 | "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", 216 | "Referer": "https://cart.jd.com/cart", 217 | "Connection": "keep-alive" 218 | } 219 | resp = session.post(url, data=data) 220 | return json.loads(resp.text)['sortedWebCartResult']['achieveSevenState'] == 2 221 | 222 | 223 | def addItemToCart(sku_id, session, logger): 224 | url = 'https://cart.jd.com/gate.action' 225 | payload = { 226 | 'pid': sku_id, 227 | 'pcount': 1, 228 | 'ptype': 1, 229 | } 230 | resp = session.get(url=url, params=payload) 231 | if 'https://cart.jd.com/cart.action' in resp.url: # 套装商品加入购物车后直接跳转到购物车页面 232 | result = True 233 | else: # 普通商品成功加入购物车后会跳转到提示 "商品已成功加入购物车!" 页面 234 | soup = BeautifulSoup(resp.text, "html.parser") 235 | result = bool(soup.select('h3.ftx-02')) # [

商品已成功加入购物车!

] 236 | 237 | if result: 238 | logger.info('%s 已成功加入购物车', sku_id) 239 | else: 240 | logger.error('%s 添加到购物车失败', sku_id) 241 | 242 | 243 | def get_checkout_page_detail(session, logger): 244 | url = 'http://trade.jd.com/shopping/order/getOrderInfo.action' 245 | # url = 'https://cart.jd.com/gotoOrder.action' 246 | payload = { 247 | 'rid': str(int(time.time() * 1000)), 248 | } 249 | headers = { 250 | "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36", 251 | "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", 252 | "Referer": "https://cart.jd.com/cart.action", 253 | "Connection": "keep-alive", 254 | 'Host': 'trade.jd.com', 255 | } 256 | try: 257 | resp = session.get(url=url, params=payload, headers=headers) 258 | if not responseStatus(resp): 259 | logger.error('获取订单结算页信息失败') 260 | return '' 261 | 262 | soup = BeautifulSoup(resp.text, "html.parser") 263 | risk_control = get_tag_value(soup.select('input#riskControl'), 'value') 264 | 265 | order_detail = { 266 | 'address': soup.find('span', id='sendAddr').text[5:], # remove '寄送至: ' from the begin 267 | 'receiver': soup.find('span', id='sendMobile').text[4:], # remove '收件人:' from the begin 268 | 'total_price': soup.find('span', id='sumPayPriceId').text[1:], # remove '¥' from the begin 269 | 'items': [] 270 | } 271 | 272 | logger.info("下单信息: %s", order_detail) 273 | return order_detail 274 | except requests.exceptions.RequestException as e: 275 | logger.error('订单结算页面获取异常: %s' % e) 276 | except Exception as e: 277 | logger.error('下单页面数据解析异常: %s', e) 278 | return None 279 | 280 | 281 | def submit_order(risk_control, session, logger, payment_pwd): 282 | url = 'https://trade.jd.com/shopping/order/submitOrder.action' 283 | # js function of submit order is included in https://trade.jd.com/shopping/misc/js/order.js?r=2018070403091 284 | 285 | # overseaPurchaseCookies: 286 | # vendorRemarks: [] 287 | # submitOrderParam.sopNotPutInvoice: false 288 | # submitOrderParam.trackID: TestTrackId 289 | # submitOrderParam.ignorePriceChange: 0 290 | # submitOrderParam.btSupport: 0 291 | # riskControl: 292 | # submitOrderParam.isBestCoupon: 1 293 | # submitOrderParam.jxj: 1 294 | # submitOrderParam.trackId: 295 | 296 | data = { 297 | 'overseaPurchaseCookies': '', 298 | 'vendorRemarks': '[]', 299 | 'submitOrderParam.sopNotPutInvoice': 'false', 300 | 'submitOrderParam.trackID': 'TestTrackId', 301 | 'submitOrderParam.ignorePriceChange': '0', 302 | 'submitOrderParam.btSupport': '0', 303 | 'riskControl': risk_control, 304 | 'submitOrderParam.isBestCoupon': 1, 305 | 'submitOrderParam.jxj': 1, 306 | 'submitOrderParam.trackId': '9643cbd55bbbe103eef18a213e069eb0', # Todo: need to get trackId 307 | # 'submitOrderParam.eid': eid, 308 | # 'submitOrderParam.fp': fp, 309 | 'submitOrderParam.needCheck': 1, 310 | } 311 | 312 | def encrypt_payment_pwd(paymentPwd): 313 | return ''.join(['u3' + x for x in paymentPwd]) 314 | 315 | if len(payment_pwd) > 0: 316 | data['submitOrderParam.payPassword'] = encrypt_payment_pwd(payment_pwd) 317 | 318 | headers = { 319 | "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36", 320 | "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", 321 | "Referer": "http://trade.jd.com/shopping/order/getOrderInfo.action", 322 | "Connection": "keep-alive", 323 | 'Host': 'trade.jd.com', 324 | } 325 | 326 | try: 327 | resp = session.post(url=url, data=data, headers=headers) 328 | resp_json = json.loads(resp.text) 329 | 330 | if resp_json.get('success'): 331 | logger.info('订单提交成功! 订单号: %s', resp_json.get('orderId')) 332 | return True 333 | else: 334 | message, result_code = resp_json.get('message'), resp_json.get('resultCode') 335 | if result_code == 0: 336 | # self._save_invoice() 337 | message = message + '(下单商品可能为第三方商品, 将切换为普通发票进行尝试)' 338 | elif result_code == 60077: 339 | message = message + '(可能是购物车为空或未勾选购物车中商品)' 340 | elif result_code == 60123: 341 | message = message + '(未配置支付密码)' 342 | logger.info('订单提交失败, 错误码: %s, 返回信息: %s', result_code, message) 343 | logger.info(resp_json) 344 | return False 345 | except Exception as e: 346 | logger.error(e) 347 | return False 348 | 349 | 350 | def item_removed(sku_id): 351 | """ 352 | 判断商品是否下架,若商品未下架,返回真 353 | """ 354 | headers = { 355 | "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36", 356 | "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", 357 | "Referer": "http://trade.jd.com/shopping/order/getOrderInfo.action", 358 | "Connection": "keep-alive", 359 | 'Host': 'trade.jd.com', 360 | } 361 | url = 'https://item.jd.com/{}.html'.format(sku_id) 362 | page = requests.get(url=url, headers=headers) 363 | return '该商品已下柜' not in page.text 364 | 365 | 366 | def buyGood(sku_id, session, logger, payment_pwd): 367 | for count in range(1, 5): 368 | logger.info('第[%s/%s]次尝试提交订单', count, 5) 369 | cancelSelectCartItem(session) 370 | cart = cart_detail(session, logger) 371 | if sku_id not in cart: 372 | addItemToCart(sku_id, session, logger) 373 | cart_detail(session, logger, True) 374 | 375 | risk_control = get_checkout_page_detail(session, logger) 376 | if len(risk_control) > 0: 377 | if submit_order(risk_control, session, logger, payment_pwd): 378 | return True 379 | logger.info('等待%ss', 3) 380 | time.sleep(3) 381 | else: 382 | logger.info('执行结束, 提交订单失败!') 383 | return False 384 | 385 | def main(sendTo, cookies_String, url): 386 | print("main函数开始运行!") 387 | session = requests.session() 388 | session.headers = { 389 | "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36", 390 | "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=1.8,application/signed-exchange;v=b3", 391 | "Connection": "keep-alive" 392 | } 393 | 394 | logFileName = 'jdAutoBuyGood.log' 395 | logger = logging.getLogger() 396 | setLogger(logFileName, logger) 397 | 398 | manual_cookies = {} 399 | for item in cookies_String.split(';'): 400 | # 用=号分割. 401 | name, value = item.strip().split('=', 1) 402 | manual_cookies[name] = value 403 | # if __name__ == "__main__": 404 | # print("manual_cookies = \n",manual_cookies) 405 | cookiesJar = requests.utils.cookiejar_from_dict(manual_cookies, cookiejar=None, overwrite=True) 406 | session.cookies = cookiesJar 407 | # if __name__ == "__main__": 408 | # print("session.cookies = \n",session.cookies) 409 | # print("manual_coolies = {}\n".format(manual_cookies)) 410 | # sys.exit("测试结束!") 411 | 412 | payment_pwd = '' 413 | flag = 1 414 | while (1): 415 | try: 416 | if flag == 1: 417 | validateCookies(logger, session) 418 | getUsername(logger, session) 419 | checkSession = requests.Session() 420 | checkSession.headers = { 421 | "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36", 422 | "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", 423 | "Connection": "keep-alive" 424 | } 425 | logger.info('第' + str(flag) + '次 查询...') 426 | flag += 1 427 | for i in url: 428 | # 商品url,skuid是商品编号 429 | skuId = i.split('skuIds=')[1].split('%2C')[2] 430 | skuidUrl = 'https://item.jd.com/' + skuId + '.html' 431 | response = checkSession.get(i) 432 | #一个商品url中实际上有一种商品的多种不同规格的货号 433 | tmp = response.text.split(str(skuId))[1] 434 | m = tmp.find('{') 435 | n = tmp.find('}') 436 | tmp = tmp[m:n+1] 437 | # print(skuId,tmp) 438 | # sys.exit('测试结束!') 439 | if (tmp.find('无货') > 0): 440 | logger.info('[%s]商品无货.', skuId) 441 | else: 442 | if item_removed(skuId): 443 | logger.info('[%s]商品有货啦! 马上下单...', skuId) 444 | if buyGood(skuId, session, logger, payment_pwd): 445 | sendMail(skuidUrl, True, sendTo) 446 | sys.exit(1) 447 | else: 448 | sendMail(skuidUrl, False, sendTo) 449 | sys.exit(1) 450 | else: 451 | logger.info('[%s]商品有货, 但已下架.', skuId) 452 | time.sleep(5) 453 | if flag % 20 == 0: 454 | logger.info('校验是否还在登录...') 455 | validateCookies(logger, session) 456 | except Exception as e: 457 | print(traceback.format_exc()) 458 | time.sleep(10) 459 | 460 | 461 | if __name__ == '__main__': #当一个模块被直接运行时,内置变量__name__==‘__main__’, 462 | sendTo = '' #邮箱 463 | cookies_String = '' #用户登陆cookies 464 | fp = open("./Please fill out this document.txt", 'r', encoding='utf-8') 465 | cont = fp.read() 466 | pattern = re.compile("'(.*)'") 467 | contRe = pattern.findall(cont) 468 | if len(contRe) >= 2: 469 | sendTo = contRe[0] 470 | cookies_String = contRe[1] 471 | print("Please confirm the email address: %s" % sendTo) 472 | if len(cookies_String) == 0: 473 | print("ERROR: Missing cookie.") 474 | contRe = contRe[2:] #商品url 475 | print(contRe) 476 | try: 477 | main(sendTo, cookies_String, contRe) 478 | except Exception: 479 | sendError(sendTo) #有异常就发消息到邮箱 -------------------------------------------------------------------------------- /Console Version/Please fill out this document.txt: -------------------------------------------------------------------------------- 1 | 请注意所有讯息在单引号内填写 2 | 您接收下单成功讯息的邮箱(可不填): 'chjxg3@yeah.net' 3 | 4 | 您的登录cookie(请按照README.md内指南获取): 5 | '__jdv=122270672|direct|-|none|-|1605468694100; pinId=mtHyqkrb05E; pin=chjxg3; unick=%E9%87%91%E8%AF%BA1099; _tp=QuoZkycTxuXFYHPqSvJoqA%3D%3D; _pst=chjxg3; PCSYCityID=CN_420000_0_0; shshshfp=799b93d7a8807c25492100e285d0bd55; shshshfpa=1afbb246-5bbf-b0e4-eb19-ca7428a239c2-1605468794; shshshfpb=d4w%2FZW%208KFMTtNlOBKqY1jQ%3D%3D; areaId=17; user-key=3a193397-5d55-4c21-8176-e2568fc8820e; ceshi3.com=000; ipLoc-djd=17-1387-1393-43304.2396251004; ipLocation=%u6e56%u5317; cn=0; __jdc=122270672; 3AB9D23F7A4B3C9B=X55747X4MWHQ4YWHGG47EFSXIGUUGSZI5RNEJF3IX4JH265DUXALGYZHETH75UY53DCBJUZ5GHTBGBUEXZSO5Y6R5M; __jda=122270672.160546869409921141914.1605468694.1605901316.1605987793.7; wlfstk_smdl=cl1ko0xgq0fych62kmi38d0ruyt472bj; TrackID=1dTf7yzpt9a33kDCVdboPq-Ax9MwWPVeOP5kYKTpB-T_Z49UrpKE0dzmea77r3oxL-0kqEcDOjl1hGl-NbGV2QkrT3tHNdlQbZvamwFXsADU; shshshsID=076c0c0be41510eecd156a03c884dbd6_4_1605989099131; __jdb=122270672.9.160546869409921141914|7.1605987793; thor=E0CB04CC147C275CCCD79D976645470FD65B201FDFD67E98013EC61C97FAB76E470C08F264764C16C34075F2448CFA57F9C7E2C16B983ADFB4897CCE3183E6C50F31425C0CF1C7DA25CDD345A69871F2F5A5F3A3068422EB90AD487702ECAE459DBC22C74C6FA326F6FF069A3BDCBD5C3F63B84834E9B749110E7BA703B219E9' 6 | 7 | 您需要自动购买的商品URL(请按照README.md内指南获取): 8 | 'https://c0.3.cn/stocks?callback=jQuery2435878&type=getstocks&skuIds=1564242%2C868883%2C4708316%2C1003982%2C868884&area=17_1387_1393_43304&_=1605898524364' -------------------------------------------------------------------------------- /Console Version/Please fill out this document.txt.old: -------------------------------------------------------------------------------- 1 | 请注意所有讯息在单引号内填写 2 | 您接收下单成功讯息的邮箱(可不填): 'chjxg3@yeah.net' 3 | 4 | 您的登录cookie(请按照README.md内指南获取): 5 | 'e2a6650a-bf7e-4ebd-96ee-0dcc94d82157' 6 | 7 | 您需要自动购买的商品URL(请按照README.md内指南获取): 8 | 9 | 'https://c0.3.cn/stock?skuId=1835967&area=16_1362_44319_51500&venderId=1000084390&buyNum=1&choseSuitSkuIds=&cat=9192,12190,1517&extraParam={%22originid%22:%221%22}&fqsp=0&pdpin=jd_77a8935fb872d&pduid=526700225&ch=1&callback=jQuery1535213' 10 | 'https://c0.3.cn/stock?skuId=1835968&area=16_1362_44319_51500&venderId=1000084390&buyNum=1&choseSuitSkuIds=&cat=9192,12190,1517&extraParam={%22originid%22:%221%22}&fqsp=0&pdpin=jd_77a8935fb872d&pduid=526700225&ch=1&callback=jQuery366840' 11 | 'https://c0.3.cn/stock?skuId=1336984&area=16_1362_44319_51500&venderId=1000078145&buyNum=1&choseSuitSkuIds=&cat=9192,12190,1517&extraParam={%22originid%22:%221%22}&fqsp=0&pdpin=jd_77a8935fb872d&pduid=526700225&ch=1&callback=jQuery94700' 12 | 'https://c0.3.cn/stock?skuId=65466451629&area=16_1362_44319_51500&venderId=127922&buyNum=1&choseSuitSkuIds=&cat=9855,9858,9924&extraParam={%22originid%22:%221%22}&fqsp=0&pdpin=jd_77a8935fb872d&pduid=526700225&ch=1&callback=jQuery8432226' 13 | 'https://c0.3.cn/stock?skuId=7498169&area=16_1362_44319_51500&venderId=1000128491&buyNum=1&choseSuitSkuIds=&cat=9855,9858,9924&extraParam={%22originid%22:%221%22}&fqsp=0&pdpin=jd_77a8935fb872d&pduid=526700225&ch=1&callback=jQuery7323892' 14 | 'https://c0.3.cn/stock?skuId=7263128&area=16_1362_44319_51500&venderId=1000128491&buyNum=1&choseSuitSkuIds=&cat=9855,9858,9924&extraParam={%22originid%22:%221%22}&fqsp=0&pdpin=jd_77a8935fb872d&pduid=526700225&ch=1&callback=jQuery9621467' 15 | 'https://c0.3.cn/stock?skuId=4061438&area=16_1362_44319_51500&venderId=1000005584&buyNum=1&choseSuitSkuIds=&cat=9192,12190,1517&extraParam={%22originid%22:%221%22}&fqsp=0&pdpin=jd_77a8935fb872d&pduid=526700225&ch=1&callback=jQuery620656' 16 | 'https://c0.3.cn/stock?skuId=65421329578&area=16_1362_44319_51500&venderId=593210&buyNum=1&choseSuitSkuIds=&cat=9192,12190,1517&extraParam={%22originid%22:%221%22}&fqsp=0&pdpin=jd_77a8935fb872d&pduid=526700225&ch=1&callback=jQuery4952468' 17 | 'https://c0.3.cn/stock?skuId=100005678825&area=16_1362_44319_51500&venderId=1000090691&buyNum=1&choseSuitSkuIds=&cat=9855,9858,9924&extraParam={%22originid%22:%221%22}&fqsp=0&pdpin=jd_77a8935fb872d&pduid=526700225&ch=1&callback=jQuery2192795' 18 | 'https://c0.3.cn/stock?skuId=100005294853&area=16_1362_44319_51500&venderId=1000090691&buyNum=1&choseSuitSkuIds=&cat=9855,9858,9924&extraParam={%22originid%22:%221%22}&fqsp=0&pdpin=jd_77a8935fb872d&pduid=526700225&ch=1&callback=jQuery8766944' 19 | 'https://c0.3.cn/stock?skuId=45923412989&area=16_1362_44319_51500&venderId=10066244&buyNum=1&choseSuitSkuIds=&cat=9192,12190,1517&extraParam={%22originid%22:%221%22}&fqsp=0&pdpin=jd_77a8935fb872d&pduid=526700225&ch=1&callback=jQuery8072251' 20 | 'https://c0.3.cn/stock?skuId=62830056100&area=16_1362_44319_51500&venderId=10066244&buyNum=1&choseSuitSkuIds=&cat=9192,12190,1517&extraParam={%22originid%22:%221%22}&fqsp=0&pdpin=jd_77a8935fb872d&pduid=526700225&ch=1&callback=jQuery599501' 21 | 'https://c0.3.cn/stock?skuId=45006657879&area=16_1362_44319_51500&venderId=10066244&buyNum=1&choseSuitSkuIds=&cat=9192,12190,1517&extraParam={%22originid%22:%221%22}&fqsp=0&pdpin=jd_77a8935fb872d&pduid=526700225&ch=1&callback=jQuery6257903' -------------------------------------------------------------------------------- /Console Version/__pycache__/JDAutoBuyTool.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jjjenkinson/autobuy-jd/1834e6d14b598f352ca71665335a3e2979e9eeb9/Console Version/__pycache__/JDAutoBuyTool.cpython-37.pyc -------------------------------------------------------------------------------- /Console Version/__pycache__/JDAutoBuyTool.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jjjenkinson/autobuy-jd/1834e6d14b598f352ca71665335a3e2979e9eeb9/Console Version/__pycache__/JDAutoBuyTool.cpython-38.pyc -------------------------------------------------------------------------------- /Console Version/__pycache__/my_test.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jjjenkinson/autobuy-jd/1834e6d14b598f352ca71665335a3e2979e9eeb9/Console Version/__pycache__/my_test.cpython-37.pyc -------------------------------------------------------------------------------- /Console Version/__pycache__/test.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jjjenkinson/autobuy-jd/1834e6d14b598f352ca71665335a3e2979e9eeb9/Console Version/__pycache__/test.cpython-37.pyc -------------------------------------------------------------------------------- /Console Version/jQuery3078854.dat: -------------------------------------------------------------------------------- 1 | 'jQuery3078854({"1003982":{"StockState":33,"freshEdi":null,"ab":"-1","ac":"-1","ad":"-1","ae":"-1","skuState":1,"PopType":0,"af":"-1","ag":"-1","sidDely":"101","channel":1,"StockStateName":"现货","rid":null,"m":"0","sid":"101","rfg":0,"dcId":"5","ArrivalDate":"","v":"0","IsPurchase":false,"rn":-1,"eb":"0","ec":"-1"},"868884":{"StockState":34,"freshEdi":null,"ab":"-1","ac":"-1","ad":"-1","ae":"-1","skuState":1,"PopType":0,"af":"-1","ag":"-1","sidDely":"0","channel":1,"StockStateName":"无货","rid":null,"m":"0","sid":"0","rfg":0,"dcId":"183","ArrivalDate":"","v":"0","IsPurchase":false,"rn":-1,"eb":"-1000000000","ec":"-1"},"4708316":{"StockState":33,"freshEdi":null,"ab":"-1","ac":"-1","ad":"-1","ae":"-1","skuState":1,"PopType":0,"af":"-1","ag":"-1","sidDely":"101","channel":1,"StockStateName":"现货","rid":null,"m":"0","sid":"101","rfg":0,"dcId":"5","ArrivalDate":"","v":"0","IsPurchase":false,"rn":-1,"eb":"0","ec":"-1"},"1564242":{"StockState":33,"freshEdi":null,"ab":"-1","ac":"-1","ad":"-1","ae":"-1","skuState":1,"PopType":0,"af":"-1","ag":"-1","sidDely":"101","channel":1,"StockStateName":"现货","rid":null,"m":"0","sid":"101","rfg":0,"dcId":"5","ArrivalDate":"","v":"0","IsPurchase":false,"rn":-1,"eb":"0","ec":"-1"},"868883":{"StockState":33,"freshEdi":null,"ab":"-1","ac":"-1","ad":"-1","ae":"-1","skuState":1,"PopType":0,"af":"-1","ag":"-1","sidDely":"101","channel":1,"StockStateName":"现货","rid":null,"m":"0","sid":"101","rfg":0,"dcId":"5","ArrivalDate":"","v":"0","IsPurchase":false,"rn":-1,"eb":"0","ec":"-1"}})' -------------------------------------------------------------------------------- /Console Version/jQuery3078854.txt: -------------------------------------------------------------------------------- 1 | 'jQuery3078854({"1003982":{"StockState":33,"freshEdi":null,"ab":"-1","ac":"-1","ad":"-1","ae":"-1","skuState":1,"PopType":0,"af":"-1","ag":"-1","sidDely":"101","channel":1,"StockStateName":"现货","rid":null,"m":"0","sid":"101","rfg":0,"dcId":"5","ArrivalDate":"","v":"0","IsPurchase":false,"rn":-1,"eb":"0","ec":"-1"},"868884":{"StockState":34,"freshEdi":null,"ab":"-1","ac":"-1","ad":"-1","ae":"-1","skuState":1,"PopType":0,"af":"-1","ag":"-1","sidDely":"0","channel":1,"StockStateName":"无货","rid":null,"m":"0","sid":"0","rfg":0,"dcId":"183","ArrivalDate":"","v":"0","IsPurchase":false,"rn":-1,"eb":"-1000000000","ec":"-1"},"4708316":{"StockState":33,"freshEdi":null,"ab":"-1","ac":"-1","ad":"-1","ae":"-1","skuState":1,"PopType":0,"af":"-1","ag":"-1","sidDely":"101","channel":1,"StockStateName":"现货","rid":null,"m":"0","sid":"101","rfg":0,"dcId":"5","ArrivalDate":"","v":"0","IsPurchase":false,"rn":-1,"eb":"0","ec":"-1"},"1564242":{"StockState":33,"freshEdi":null,"ab":"-1","ac":"-1","ad":"-1","ae":"-1","skuState":1,"PopType":0,"af":"-1","ag":"-1","sidDely":"101","channel":1,"StockStateName":"现货","rid":null,"m":"0","sid":"101","rfg":0,"dcId":"5","ArrivalDate":"","v":"0","IsPurchase":false,"rn":-1,"eb":"0","ec":"-1"},"868883":{"StockState":33,"freshEdi":null,"ab":"-1","ac":"-1","ad":"-1","ae":"-1","skuState":1,"PopType":0,"af":"-1","ag":"-1","sidDely":"101","channel":1,"StockStateName":"现货","rid":null,"m":"0","sid":"101","rfg":0,"dcId":"5","ArrivalDate":"","v":"0","IsPurchase":false,"rn":-1,"eb":"0","ec":"-1"}})' -------------------------------------------------------------------------------- /Console Version/jdAutoBuyGood.log: -------------------------------------------------------------------------------- 1 | 2020-02-06 13:01:10,916 INFO: 登录成功! 2 | 2020-02-06 13:01:11,168 INFO: 登录账号名称: jd_180519iya 3 | 2020-02-06 13:01:11,173 INFO: 第1次 查询... 4 | 2020-02-06 13:01:11,389 INFO: [1835967]商品无货. 5 | 2020-02-06 13:01:11,583 INFO: [1835968]商品无货. 6 | 2020-02-07 18:13:10,251 INFO: 登录成功! 7 | 2020-02-07 18:13:10,463 INFO: 登录账号名称: jd_180519iya 8 | 2020-02-07 18:13:10,467 INFO: 第1次 查询... 9 | 2020-02-07 18:13:10,699 INFO: [1835967]商品无货. 10 | 2020-02-07 18:13:10,947 INFO: [1835968]商品无货. 11 | 2020-11-12 05:18:35,050 INFO: 登录成功! 12 | 2020-11-12 05:18:35,254 INFO: 登录账号名称: 金诺1099 13 | 2020-11-12 05:18:35,255 INFO: 第1次 查询... 14 | 2020-11-12 05:18:45,267 INFO: 第2次 查询... 15 | 2020-11-12 05:18:55,278 INFO: 第3次 查询... 16 | 2020-11-12 05:19:05,287 INFO: 第4次 查询... 17 | 2020-11-12 05:19:15,300 INFO: 第5次 查询... 18 | 2020-11-12 05:19:25,313 INFO: 第6次 查询... 19 | 2020-11-12 05:19:35,326 INFO: 第7次 查询... 20 | 2020-11-12 05:19:45,338 INFO: 第8次 查询... 21 | 2020-11-12 05:19:55,348 INFO: 第9次 查询... 22 | 2020-11-12 05:20:05,361 INFO: 第10次 查询... 23 | 2020-11-12 05:20:15,371 INFO: 第11次 查询... 24 | 2020-11-12 05:20:25,384 INFO: 第12次 查询... 25 | 2020-11-12 05:20:35,395 INFO: 第13次 查询... 26 | 2020-11-12 05:20:45,407 INFO: 第14次 查询... 27 | 2020-11-12 05:20:55,417 INFO: 第15次 查询... 28 | 2020-11-12 05:21:05,427 INFO: 第16次 查询... 29 | 2020-11-12 05:21:15,437 INFO: 第17次 查询... 30 | 2020-11-12 05:21:25,447 INFO: 第18次 查询... 31 | 2020-11-12 05:21:35,457 INFO: 第19次 查询... 32 | 2020-11-12 05:21:45,467 INFO: 第20次 查询... 33 | 2020-11-12 05:21:55,478 INFO: 第21次 查询... 34 | 2020-11-12 05:22:05,487 INFO: 第22次 查询... 35 | 2020-11-12 05:22:15,497 INFO: 第23次 查询... 36 | 2020-11-12 05:22:25,501 INFO: 第24次 查询... 37 | 2020-11-12 05:22:35,511 INFO: 第25次 查询... 38 | 2020-11-12 05:22:45,521 INFO: 第26次 查询... 39 | 2020-11-12 05:22:55,530 INFO: 第27次 查询... 40 | 2020-11-12 05:23:05,542 INFO: 第28次 查询... 41 | 2020-11-12 05:23:15,554 INFO: 第29次 查询... 42 | 2020-11-12 05:23:25,564 INFO: 第30次 查询... 43 | 2020-11-12 05:23:35,576 INFO: 第31次 查询... 44 | 2020-11-12 05:23:45,588 INFO: 第32次 查询... 45 | 2020-11-12 05:23:55,597 INFO: 第33次 查询... 46 | 2020-11-12 05:24:05,607 INFO: 第34次 查询... 47 | 2020-11-12 05:24:15,617 INFO: 第35次 查询... 48 | 2020-11-12 05:31:09,370 INFO: 登录成功! 49 | 2020-11-12 05:31:09,503 INFO: 登录账号名称: 金诺1099 50 | 2020-11-12 05:31:09,504 INFO: 第1次 查询... 51 | 2020-11-12 05:31:19,513 INFO: 第2次 查询... 52 | 2020-11-12 05:35:24,215 INFO: 登录成功! 53 | 2020-11-12 05:35:24,346 INFO: 登录账号名称: 金诺1099 54 | 2020-11-12 05:35:24,346 INFO: 第1次 查询... 55 | 2020-11-12 05:35:34,357 INFO: 第2次 查询... 56 | 2020-11-16 03:34:03,106 INFO: 第[1]次请重新获取cookie... 57 | 2020-11-16 03:34:08,268 INFO: 第[2]次请重新获取cookie... 58 | 2020-11-16 03:34:13,418 INFO: 登录账号名称: 金诺1099 59 | 2020-11-16 03:34:13,419 INFO: 第1次 查询... 60 | 2020-11-16 03:34:23,429 INFO: 第2次 查询... 61 | 2020-11-16 03:40:55,460 INFO: 登录成功! 62 | 2020-11-16 03:40:55,615 INFO: 登录账号名称: 金诺1099 63 | 2020-11-16 03:40:55,616 INFO: 第1次 查询... 64 | 2020-11-16 03:41:05,628 INFO: 第2次 查询... 65 | 2020-11-16 03:41:15,639 INFO: 第3次 查询... 66 | 2020-11-16 03:41:25,649 INFO: 第4次 查询... 67 | 2020-11-18 03:30:10,596 INFO: 第[1]次请重新获取cookie... 68 | 2020-11-18 03:30:15,746 INFO: 第[2]次请重新获取cookie... 69 | 2020-11-18 03:30:20,909 INFO: 登录账号名称: 金诺1099 70 | 2020-11-18 03:30:20,909 INFO: 第1次 查询... 71 | 2020-11-18 03:30:30,918 INFO: 第2次 查询... 72 | 2020-11-18 03:30:40,928 INFO: 第3次 查询... 73 | 2020-11-18 03:37:10,026 INFO: 登录成功! 74 | 2020-11-18 03:37:10,192 INFO: 登录账号名称: 金诺1099 75 | 2020-11-18 03:37:10,192 INFO: 第1次 查询... 76 | 2020-11-18 03:37:20,204 INFO: 第2次 查询... 77 | 2020-11-18 04:03:31,617 INFO: 登录成功! 78 | 2020-11-18 04:03:31,807 INFO: 登录账号名称: 金诺1099 79 | 2020-11-18 04:03:31,808 INFO: 第1次 查询... 80 | 2020-11-18 04:05:41,188 INFO: 第2次 查询... 81 | 2020-11-20 04:00:17,920 INFO: 第[1]次请重新获取cookie... 82 | 2020-11-20 04:00:23,086 INFO: 第[2]次请重新获取cookie... 83 | 2020-11-20 04:00:28,283 INFO: 登录账号名称: 金诺1099 84 | 2020-11-20 04:00:28,284 INFO: 第1次 查询... 85 | 2020-11-20 04:55:00,369 INFO: 第[1]次请重新获取cookie... 86 | 2020-11-20 04:55:05,537 INFO: 第[2]次请重新获取cookie... 87 | 2020-11-20 04:55:10,697 INFO: 登录账号名称: 金诺1099 88 | 2020-11-20 04:55:10,698 INFO: 第1次 查询... 89 | 2020-11-20 04:55:10,826 INFO: [100016129294]商品无货. 90 | 2020-11-20 04:55:15,832 INFO: 第2次 查询... 91 | 2020-11-20 04:55:15,968 INFO: [100016129294]商品无货. 92 | 2020-11-20 04:55:20,973 INFO: 第3次 查询... 93 | 2020-11-20 04:55:21,172 INFO: [100016129294]商品无货. 94 | 2020-11-20 04:55:26,176 INFO: 第4次 查询... 95 | 2020-11-20 04:55:26,298 INFO: [100016129294]商品无货. 96 | 2020-11-20 05:21:41,854 INFO: 第[1]次请重新获取cookie... 97 | 2020-11-20 05:21:47,018 INFO: 第[2]次请重新获取cookie... 98 | 2020-11-20 05:21:52,446 INFO: 登录账号名称: 金诺1099 99 | 2020-11-20 05:21:52,446 INFO: 第1次 查询... 100 | 2020-11-20 05:21:57,450 INFO: 第2次 查询... 101 | 2020-11-20 05:22:02,453 INFO: 第3次 查询... 102 | 2020-11-20 05:22:07,456 INFO: 第4次 查询... 103 | 2020-11-20 05:22:12,459 INFO: 第5次 查询... 104 | 2020-11-20 05:22:17,463 INFO: 第6次 查询... 105 | 2020-11-20 05:22:22,466 INFO: 第7次 查询... 106 | 2020-11-20 05:22:27,469 INFO: 第8次 查询... 107 | 2020-11-20 05:22:32,474 INFO: 第9次 查询... 108 | 2020-11-20 05:22:37,479 INFO: 第10次 查询... 109 | 2020-11-20 05:22:42,485 INFO: 第11次 查询... 110 | 2020-11-20 05:22:47,489 INFO: 第12次 查询... 111 | 2020-11-20 05:22:52,495 INFO: 第13次 查询... 112 | 2020-11-20 05:22:57,499 INFO: 第14次 查询... 113 | 2020-11-20 05:23:02,503 INFO: 第15次 查询... 114 | 2020-11-20 05:23:07,506 INFO: 第16次 查询... 115 | 2020-11-20 05:23:12,509 INFO: 第17次 查询... 116 | 2020-11-20 05:23:17,515 INFO: 第18次 查询... 117 | 2020-11-20 05:23:22,520 INFO: 第19次 查询... 118 | 2020-11-20 05:23:27,522 INFO: 校验是否还在登录... 119 | 2020-11-20 05:23:27,684 INFO: 第[1]次请重新获取cookie... 120 | 2020-11-20 05:23:32,848 INFO: 第[2]次请重新获取cookie... 121 | 2020-11-20 05:23:37,853 INFO: 第20次 查询... 122 | 2020-11-20 05:23:42,858 INFO: 第21次 查询... 123 | 2020-11-20 05:23:47,863 INFO: 第22次 查询... 124 | 2020-11-20 05:26:41,576 INFO: 登录成功! 125 | 2020-11-20 05:26:41,722 INFO: 登录账号名称: 金诺1099 126 | 2020-11-20 05:26:41,723 INFO: 第1次 查询... 127 | 2020-11-20 05:26:46,728 INFO: 第2次 查询... 128 | 2020-11-20 05:26:51,733 INFO: 第3次 查询... 129 | 2020-11-20 05:26:56,736 INFO: 第4次 查询... 130 | 2020-11-20 05:38:39,667 INFO: 登录成功! 131 | 2020-11-20 05:38:39,849 INFO: 登录账号名称: 金诺1099 132 | 2020-11-20 05:38:39,850 INFO: 第1次 查询... 133 | 2020-11-20 05:39:40,265 INFO: 第2次 查询... 134 | 2020-11-20 05:41:41,923 INFO: 登录成功! 135 | 2020-11-20 05:41:42,179 INFO: 登录账号名称: 金诺1099 136 | 2020-11-20 05:41:42,180 INFO: 第1次 查询... 137 | 2020-11-20 05:41:42,537 INFO: [10022306971495]商品无货. 138 | 2020-11-20 05:41:47,543 INFO: 第2次 查询... 139 | 2020-11-20 05:41:47,694 INFO: [10022306971495]商品无货. 140 | 2020-11-20 05:47:10,269 INFO: 登录成功! 141 | 2020-11-20 05:47:10,401 INFO: 登录账号名称: 金诺1099 142 | 2020-11-20 05:47:10,401 INFO: 第1次 查询... 143 | 2020-11-20 05:47:10,529 INFO: [10023884082830]商品无货. 144 | 2020-11-20 05:47:15,535 INFO: 第2次 查询... 145 | 2020-11-20 05:47:15,670 INFO: [10023884082830]商品无货. 146 | 2020-11-20 05:47:20,676 INFO: 第3次 查询... 147 | 2020-11-20 05:47:20,812 INFO: [10023884082830]商品无货. 148 | 2020-11-20 05:51:10,977 INFO: 登录成功! 149 | 2020-11-20 05:51:11,128 INFO: 登录账号名称: 金诺1099 150 | 2020-11-20 05:51:11,129 INFO: 第1次 查询... 151 | 2020-11-20 05:51:11,264 INFO: [868883]商品无货. 152 | 2020-11-20 05:51:16,270 INFO: 第2次 查询... 153 | 2020-11-20 05:51:16,404 INFO: [868883]商品无货. 154 | 2020-11-20 05:51:21,409 INFO: 第3次 查询... 155 | 2020-11-20 05:51:21,731 INFO: [868883]商品无货. 156 | 2020-11-20 05:51:26,736 INFO: 第4次 查询... 157 | 2020-11-20 05:51:26,867 INFO: [868883]商品无货. 158 | 2020-11-20 05:51:31,873 INFO: 第5次 查询... 159 | 2020-11-20 05:51:32,005 INFO: [868883]商品无货. 160 | 2020-11-20 05:55:37,205 INFO: 登录成功! 161 | 2020-11-20 05:55:37,469 INFO: 登录账号名称: 金诺1099 162 | 2020-11-20 05:55:37,470 INFO: 第1次 查询... 163 | 2020-11-21 02:01:07,710 INFO: 登录成功! 164 | 2020-11-21 02:01:07,856 INFO: 登录账号名称: 金诺1099 165 | 2020-11-21 02:01:07,857 INFO: 第1次 查询... 166 | 2020-11-21 02:01:08,016 INFO: [868883]商品无货. 167 | 2020-11-21 02:01:13,021 INFO: 第2次 查询... 168 | 2020-11-21 02:01:13,154 INFO: [868883]商品无货. 169 | 2020-11-21 02:40:48,233 INFO: 登录成功! 170 | 2020-11-21 02:40:48,379 INFO: 登录账号名称: 金诺1099 171 | 2020-11-21 02:40:48,379 INFO: 第1次 查询... 172 | 2020-11-21 02:40:48,534 INFO: [868883]商品无货. 173 | 2020-11-21 02:40:53,538 INFO: 第2次 查询... 174 | 2020-11-21 02:40:53,672 INFO: [868883]商品无货. 175 | 2020-11-21 03:41:30,295 INFO: 登录成功! 176 | 2020-11-21 03:41:30,536 INFO: 登录账号名称: 金诺1099 177 | 2020-11-21 03:41:30,536 INFO: 第1次 查询... 178 | 2020-11-21 03:41:31,355 INFO: [868883]商品有货啦! 马上下单... 179 | 2020-11-21 03:41:31,356 INFO: 第[1/5]次尝试提交订单 180 | 2020-11-21 03:41:33,213 INFO: 868883 已成功加入购物车 181 | 2020-11-21 03:41:33,636 INFO: 当前购物车信息: {} 182 | 2020-11-21 03:41:34,402 INFO: 下单信息: {'address': '湖北 黄石市 大冶市 还地桥镇 长岭村费家边湾', 'receiver': '程先生 156****9627', 'total_price': '19.80', 'items': []} 183 | 2020-11-21 03:41:34,583 INFO: 订单提交成功! 订单号: 138742874826 184 | 2020-11-21 03:43:32,352 INFO: 登录成功! 185 | 2020-11-21 03:43:32,588 INFO: 登录账号名称: 金诺1099 186 | 2020-11-21 03:43:32,589 INFO: 第1次 查询... 187 | 2020-11-21 03:43:46,484 INFO: 第2次 查询... 188 | 2020-11-21 03:43:57,430 INFO: 第3次 查询... 189 | 2020-11-21 03:43:57,856 INFO: [868883]商品有货啦! 马上下单... 190 | 2020-11-21 03:43:57,856 INFO: 第[1/5]次尝试提交订单 191 | 2020-11-21 03:43:58,957 INFO: 868883 已成功加入购物车 192 | 2020-11-21 03:43:59,641 INFO: 当前购物车信息: {} 193 | 2020-11-21 03:44:00,870 INFO: 下单信息: {'address': '湖北 黄石市 大冶市 还地桥镇 长岭村费家边湾', 'receiver': '程先生 156****9627', 'total_price': '19.80', 'items': []} 194 | 2020-11-21 03:44:01,069 INFO: 订单提交成功! 订单号: 132966892561 195 | 2020-11-21 03:46:06,509 INFO: 登录成功! 196 | 2020-11-21 03:46:06,657 INFO: 登录账号名称: 金诺1099 197 | 2020-11-21 03:46:06,658 INFO: 第1次 查询... 198 | 2020-11-21 03:46:51,683 INFO: 登录成功! 199 | 2020-11-21 03:46:51,819 INFO: 登录账号名称: 金诺1099 200 | 2020-11-21 03:46:51,819 INFO: 第1次 查询... 201 | 2020-11-21 03:47:37,831 INFO: 登录成功! 202 | 2020-11-21 03:47:37,974 INFO: 登录账号名称: 金诺1099 203 | 2020-11-21 03:47:37,975 INFO: 第1次 查询... 204 | 2020-11-21 03:47:48,104 INFO: 第2次 查询... 205 | 2020-11-21 03:48:20,802 INFO: 登录成功! 206 | 2020-11-21 03:48:20,934 INFO: 登录账号名称: 金诺1099 207 | 2020-11-21 03:48:20,935 INFO: 第1次 查询... 208 | 2020-11-22 03:48:38,435 INFO: 第[1]次请重新获取cookie... 209 | 2020-11-22 03:48:43,691 INFO: 第[2]次请重新获取cookie... 210 | 2020-11-22 03:48:48,856 INFO: 登录账号名称: 金诺1099 211 | 2020-11-22 03:48:48,857 INFO: 第1次 查询... 212 | 2020-11-22 04:29:01,998 INFO: 第[1]次请重新获取cookie... 213 | 2020-11-22 04:29:07,165 INFO: 第[2]次请重新获取cookie... 214 | 2020-11-22 04:29:12,486 INFO: 登录账号名称: 金诺1099 215 | 2020-11-22 04:29:12,487 INFO: 第1次 查询... 216 | 2020-11-22 04:29:13,339 INFO: [4708316]商品有货啦! 马上下单... 217 | 2020-11-22 04:29:13,340 INFO: 第[1/5]次尝试提交订单 218 | 2020-11-22 04:29:25,177 INFO: 第2次 查询... 219 | 2020-11-22 04:29:25,956 INFO: [4708316]商品有货啦! 马上下单... 220 | 2020-11-22 04:29:25,956 INFO: 第[1/5]次尝试提交订单 221 | 2020-11-22 04:29:36,924 INFO: 第3次 查询... 222 | 2020-11-22 04:29:37,391 INFO: [4708316]商品有货啦! 马上下单... 223 | 2020-11-22 04:29:37,391 INFO: 第[1/5]次尝试提交订单 224 | 2020-11-22 04:29:47,901 INFO: 第4次 查询... 225 | 2020-11-22 04:29:48,344 INFO: [4708316]商品有货啦! 马上下单... 226 | 2020-11-22 04:29:48,345 INFO: 第[1/5]次尝试提交订单 227 | 2020-11-22 04:34:04,499 INFO: 登录成功! 228 | 2020-11-22 04:34:04,648 INFO: 登录账号名称: 金诺1099 229 | 2020-11-22 04:34:04,648 INFO: 第1次 查询... 230 | 2020-11-22 04:34:05,082 INFO: [4708316]商品有货啦! 马上下单... 231 | 2020-11-22 04:34:05,083 INFO: 第[1/5]次尝试提交订单 232 | 2020-11-22 04:34:06,046 INFO: 4708316 已成功加入购物车 233 | 2020-11-22 04:34:06,493 INFO: 当前购物车信息: {} 234 | 2020-11-22 04:34:07,198 INFO: 下单信息: {'address': '湖北 黄石市 大冶市 还地桥镇 长岭村费家边湾', 'receiver': '程先生 156****9627', 'total_price': '19.80', 'items': []} 235 | 2020-11-22 04:34:07,388 INFO: 订单提交成功! 订单号: 138769320323 236 | -------------------------------------------------------------------------------- /Console Version/my_test.py: -------------------------------------------------------------------------------- 1 | import time 2 | import re 3 | import requests 4 | import socket,getpass 5 | from JDAutoBuyTool import sendError 6 | import JDAutoBuyTool as jd 7 | 8 | # print('time.asctime() = {}'.format(time.asctime())) 9 | 10 | # print('time.time() = {}'.format(time.time())) 11 | # print('time.time() = {}'.format(time.time())) 12 | # print('username = {}, hostname = {}'.format(getpass.getuser(),socket.gethostname())) 13 | 14 | infilename = './Please fill out this document.txt' 15 | fp = open(infilename, 'r', encoding='utf-8') 16 | cont = fp.read() 17 | pattern = re.compile("'(.*)'") 18 | contRe = pattern.findall(cont) 19 | # print('contRe = ',contRe) 20 | contRe = contRe[2:] 21 | fp.close() 22 | url =contRe 23 | # print(url) 24 | for i in url: 25 | skuId = i.split('skuIds=')[1].split('%2C')[2] 26 | skuIdUrl = 'https://item.jd.com/' + skuId + '.html' 27 | print('skuIdUrl = {}'.format(skuIdUrl)) 28 | 29 | mysession = requests.session() 30 | mysession.headers = { 31 | "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36", 32 | "Accept": "*/*", 33 | "Connection": "keep-alive" 34 | } 35 | 36 | response = mysession.get(i) 37 | # print('response = ',response.text) # 38 | j = response.text.find(str(skuId)) 39 | # print(response.text.find(str(skuId))) 40 | # print(len(str(skuId))) 41 | # print(response.text[j:j+len(str(skuId))]) 42 | tmp = response.text.split(str(skuId))[1] 43 | m = tmp.find('{') 44 | n = tmp.find('}') 45 | tmp = tmp[m:n+1] 46 | print(m,n) 47 | print(tmp) 48 | 49 | dict1 = { 50 | 'a' : 12, 51 | 'b' : 23 52 | } 53 | print(dict1) 54 | 55 | 56 | -------------------------------------------------------------------------------- /Console Version/requirements.txt: -------------------------------------------------------------------------------- 1 | requests==2.22.0 2 | beautifulsoup4==4.8.2 3 | -------------------------------------------------------------------------------- /Console Version/test.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | ''' 4 | 【简介】 5 | PyQt5中QButton例子 6 | ''' 7 | 8 | import sys 9 | from PyQt5.QtCore import * 10 | from PyQt5.QtGui import * 11 | from PyQt5.QtWidgets import * 12 | 13 | class Form(QDialog): 14 | def __init__(self, parent=None): 15 | super(Form, self).__init__(parent) 16 | layout = QVBoxLayout() #设置垂直布局 17 | 18 | self.btn1 = QPushButton("Button1") 19 | # setChenkable():设置按钮是否已经被选中,true表示按钮将被保持已点击和释放状态 20 | self.btn1.setCheckable(True) 21 | # toggle():在按钮之间进行切换 22 | self.btn1.toggle() 23 | # 通过lambda方式来传递额外的参数btn1,将clicked信号发送给槽函数whichbtn() 24 | self.btn1.clicked.connect(lambda:self.whichbtn(self.btn1) ) 25 | self.btn1.clicked.connect(self.btnstate) 26 | layout.addWidget(self.btn1) 27 | 28 | self.btn2 = QPushButton('image') 29 | self.btn2.setIcon(QIcon(QPixmap("./images/python.png"))) 30 | self.btn2.clicked.connect(lambda:self.whichbtn(self.btn2) ) 31 | layout.addWidget(self.btn2) 32 | self.setLayout(layout) 33 | 34 | self.btn3 = QPushButton("Disabled") 35 | # setEnabled():设置按钮是否可用,false时按钮变成不可用状态,点击它不会发送信号 36 | self.btn3.setEnabled(False) 37 | layout.addWidget(self.btn3) 38 | 39 | self.btn4= QPushButton("&Download") 40 | self.btn4.setDefault(True) #设置按钮的默认状态 41 | self.btn4.clicked.connect(lambda:self.whichbtn(self.btn4)) 42 | layout.addWidget(self.btn4) 43 | self.setWindowTitle("Button demo") 44 | 45 | def btnstate(self): 46 | if self.btn1.isChecked(): #返回按钮的状态 47 | print("button pressed" ) 48 | 49 | else: 50 | print("button released" ) 51 | 52 | def whichbtn(self,btn): 53 | print("clicked button is " + btn.text() ) 54 | 55 | if __name__ == '__main__': 56 | app = QApplication(sys.argv) 57 | btnDemo = Form() 58 | btnDemo.show() 59 | sys.exit(app.exec_()) -------------------------------------------------------------------------------- /Console Version/test2.py: -------------------------------------------------------------------------------- 1 | PI = 3.1415926 2 | def main1(): 3 | print('PI = ',PI) 4 | 5 | 6 | if __name__ == "__main__": 7 | main1() -------------------------------------------------------------------------------- /GUI Version/autobuy.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'qsswindow.ui' 4 | # 5 | # Created by: PyQt5 UI code generator 5.14.1 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt5 import QtCore, QtGui, QtWidgets 10 | from PyQt5.QtWidgets import QApplication 11 | from PyQt5.QtCore import QTimer 12 | 13 | import sys 14 | 15 | import argparse 16 | import os 17 | import pickle 18 | import random 19 | import time 20 | import json 21 | import requests 22 | import re 23 | import logging 24 | import logging.handlers 25 | from bs4 import BeautifulSoup 26 | import smtplib 27 | from email.mime.text import MIMEText 28 | from email.header import Header 29 | 30 | class Ui_QSSWindow(object): 31 | def setupUi(self, QSSWindow): 32 | QSSWindow.setObjectName("QSSWindow") 33 | QSSWindow.resize(950, 450) 34 | self.centralwidget = QtWidgets.QWidget(QSSWindow) 35 | self.centralwidget.setObjectName("centralwidget") 36 | self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.centralwidget) 37 | self.verticalLayout_3.setObjectName("verticalLayout_3") 38 | self.tabWidget = QtWidgets.QTabWidget(self.centralwidget) 39 | self.tabWidget.setObjectName("tabWidget") 40 | self.tab = QtWidgets.QWidget() 41 | self.tab.setObjectName("tab") 42 | 43 | self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.tab) 44 | self.verticalLayout_2.setObjectName("verticalLayout_2") 45 | self.groupBox = QtWidgets.QGroupBox(self.tab) 46 | self.groupBox.setObjectName("groupBox") 47 | self.verticalLayout = QtWidgets.QVBoxLayout(self.groupBox) 48 | self.verticalLayout.setObjectName("verticalLayout") 49 | self.goods = QtWidgets.QHBoxLayout() 50 | self.goods.setObjectName("goods") 51 | self.labelGoods = QtWidgets.QLabel(self.groupBox) 52 | self.labelGoods.setObjectName("labelGoods") 53 | self.goods.addWidget(self.labelGoods) 54 | self.inputGoods = QtWidgets.QLineEdit(self.groupBox) 55 | self.inputGoods.setObjectName("inputGoods") 56 | self.goods.addWidget(self.inputGoods) 57 | self.verticalLayout.addLayout(self.goods) 58 | self.area = QtWidgets.QHBoxLayout() 59 | self.area.setObjectName("area") 60 | self.labelArea = QtWidgets.QLabel(self.groupBox) 61 | self.labelArea.setObjectName("labelArea") 62 | self.area.addWidget(self.labelArea) 63 | self.inputArea = QtWidgets.QLineEdit(self.groupBox) 64 | self.inputArea.setObjectName("inputArea") 65 | self.area.addWidget(self.inputArea) 66 | 67 | self.labelMail = QtWidgets.QLabel(self.groupBox) 68 | self.labelMail.setObjectName("labelMail") 69 | self.area.addWidget(self.labelMail) 70 | self.inputMail = QtWidgets.QLineEdit(self.groupBox) 71 | self.inputMail.setObjectName("inputMail") 72 | self.area.addWidget(self.inputMail) 73 | 74 | self.labelNum = QtWidgets.QLabel(self.groupBox) 75 | self.labelNum.setObjectName("labelNum") 76 | self.area.addWidget(self.labelNum) 77 | self.comboBox = QtWidgets.QComboBox(self.groupBox) 78 | self.comboBox.setObjectName("comboBox") 79 | self.area.addWidget(self.comboBox) 80 | 81 | self.checkBox = QtWidgets.QCheckBox(self.groupBox) 82 | self.checkBox.setObjectName("checkBox") 83 | self.area.addWidget(self.checkBox) 84 | 85 | self.verticalLayout.addLayout(self.area) 86 | self.speedLayout = QtWidgets.QHBoxLayout() 87 | self.speedLayout.setObjectName("speedLayout") 88 | self.horizontalSlider = QtWidgets.QSlider(self.groupBox) 89 | self.horizontalSlider.setMaximum(100) 90 | self.horizontalSlider.setProperty("value", 50) 91 | self.horizontalSlider.setOrientation(QtCore.Qt.Horizontal) 92 | self.horizontalSlider.setTickInterval(0) 93 | self.horizontalSlider.setObjectName("horizontalSlider") 94 | self.speedLayout.addWidget(self.horizontalSlider) 95 | self.progressBar = QtWidgets.QProgressBar(self.groupBox) 96 | self.progressBar.setProperty("value", 24) 97 | self.progressBar.setObjectName("progressBar") 98 | self.speedLayout.addWidget(self.progressBar) 99 | 100 | self.verticalLayout.addLayout(self.speedLayout) 101 | self.textEdit = QtWidgets.QTextEdit(self.groupBox) 102 | self.textEdit.setObjectName("textEdit") 103 | self.verticalLayout.addWidget(self.textEdit) 104 | self.buttonLayout = QtWidgets.QHBoxLayout() 105 | self.buttonLayout.setObjectName("buttonLayout") 106 | self.loginBtn = QtWidgets.QPushButton(self.groupBox) 107 | self.loginBtn.setStyleSheet("") 108 | self.loginBtn.setObjectName("loginBtn") 109 | self.buttonLayout.addWidget(self.loginBtn) 110 | self.startBtn = QtWidgets.QPushButton(self.groupBox) 111 | self.startBtn.setStyleSheet("") 112 | self.startBtn.setObjectName("startBtn") 113 | self.buttonLayout.addWidget(self.startBtn) 114 | self.stopBtn = QtWidgets.QPushButton(self.groupBox) 115 | self.stopBtn.setStyleSheet("") 116 | self.stopBtn.setObjectName("stopBtn") 117 | self.buttonLayout.addWidget(self.stopBtn) 118 | self.verticalLayout.addLayout(self.buttonLayout) 119 | self.verticalLayout_2.addWidget(self.groupBox) 120 | self.tabWidget.addTab(self.tab, "") 121 | self.tab_1 = QtWidgets.QWidget() 122 | self.tab_1.setObjectName("tab_1") 123 | 124 | self.labelAboutMe = QtWidgets.QLabel(self.tab_1) 125 | # self.labelAboutMe.setGeometry(QtCore.QRect(50, 30, 280, 180)) 126 | self.labelAboutMe.setObjectName("labelAboutMe") 127 | 128 | self.tabWidget.addTab(self.tab_1, "") 129 | self.verticalLayout_3.addWidget(self.tabWidget) 130 | QSSWindow.setCentralWidget(self.centralwidget) 131 | self.statusbar = QtWidgets.QStatusBar(QSSWindow) 132 | self.statusbar.setObjectName("statusbar") 133 | QSSWindow.setStatusBar(self.statusbar) 134 | self.menubar = QtWidgets.QMenuBar(QSSWindow) 135 | self.menubar.setGeometry(QtCore.QRect(0, 0, 680, 25)) 136 | self.menubar.setObjectName("menubar") 137 | self.file = QtWidgets.QMenu(self.menubar) 138 | self.file.setObjectName("file") 139 | self.edit = QtWidgets.QMenu(self.menubar) 140 | self.edit.setObjectName("edit") 141 | QSSWindow.setMenuBar(self.menubar) 142 | self.file.addSeparator() 143 | self.menubar.addAction(self.file.menuAction()) 144 | self.menubar.addAction(self.edit.menuAction()) 145 | 146 | self.retranslateUi(QSSWindow) 147 | self.tabWidget.setCurrentIndex(5) 148 | QtCore.QMetaObject.connectSlotsByName(QSSWindow) 149 | 150 | 151 | 152 | 153 | 154 | def retranslateUi(self, QSSWindow): 155 | _translate = QtCore.QCoreApplication.translate 156 | QSSWindow.setWindowTitle(_translate("QSSWindow", "MainWindow")) 157 | self.tabWidget.setToolTip(_translate("QSSWindow", "


")) 158 | self.tabWidget.setWhatsThis(_translate("QSSWindow", "


")) 159 | self.groupBox.setTitle(_translate("QSSWindow", "一定能尽快战胜疫情, 中国加油!")) 160 | self.labelGoods.setText(_translate("QSSWindow", "请输入商品ID(以逗号间隔):")) 161 | self.labelArea.setText(_translate("QSSWindow", "请输入收件地区编码:")) 162 | self.labelMail.setText(_translate("QSSWindow", "接受讯息邮箱:")) 163 | self.labelNum.setText(_translate("QSSWindow", "购买数量:")) 164 | self.loginBtn.setText(_translate("QSSWindow", "扫码登录")) 165 | self.startBtn.setText(_translate("QSSWindow", "开始监控(可自动登录)")) 166 | self.stopBtn.setText(_translate("QSSWindow", "停止监控")) 167 | self.checkBox.setText(_translate("QSSWindow", "是否自动忽略下架商品")) 168 | 169 | 170 | self.labelAboutMe.setText(_translate("QSSWindow", '

使用指南

请点击这里跳转

战疫情, 加油!

欢迎在GitHub上加星. 谢谢!

Tips: 登录一次之后本地会保存登录信息, 重启软件之后仍然可以记住账号登录信息

只需点击"开始监控"就可以自动登录, 不必重复扫码哦

')) 171 | self.labelAboutMe.setOpenExternalLinks(True) 172 | 173 | self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("QSSWindow", "Console")) 174 | self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_1), _translate("QSSWindow", "指南")) 175 | 176 | self.file.setTitle(_translate("QSSWindow", "文件")) 177 | self.edit.setTitle(_translate("QSSWindow", "编辑")) 178 | 179 | 180 | 181 | class Autobuy(QtWidgets.QMainWindow, Ui_QSSWindow): 182 | def __init__(self): 183 | super().__init__() 184 | self.sess = requests.Session() 185 | self.sess.headers = { 186 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36", 187 | "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", 188 | "Referer": "https://order.jd.com/center/list.action", 189 | "Connection": "keep-alive" 190 | } 191 | 192 | self.headers = { 193 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/531.36", 194 | "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", 195 | "Referer": "https://cart.jd.com/cart.action", 196 | "Connection": "keep-alive" 197 | } 198 | 199 | self.speed = 5000 200 | self.isMonitorSoldout = True 201 | # self.isLogin = False 202 | self.cookiesString = '' 203 | self.cookies = {} 204 | self.skuidString = '' 205 | self.skuid = [] 206 | self.cont = 1 207 | self.timer = QTimer(self) 208 | self.logger = logging.getLogger() 209 | self.loadQSS() 210 | self.setupUi(self) 211 | self.connectSign() 212 | self.initData() 213 | self.show() 214 | 215 | 216 | def loadQSS(self): 217 | file = 'window.qss' 218 | with open(file, 'rt', encoding='utf8') as f: 219 | styleSheet = f.read() 220 | self.setStyleSheet(styleSheet) 221 | f.close() 222 | 223 | def setLogger(self, logFileName='jdAutoBuyGood.log'): 224 | self.logger.setLevel(logging.INFO) 225 | formatter = logging.Formatter('%(asctime)s %(levelname)s: %(message)s') 226 | 227 | console_handler = logging.StreamHandler() 228 | console_handler.setFormatter(formatter) 229 | self.logger.addHandler(console_handler) 230 | 231 | file_handler = logging.handlers.RotatingFileHandler( 232 | logFileName, maxBytes=10485760, backupCount=5, encoding="utf-8") 233 | file_handler.setFormatter(formatter) 234 | self.logger.addHandler(file_handler) 235 | 236 | def initData(self): 237 | self.inputGoods.setText("65466451629,65437208345,7498169,7498165,1835968,7263128,7498167,17449572304,37934196731,100001086804,56657322838,56657322841,100005294853,1938795,15595191653,15595191654,45923412989,1835967,1336984,65466451629,7498169,7263128,4061438,65421329578,100005678825,100005294853,45923412989,62830056100,45006657879") 238 | self.inputArea.setText("16_1362_44319_51500") 239 | self.inputMail.setText("$$$$$$$@qq.com") 240 | self.comboBox.addItems(['1', '2', '3']) 241 | self.horizontalSlider.setValue(50) 242 | self.horizontalSlider.setMaximum(100) 243 | self.horizontalSlider.setMinimum(0) 244 | self.setProgressBar() 245 | 246 | self.setLogger() 247 | 248 | if len(self.cookiesString) != 0: 249 | manual_cookies = {} 250 | for item in self.cookiesString.split(';'): 251 | # 用=号分割. 252 | name, value = item.strip().split('=', 1) 253 | manual_cookies[name] = value 254 | self.cookies = requests.utils.cookiejar_from_dict(manual_cookies, cookiejar=None, overwrite=True) 255 | self.sess.cookies = self.cookies 256 | 257 | def connectSign(self): 258 | self.horizontalSlider.valueChanged.connect(self.setProgressBar) 259 | self.horizontalSlider.valueChanged[int].connect(self.slvaluechange) 260 | 261 | self.loginBtn.clicked.connect(self.loginByQR) 262 | self.startBtn.clicked.connect(self.monitorConnect) 263 | self.stopBtn.clicked.connect(self.stopConnect) 264 | 265 | def stopConnect(self): 266 | self.updateStateText("已停止监控.") 267 | self.timer.stop() 268 | 269 | def stopNow(self): 270 | self.updateStateText("已停止监控.") 271 | self.timer.stop() 272 | 273 | def slvaluechange(self, val): 274 | # self.updateStateText("设置抢购速度: %d" % val) 275 | if val > 85: 276 | self.speed = 500 277 | elif val > 60: 278 | self.speed = 9000 - val * 100 279 | else: 280 | self.speed = 10000 - val * 100 281 | 282 | def setProgressBar(self): 283 | self.progressBar.setValue(self.horizontalSlider.value()) 284 | 285 | def checkLogin(self): 286 | self.updateStateText('正在验证登录状态...') 287 | for flag in range(1, 3): 288 | try: 289 | targetURL = 'https://order.jd.com/center/list.action' 290 | payload = { 291 | 'rid': str(int(time.time() * 1000)), 292 | } 293 | resp = self.sess.get(url=targetURL, params=payload, allow_redirects=False) 294 | if resp.status_code == requests.codes.OK: 295 | self.updateStateText('登录成功!') 296 | return True 297 | else: 298 | self.updateStateText('第 %s 次再尝试验证cookie...' % flag) 299 | self.updateStateText('正在尝试从历史讯息中恢复...') 300 | with open('cookie', 'rb') as f: 301 | cookies = requests.utils.cookiejar_from_dict(pickle.load(f)) 302 | # print(cookies) 303 | self.sess.cookies = cookies 304 | continue 305 | except Exception as e: 306 | self.updateStateText(str(e)) 307 | self.updateStateText('第 %s 次再尝试验证cookie...' % flag) 308 | continue 309 | self.updateStateText('请登录!') 310 | return False 311 | 312 | def loginByQR(self): 313 | # jd login by QR code 314 | try: 315 | self.updateStateText('请您打开京东手机客户端或微信扫一扫, 准备扫码登录') 316 | 317 | urls = ( 318 | 'https://passport.jd.com/new/login.aspx', 319 | 'https://qr.m.jd.com/show', 320 | 'https://qr.m.jd.com/check', 321 | 'https://passport.jd.com/uc/qrCodeTicketValidation' 322 | ) 323 | # step 1: open login page 324 | response = self.sess.get( 325 | urls[0], 326 | headers=self.headers 327 | ) 328 | if response.status_code != requests.codes.OK: 329 | self.updateStateText(f'获取登录页失败: {response.status_code}') 330 | # self.isLogin = False 331 | return False 332 | # update cookies 333 | self.cookies.update(response.cookies) 334 | self.sess.cookies = response.cookies 335 | 336 | # step 2: get QR image 337 | response = self.sess.get( 338 | urls[1], 339 | headers=self.headers, 340 | cookies=self.cookies, 341 | params={ 342 | 'appid': 133, 343 | 'size': 147, 344 | 't': int(time.time() * 1000), 345 | } 346 | ) 347 | if response.status_code != requests.codes.OK: 348 | self.updateStateText(f'获取二维码失败: {response.status_code}') 349 | # self.isLogin = False 350 | return False 351 | 352 | # update cookies 353 | self.cookies.update(response.cookies) 354 | self.sess.cookies = response.cookies 355 | 356 | # save QR code 357 | image_file = 'qr.png' 358 | with open(image_file, 'wb') as f: 359 | for chunk in response.iter_content(chunk_size=1024): 360 | f.write(chunk) 361 | 362 | # scan QR code with phone 363 | if os.name == "nt": 364 | # for windows 365 | os.system('start ' + image_file) 366 | else: 367 | if os.uname()[0] == "Linux": 368 | # for linux platform 369 | os.system("eog " + image_file) 370 | else: 371 | # for Mac platform 372 | os.system("open " + image_file) 373 | 374 | # step 3: check scan result 375 | self.headers['Host'] = 'qr.m.jd.com' 376 | self.headers['Referer'] = 'https://passport.jd.com/new/login.aspx' 377 | 378 | # check if QR code scanned 379 | qr_ticket = None 380 | retry_times = 1000 # 尝试1000次 381 | while retry_times: 382 | retry_times -= 1 383 | response = self.sess.get( 384 | urls[2], 385 | headers=self.headers, 386 | cookies=self.cookies, 387 | params={ 388 | 'callback': 'jQuery%d' % random.randint(1000000, 9999999), 389 | 'appid': 133, 390 | 'token': self.cookies['wlfstk_smdl'], 391 | '_': int(time.time() * 1000) 392 | } 393 | ) 394 | if response.status_code != requests.codes.OK: 395 | continue 396 | rs = json.loads(re.search(r'{.*?}', response.text, re.S).group()) 397 | if rs['code'] == 200: 398 | self.updateStateText(f"{rs['ticket']}(Response Code: {rs['code']})") 399 | qr_ticket = rs['ticket'] 400 | break 401 | else: 402 | self.updateStateText(f"{rs['msg']}(Response Code: {rs['code']})") 403 | time.sleep(2) 404 | 405 | if not qr_ticket: 406 | self.updateStateText("ERROR: 二维码登录失败.") 407 | # self.isLogin = False 408 | return False 409 | 410 | # step 4: validate scan result 411 | self.headers['Host'] = 'passport.jd.com' 412 | self.headers['Referer'] = 'https://passport.jd.com/new/login.aspx' 413 | response = requests.get( 414 | urls[3], 415 | headers=self.headers, 416 | cookies=self.cookies, 417 | params={'t': qr_ticket}, 418 | ) 419 | if response.status_code != requests.codes.OK: 420 | self.updateStateText(f"二维码登录校验失败: {response.status_code}") 421 | # self.isLogin = False 422 | return False 423 | 424 | # 京东有时会认为当前登录有危险, 需要手动验证 425 | # url: https://safe.jd.com/dangerousVerify/index.action?username=... 426 | res = json.loads(response.text) 427 | if not response.headers.get('p3p'): 428 | if 'url' in res: 429 | self.updateStateText(f"请进行手动安全验证: {res['url']}") 430 | # self.isLogin = False 431 | return False 432 | else: 433 | self.updateStateText('登录失败, ERROR message: ' + res) 434 | # self.isLogin = False 435 | return False 436 | 437 | # login succeed 438 | self.headers['P3P'] = response.headers.get('P3P') 439 | self.cookies.update(response.cookies) 440 | self.sess.cookies = response.cookies 441 | 442 | 443 | # save cookie 444 | with open('cookie', 'wb') as f: 445 | pickle.dump(self.cookies, f) 446 | 447 | self.updateStateText("登录成功!") 448 | # self.isLogin = True 449 | self.getUsername() 450 | return True 451 | 452 | except Exception as e: 453 | # self.isLogin = False 454 | self.updateStateText('ERROR message: ' + str(e)) 455 | raise 456 | 457 | def getUsername(self): 458 | userName_Url = 'https://passport.jd.com/new/helloService.ashx?callback=jQuery339448&_=' + str( 459 | int(time.time() * 1000)) 460 | 461 | resp = self.sess.get(url=userName_Url, allow_redirects=True) 462 | resultText = resp.text 463 | resultText = resultText.replace('jQuery339448(', '') 464 | resultText = resultText.replace(')', '') 465 | usernameJson = json.loads(resultText) 466 | self.updateStateText('账号名称: ' + usernameJson['nick']) 467 | 468 | def checkStock(self): 469 | url = 'https://c0.3.cn/stocks' 470 | 471 | callback = 'jQuery' + str(random.randint(1000000, 9999999)) 472 | 473 | headers = { 474 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/531.36", 475 | "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", 476 | "Referer": "https://cart.jd.com/cart.action", 477 | "Connection": "keep-alive", 478 | } 479 | 480 | payload = { 481 | 'type': 'getstocks', 482 | 'skuIds': self.skuidString, 483 | 'area': self.areaID, 484 | 'callback': callback, 485 | '_': int(time.time() * 1000), 486 | } 487 | resp = self.sess.get(url=url, params=payload, headers=headers) 488 | respText = resp.text.replace(callback + '(', '').replace(')', '') 489 | respJson = json.loads(respText) 490 | inStockSkuid = [] 491 | nohasSkuid = [] 492 | abnormalSkuid = [] 493 | 494 | soldOut = 0 495 | alloca = 0 496 | for i in self.skuid: 497 | try: 498 | if respJson[i]['StockStateName'] == '无货': 499 | nohasSkuid.append(i) 500 | soldOut += 1 501 | elif respJson[i]['StockStateName'] == '可配货': 502 | nohasSkuid.append(i) 503 | alloca += 1 504 | else: 505 | inStockSkuid.append(i) 506 | 507 | except Exception as e: 508 | abnormalSkuid.append(i) 509 | 510 | if soldOut != 0: 511 | self.updateStateText('监控的 %d 个商品无货.' % soldOut) 512 | if alloca != 0: 513 | self.updateStateText('监控的 %d 个商品所在地区暂无货, 未来可能配货.' % alloca) 514 | if len(abnormalSkuid) > 0: 515 | self.updateStateText('WARNING: %s 编号商品查询异常.' % ','.join(abnormalSkuid)) 516 | return inStockSkuid 517 | 518 | def isSoldOut(self, sku_id): 519 | headers = { 520 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/531.36", 521 | "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", 522 | "Referer": "http://trade.jd.com/shopping/order/getOrderInfo.action", 523 | "Connection": "keep-alive", 524 | 'Host': 'item.jd.com', 525 | } 526 | url = 'https://item.jd.com/{}.html'.format(sku_id) 527 | page = requests.get(url=url, headers=headers) 528 | return '该商品已下柜' not in page.text 529 | 530 | def selectAll(self): 531 | url = "https://cart.jd.com/selectAllItem.action" 532 | data = { 533 | 't': 0, 534 | 'outSkus': '', 535 | 'random': random.random() 536 | } 537 | resp = self.sess.post(url, data=data) 538 | if resp.status_code != requests.codes.OK: 539 | self.updateStateText('全选购物车商品出错! status_code: %u, URL: %s' % (resp.status_code, resp.url)) 540 | return False 541 | self.updateStateText('全选购物车商品成功.') 542 | return True 543 | 544 | def cart_detail(self, isOutput=False): 545 | url = 'https://cart.jd.com/cart.action' 546 | resp = self.sess.get(url, headers=self.headers) 547 | soup = BeautifulSoup(resp.text, "html.parser") 548 | 549 | cartDetail = dict() 550 | for item in soup.find_all(class_='item-item'): 551 | sku_id = item['skuid'] # 商品id 552 | try: 553 | # 例如: ['increment', '8888', '100001071956', '1', '13', '0', '50067652554'] 554 | # ['increment', '8888', '100002404322', '2', '1', '0'] 555 | item_attr_list = item.find(class_='increment')['id'].split('_') 556 | p_type = item_attr_list[4] 557 | promo_id = target_id = item_attr_list[-1] if len(item_attr_list) == 7 else 0 558 | 559 | def get_tag_value(tag, key='', index=0): 560 | if key: 561 | value = tag[index].get(key) 562 | else: 563 | value = tag[index].text 564 | return value.strip(' \t\r\n') 565 | 566 | cartDetail[sku_id] = { 567 | 'name': get_tag_value(item.select('div.p-name a')), # 商品名称 568 | 'verder_id': item['venderid'], # 商家id 569 | 'count': int(item['num']), # 数量 570 | 'unit_price': get_tag_value(item.select('div.p-price strong'))[1:], # 单价 571 | 'total_price': get_tag_value(item.select('div.p-sum strong'))[1:], # 总价 572 | 'is_selected': 'item-selected' in item['class'], # 商品是否被勾选 573 | 'p_type': p_type, 574 | 'target_id': target_id, 575 | 'promo_id': promo_id 576 | } 577 | except Exception as e: 578 | self.updateStateText("ERROR: 商品%s在购物车中的信息无法解析, 报错信息: %s, 该商品自动忽略.", sku_id, e) 579 | 580 | if isOutput == True: 581 | self.updateStateText('当前购物车信息: %s.' % cartDetail) 582 | return cartDetail 583 | 584 | def addItemToCart(self, sku_id): 585 | url = 'https://cart.jd.com/gate.action' 586 | addNum = self.comboBox.currentIndex() + 1 587 | payload = { 588 | 'pid': sku_id, 589 | 'pcount': addNum, 590 | 'ptype': 1 591 | } 592 | resp = self.sess.get(url=url, params=payload) 593 | if 'https://cart.jd.com/cart.action' in resp.url: # 套装商品加入购物车后直接跳转到购物车页面 594 | result = True 595 | else: # 普通商品成功加入购物车后会跳转到提示 "商品已成功加入购物车!" 页面 596 | soup = BeautifulSoup(resp.text, "html.parser") 597 | result = bool(soup.select('h3.ftx-02')) # [

商品已成功加入购物车!

] 598 | 599 | if result: 600 | self.updateStateText('%s 编号商品已成功加入购物车, 数量: %d.' % (sku_id, addNum)) 601 | else: 602 | self.updateStateText('ERROR: %s 编号商品添加到购物车失败.' % sku_id) 603 | 604 | def responseStatus(self, resp): 605 | if resp.status_code != requests.codes.OK: 606 | self.updateStateText('Status: %u, Url: %s' % (resp.status_code, resp.url)) 607 | return False 608 | return True 609 | 610 | def getCheckoutPageDetail(self): 611 | url = 'http://trade.jd.com/shopping/order/getOrderInfo.action' 612 | # url = 'https://cart.jd.com/gotoOrder.action' 613 | payload = { 614 | 'rid': str(int(time.time() * 1000)), 615 | } 616 | headers = { 617 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36", 618 | "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", 619 | "Referer": "https://cart.jd.com/cart.action", 620 | "Connection": "keep-alive", 621 | 'Host': 'trade.jd.com', 622 | } 623 | try: 624 | resp = self.sess.get(url=url, params=payload, headers=headers) 625 | 626 | if not self.responseStatus(resp): 627 | self.updateStateText('ERROR: 获取订单结算页信息失败.') 628 | return None 629 | soup = BeautifulSoup(resp.text, "html.parser") 630 | 631 | order_detail = { 632 | 'address': soup.find('span', id='sendAddr').text[5:], 633 | 'receiver': soup.find('span', id='sendMobile').text[4:], 634 | 'total_price': soup.find('span', id='sumPayPriceId').text[1:], 635 | 'items': [] 636 | } 637 | 638 | self.updateStateText("下单信息: %s" % order_detail) 639 | return order_detail 640 | except requests.exceptions.RequestException as e: 641 | self.updateStateText('订单结算页面获取异常, ERROR message: %s.' % e) 642 | except Exception as e: 643 | self.updateStateText('下单页面数据解析异常, ERROR message: %s.' % e) 644 | return None 645 | 646 | def submit_order(self, risk_control, payment_pwd): 647 | url = 'https://trade.jd.com/shopping/order/submitOrder.action' 648 | # js function of submit order is included in https://trade.jd.com/shopping/misc/js/order.js?r=2018070403091 649 | 650 | # overseaPurchaseCookies: 651 | # vendorRemarks: [] 652 | # submitOrderParam.sopNotPutInvoice: false 653 | # submitOrderParam.trackID: TestTrackId 654 | # submitOrderParam.ignorePriceChange: 0 655 | # submitOrderParam.btSupport: 0 656 | # riskControl: 657 | # submitOrderParam.isBestCoupon: 1 658 | # submitOrderParam.jxj: 1 659 | # submitOrderParam.trackId: 660 | 661 | data = { 662 | 'overseaPurchaseCookies': '', 663 | 'vendorRemarks': '[]', 664 | 'submitOrderParam.sopNotPutInvoice': 'false', 665 | 'submitOrderParam.trackID': 'TestTrackId', 666 | 'submitOrderParam.ignorePriceChange': '0', 667 | 'submitOrderParam.btSupport': '0', 668 | 'riskControl': risk_control, 669 | 'submitOrderParam.isBestCoupon': 1, 670 | 'submitOrderParam.jxj': 1, 671 | 'submitOrderParam.trackId': '9643cbd55bbbe103eef18a213e069eb0', # Todo: need to get trackId 672 | # 'submitOrderParam.eid': eid, 673 | # 'submitOrderParam.fp': fp, 674 | 'submitOrderParam.needCheck': 1, 675 | } 676 | 677 | def encrypt_payment_pwd(paymentPwd): 678 | return ''.join(['u3' + x for x in paymentPwd]) 679 | 680 | if len(payment_pwd) > 0: 681 | data['submitOrderParam.payPassword'] = encrypt_payment_pwd(payment_pwd) 682 | 683 | headers = { 684 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36", 685 | "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", 686 | "Referer": "http://trade.jd.com/shopping/order/getOrderInfo.action", 687 | "Connection": "keep-alive", 688 | 'Host': 'trade.jd.com', 689 | } 690 | 691 | try: 692 | resp = self.sess.post(url=url, data=data, headers=headers) 693 | resp_json = json.loads(resp.text) 694 | 695 | if resp_json.get('success'): 696 | self.updateStateText('订单提交成功! 订单号: %s' % resp_json.get('orderId')) 697 | return True 698 | else: 699 | message, result_code = resp_json.get('message'), resp_json.get('resultCode') 700 | if result_code == 0: 701 | # self._save_invoice() 702 | message = message + '(下单商品可能为第三方商品, 将切换为普通发票进行尝试)' 703 | elif result_code == 60077: 704 | message = message + '(可能是购物车为空或未勾选购物车中商品)' 705 | elif result_code == 60123: 706 | message = message + '(未配置支付密码)' 707 | self.updateStateText('订单提交失败, 错误码: %s, 返回信息: %s.' % (result_code, message)) 708 | self.updateStateText(resp_json) 709 | return False 710 | except Exception as e: 711 | self.updateStateText("ERROR: " + str(e)) 712 | return False 713 | 714 | def cancelSelectCartItem(self): 715 | url = "https://cart.jd.com/cancelAllItem.action" 716 | data = { 717 | 't': 0, 718 | 'outSkus': '', 719 | 'random': random.random() 720 | } 721 | resp = self.sess.post(url, data=data) 722 | if resp.status_code != requests.codes.OK: 723 | self.updateStateText('cancelSelectCartItem() function WARNING: %u, Url: %s' % (resp.status_code, resp.url)) 724 | return False 725 | return True 726 | 727 | def buyGoods(self, sku_id): 728 | for i in range(1, 2): 729 | self.updateStateText('第 %d/%d 次尝试提交订单...' % (i, 2)) 730 | self.cancelSelectCartItem() 731 | cart = self.cart_detail() 732 | if sku_id not in cart: 733 | self.addItemToCart(sku_id) 734 | self.cart_detail(True) 735 | 736 | risk_control = self.getCheckoutPageDetail() 737 | if risk_control != None: 738 | if self.submit_order(risk_control, ''): 739 | return True 740 | time.sleep(1) 741 | else: 742 | self.updateStateText('执行结束,提交订单失败.') 743 | return False 744 | 745 | def monitorConnect(self): 746 | if self.checkLogin() == False: 747 | return False 748 | self.skuidString = self.inputGoods.text() 749 | pattern = re.compile(",|,") 750 | self.skuid = pattern.split(self.skuidString) 751 | 752 | self.areaID = self.inputArea.text() 753 | 754 | self.timer.timeout.connect(self.monitorMain) 755 | self.updateStateText("当前轮询速度为 %f 秒/次." % (self.speed / 1000)) 756 | if self.checkBox.isChecked(): 757 | self.isMonitorSoldout = False 758 | self.updateStateText('当前模式将为您自动忽略并删除下架商品.') 759 | else: 760 | self.isMonitorSoldout = True 761 | self.updateStateText('当前模式将为您保持监控下架商品, 若其上架则立即抢购.') 762 | self.timer.start(self.speed) # 设置计时间隔并启动 763 | return True 764 | 765 | def sendMail(self, url, isOrder): 766 | sendTo = self.inputMail.text() 767 | if len(sendTo) == 0 or sendTo == '$$$$$$$@qq.com': 768 | return 769 | 770 | mailRe = re.compile('^\w{1,15}@\w{1,10}\.(com|cn|net)$') 771 | if not re.search(mailRe, sendTo): 772 | return 773 | 774 | sendFrom = '645064582@qq.com' 775 | 776 | smtp_server = 'smtp.qq.com' 777 | if isOrder: 778 | msg = MIMEText('您抢购的 ' + url + ' 商品已下单, 请在尽快付款.', 'plain', 'utf-8') 779 | else: 780 | msg = MIMEText('您抢购的 ' + url + ' 商品下单失败.', 'plain', 'utf-8') 781 | 782 | msg['From'] = Header(sendFrom) 783 | msg['To'] = Header(sendTo) 784 | msg['Subject'] = Header('京东商品自动购买程序提示讯息') 785 | 786 | server = smtplib.SMTP_SSL(host=smtp_server) 787 | server.connect(smtp_server, 465) 788 | server.login(sendFrom, 'nkrzicfjkzznbehi') 789 | server.sendmail(sendFrom, sendTo, msg.as_string()) 790 | server.quit() 791 | 792 | def removeItem(self): 793 | url = "https://cart.jd.com/batchRemoveSkusFromCart.action" 794 | data = { 795 | 't': 0, 796 | 'null': '', 797 | 'outSkus': '', 798 | 'random': random.random(), 799 | 'locationId': '19-1607-4773-0' 800 | } 801 | headers = { 802 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.37", 803 | "Accept": "application/json, text/javascript, */*; q=0.01", 804 | "Referer": "https://cart.jd.com/cart.action", 805 | "Host": "cart.jd.com", 806 | "Content-Type": "application/x-www-form-urlencoded", 807 | "Accept-Encoding": "gzip, deflate, br", 808 | "Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7", 809 | "Origin": "https://cart.jd.com", 810 | "Connection": "keep-alive" 811 | } 812 | 813 | resp = self.sess.post(url, data=data, headers=headers) 814 | if resp.status_code != requests.codes.OK: 815 | self.updateStateText('清空购物车勾选商品出错. status_code: %u, URL: %s.' % (resp.status_code, resp.url)) 816 | return False 817 | 818 | self.updateStateText('清空购物车勾选商品成功!') 819 | return True 820 | 821 | def monitorMain(self): 822 | try: 823 | checkSession = requests.Session() 824 | checkSession.headers = { 825 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/531.36", 826 | "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", 827 | "Connection": "keep-alive" 828 | } 829 | self.updateStateText('第 ' + str(self.cont) + ' 次查询:') 830 | self.cont += 1 831 | inStockSkuid = self.checkStock() 832 | soldOutNum = 0 833 | for skuId in inStockSkuid: 834 | if self.isSoldOut(skuId): 835 | self.updateStateText('%s 编号商品有货啦! 马上下单.' % skuId) 836 | skuidUrl = 'https://item.jd.com/' + skuId + '.html' 837 | if self.buyGoods(skuId): 838 | self.sendMail(skuidUrl, True) 839 | else: 840 | self.sendMail(skuidUrl, False) 841 | self.stopNow() 842 | 843 | else: 844 | if self.isMonitorSoldout == False: 845 | self.updateStateText('%s 编号商品已下架.' % skuId) 846 | self.skuid.remove(skuId) 847 | idBeg = self.skuidString.find(str(skuId)) 848 | idEnd = idBeg + len(str(skuId)) 849 | self.skuidString = self.skuidString[0:idBeg] + self.skuidString[idEnd + 1:] 850 | self.inputGoods.setText(self.skuidString) 851 | self.updateStateText('已将 %s 编号的下架商品清除, 并更新了商品编号输入框.' % skuId) 852 | self.selectAll() 853 | self.removeItem() 854 | else: 855 | soldOutNum += 1 856 | if soldOutNum != 0: 857 | self.updateStateText('监控的 %d 个商品已下架, 但当前模式保持监控.' % soldOutNum) 858 | 859 | if self.cont % 300 == 0: 860 | self.checkLogin() 861 | except Exception as e: 862 | import traceback 863 | self.updateStateText(traceback.format_exc()) 864 | 865 | def updateStateText(self, stateText): 866 | # print(stateText) 867 | self.logger.info(stateText) 868 | self.textEdit.moveCursor(QtGui.QTextCursor.End) 869 | self.textEdit.insertPlainText(f'{time.ctime()} > ' + stateText + '\n') 870 | 871 | def main(): 872 | app = QApplication(sys.argv) 873 | test = Autobuy() 874 | sys.exit(app.exec_()) 875 | 876 | 877 | 878 | if __name__ == '__main__': 879 | main() -------------------------------------------------------------------------------- /GUI Version/image/down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jjjenkinson/autobuy-jd/1834e6d14b598f352ca71665335a3e2979e9eeb9/GUI Version/image/down.png -------------------------------------------------------------------------------- /GUI Version/image/left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jjjenkinson/autobuy-jd/1834e6d14b598f352ca71665335a3e2979e9eeb9/GUI Version/image/left.png -------------------------------------------------------------------------------- /GUI Version/image/right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jjjenkinson/autobuy-jd/1834e6d14b598f352ca71665335a3e2979e9eeb9/GUI Version/image/right.png -------------------------------------------------------------------------------- /GUI Version/jdAutoBuyGood.log: -------------------------------------------------------------------------------- 1 | 2020-11-09 05:57:59,029 INFO: 正在验证登录状态... 2 | 2020-11-09 05:57:59,174 INFO: 第 1 次再尝试验证cookie... 3 | 2020-11-09 05:57:59,175 INFO: 正在尝试从历史讯息中恢复... 4 | 2020-11-09 05:57:59,177 INFO: [Errno 2] 没有那个文件或目录: 'cookie' 5 | 2020-11-09 05:57:59,178 INFO: 第 1 次再尝试验证cookie... 6 | 2020-11-09 05:57:59,315 INFO: 第 2 次再尝试验证cookie... 7 | 2020-11-09 05:57:59,316 INFO: 正在尝试从历史讯息中恢复... 8 | 2020-11-09 05:57:59,316 INFO: [Errno 2] 没有那个文件或目录: 'cookie' 9 | 2020-11-09 05:57:59,317 INFO: 第 2 次再尝试验证cookie... 10 | 2020-11-09 05:57:59,317 INFO: 请登录! 11 | 2020-11-09 05:58:13,244 INFO: 请您打开京东手机客户端或微信扫一扫, 准备扫码登录 12 | 2020-11-09 05:58:13,715 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 13 | 2020-11-09 05:58:15,853 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 14 | 2020-11-09 05:58:18,006 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 15 | 2020-11-09 05:58:20,136 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 16 | 2020-11-09 05:58:22,424 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 17 | 2020-11-09 05:58:24,565 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 18 | 2020-11-09 05:58:26,709 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 19 | 2020-11-09 05:58:28,855 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 20 | 2020-11-09 05:58:30,993 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 21 | 2020-11-09 05:58:33,133 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 22 | 2020-11-09 05:58:35,270 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 23 | 2020-11-09 05:58:37,501 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 24 | 2020-11-09 05:58:39,637 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 25 | 2020-11-09 05:58:41,775 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 26 | 2020-11-09 05:58:43,918 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 27 | 2020-11-09 05:58:46,061 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 28 | 2020-11-09 05:58:48,203 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 29 | 2020-11-09 05:58:50,347 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 30 | 2020-11-09 05:58:52,655 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 31 | 2020-11-09 05:58:54,789 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 32 | 2020-11-09 05:58:56,933 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 33 | 2020-11-09 05:58:59,064 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 34 | 2020-11-09 05:59:01,208 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 35 | 2020-11-09 05:59:03,348 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 36 | 2020-11-09 05:59:05,540 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 37 | 2020-11-09 05:59:07,871 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 38 | 2020-11-09 05:59:10,014 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 39 | 2020-11-09 05:59:12,183 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 40 | 2020-11-09 05:59:14,329 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 41 | 2020-11-09 05:59:16,463 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 42 | 2020-11-09 05:59:18,609 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 43 | 2020-11-09 05:59:20,765 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 44 | 2020-11-09 05:59:23,118 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 45 | 2020-11-09 05:59:25,254 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 46 | 2020-11-09 05:59:27,392 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 47 | 2020-11-09 05:59:29,529 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 48 | 2020-11-09 05:59:31,671 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 49 | 2020-11-09 05:59:33,812 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 50 | 2020-11-09 05:59:36,174 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 51 | 2020-11-09 05:59:38,531 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 52 | 2020-11-09 05:59:40,669 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 53 | 2020-11-09 05:59:42,804 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 54 | 2020-11-09 05:59:44,952 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 55 | 2020-11-09 05:59:47,094 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 56 | 2020-11-09 05:59:49,242 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 57 | 2020-11-09 05:59:51,488 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 58 | 2020-11-09 05:59:53,731 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 59 | 2020-11-09 05:59:55,874 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 60 | 2020-11-09 05:59:58,024 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 61 | 2020-11-09 06:00:00,167 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 62 | 2020-11-09 06:00:02,302 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 63 | 2020-11-09 06:00:04,447 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 64 | 2020-11-09 06:00:06,859 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 65 | 2020-11-09 06:00:09,329 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 66 | 2020-11-09 06:00:11,472 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 67 | 2020-11-09 06:00:13,609 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 68 | 2020-11-09 06:00:15,753 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 69 | 2020-11-09 06:00:17,886 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 70 | 2020-11-09 06:00:20,024 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 71 | 2020-11-09 06:00:22,258 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 72 | 2020-11-09 06:00:24,497 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 73 | 2020-11-09 06:00:26,638 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 74 | 2020-11-09 06:00:28,775 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 75 | 2020-11-09 06:00:30,923 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 76 | 2020-11-09 06:02:05,725 INFO: 请您打开京东手机客户端或微信扫一扫, 准备扫码登录 77 | 2020-11-09 06:02:06,231 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 78 | 2020-11-09 06:02:08,507 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 79 | 2020-11-09 06:02:10,653 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 80 | 2020-11-09 06:02:12,792 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 81 | 2020-11-09 06:02:14,939 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 82 | 2020-11-09 06:02:17,074 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 83 | 2020-11-09 06:02:19,214 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 84 | 2020-11-09 06:02:21,502 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 85 | 2020-11-09 06:02:23,738 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 86 | 2020-11-09 06:02:25,873 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 87 | 2020-11-09 06:02:28,006 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 88 | 2020-11-09 06:02:30,148 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 89 | 2020-11-09 06:02:32,295 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 90 | 2020-11-09 06:02:34,433 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 91 | 2020-11-09 06:02:36,655 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 92 | 2020-11-09 06:02:38,949 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 93 | 2020-11-09 06:02:41,096 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 94 | 2020-11-09 06:02:43,231 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 95 | 2020-11-09 06:02:45,365 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 96 | 2020-11-09 06:02:47,495 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 97 | 2020-11-09 06:02:49,628 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 98 | 2020-11-09 06:02:52,025 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 99 | 2020-11-09 06:02:54,268 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 100 | 2020-11-09 06:02:56,408 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 101 | 2020-11-09 06:02:58,550 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 102 | 2020-11-09 06:03:00,685 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 103 | 2020-11-09 06:03:02,825 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 104 | 2020-11-09 06:03:04,968 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 105 | 2020-11-09 06:03:07,280 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 106 | 2020-11-09 06:03:09,429 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 107 | 2020-11-09 06:03:11,561 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 108 | 2020-11-09 06:03:13,702 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 109 | 2020-11-09 06:03:15,838 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 110 | 2020-11-09 06:03:17,977 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 111 | 2020-11-09 06:03:20,128 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 112 | 2020-11-09 06:03:22,430 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 113 | 2020-11-09 06:03:24,567 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 114 | 2020-11-09 06:03:26,701 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 115 | 2020-11-09 06:03:28,839 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 116 | 2020-11-09 06:03:30,976 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 117 | 2020-11-09 06:03:33,114 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 118 | 2020-11-09 06:03:35,256 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 119 | 2020-11-09 06:03:37,485 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 120 | 2020-11-09 06:03:39,608 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 121 | 2020-11-09 06:03:41,750 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 122 | 2020-11-09 06:03:43,889 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 123 | 2020-11-09 06:03:46,030 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 124 | 2020-11-09 06:03:48,169 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 125 | 2020-11-09 06:03:50,312 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 126 | 2020-11-09 06:03:52,633 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 127 | 2020-11-09 06:03:54,775 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 128 | 2020-11-09 06:03:56,924 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 129 | 2020-11-09 06:03:59,067 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 130 | 2020-11-09 06:04:01,202 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 131 | 2020-11-09 06:04:03,334 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 132 | 2020-11-09 06:04:05,545 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 133 | 2020-11-09 06:04:07,767 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 134 | 2020-11-09 06:04:09,899 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 135 | 2020-11-09 06:04:12,041 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 136 | 2020-11-09 06:04:14,181 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 137 | 2020-11-09 06:04:16,319 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 138 | 2020-11-09 06:04:18,459 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 139 | 2020-11-09 06:04:20,699 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 140 | 2020-11-09 06:04:22,932 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 141 | 2020-11-09 06:04:25,073 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 142 | 2020-11-09 06:04:27,213 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 143 | 2020-11-09 06:04:29,354 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 144 | 2020-11-09 06:04:31,488 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 145 | 2020-11-09 06:04:33,630 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 146 | 2020-11-09 06:04:35,838 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 147 | 2020-11-09 06:04:38,167 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 148 | 2020-11-09 06:04:40,302 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 149 | 2020-11-09 06:04:42,444 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 150 | 2020-11-09 06:04:44,592 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 151 | 2020-11-09 06:04:46,725 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 152 | 2020-11-09 06:04:48,864 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 153 | 2020-11-09 06:04:50,998 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 154 | 2020-11-09 06:04:53,254 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 155 | 2020-11-09 06:04:55,396 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 156 | 2020-11-09 06:04:57,538 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 157 | 2020-11-09 06:04:59,680 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 158 | 2020-11-09 06:05:01,816 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 159 | 2020-11-09 06:05:03,955 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 160 | 2020-11-09 06:05:06,194 INFO: 二维码未扫描,请扫描二维码(Response Code: 201) 161 | 2020-11-09 06:05:08,544 INFO: 二维码过期,请重新扫描(Response Code: 203) 162 | 2020-11-09 06:05:10,691 INFO: 二维码过期,请重新扫描(Response Code: 203) 163 | 2020-11-09 06:05:12,827 INFO: 二维码过期,请重新扫描(Response Code: 203) 164 | 2020-11-09 06:05:14,965 INFO: 二维码过期,请重新扫描(Response Code: 203) 165 | 2020-11-09 06:05:17,109 INFO: 二维码过期,请重新扫描(Response Code: 203) 166 | 2020-11-09 06:05:19,250 INFO: 二维码过期,请重新扫描(Response Code: 203) 167 | 2020-11-09 06:05:21,617 INFO: 二维码过期,请重新扫描(Response Code: 203) 168 | 2020-11-09 06:05:23,869 INFO: 二维码过期,请重新扫描(Response Code: 203) 169 | 2020-11-09 06:05:26,008 INFO: 二维码过期,请重新扫描(Response Code: 203) 170 | 2020-11-09 06:05:28,157 INFO: 二维码过期,请重新扫描(Response Code: 203) 171 | 2020-11-09 06:05:30,299 INFO: 二维码过期,请重新扫描(Response Code: 203) 172 | 2020-11-09 06:05:32,436 INFO: 二维码过期,请重新扫描(Response Code: 203) 173 | 2020-11-09 06:05:34,572 INFO: 二维码过期,请重新扫描(Response Code: 203) 174 | 2020-11-09 06:05:36,873 INFO: 二维码过期,请重新扫描(Response Code: 203) 175 | 2020-11-09 06:05:39,040 INFO: 二维码过期,请重新扫描(Response Code: 203) 176 | 2020-11-09 06:05:41,165 INFO: 二维码过期,请重新扫描(Response Code: 203) 177 | 2020-11-09 06:05:43,315 INFO: 二维码过期,请重新扫描(Response Code: 203) 178 | 2020-11-09 06:05:45,455 INFO: 二维码过期,请重新扫描(Response Code: 203) 179 | -------------------------------------------------------------------------------- /GUI Version/qr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jjjenkinson/autobuy-jd/1834e6d14b598f352ca71665335a3e2979e9eeb9/GUI Version/qr.png -------------------------------------------------------------------------------- /GUI Version/window.qss: -------------------------------------------------------------------------------- 1 | /* 2 | Notice: 3 | 01 注释只能用多行注释,单行注释会出错 4 | */ 5 | /*******定义字体,背景颜色*********/ 6 | *{ 7 | font: "微软雅黑"; 8 | color: rgb(220, 220, 220); 9 | background-color: rgb(68, 68, 68); 10 | border-radius: 2px; 11 | padding: 3px; 12 | margin: 2px; 13 | } 14 | /****************定义边框*****************/ 15 | QLineEdit, QPushButton, QTimeEdit, 16 | QSpinBox, QDoubleSpinBox, QComboBox, 17 | QDateEdit, QDateTimeEdit, QGroupBox, 18 | QTextEdit, QTabWidget { 19 | border:1px solid rgb(36, 36, 36); 20 | } 21 | /*************菜单下拉按钮*****************/ 22 | QMenu::item { 23 | background-color: transparent; 24 | } 25 | /********菜单下拉按钮(被选择时)***********/ 26 | QMenu::item:selected { 27 | background-color: rgb(100, 100, 100); 28 | } 29 | /****************定义菜单栏***************/ 30 | QMenuBar { 31 | border-radius: 0; 32 | background-color: rgb(72, 72, 72); 33 | border-bottom: 1px solid rgb(36, 36, 36); 34 | } 35 | /************菜单栏按钮(被选择时)********/ 36 | QMenuBar::item:selected { 37 | background-color: rgb(100, 100, 100); 38 | } 39 | /************菜单栏按钮(鼠标悬停)********/ 40 | QMenu:hover { 41 | background-color: rgb(100, 100, 100); 42 | } 43 | /*********按钮(渐变:突出显示)***********/ 44 | QPushButton { 45 | border-style: inset; 46 | background-color: qlineargradient(spread:pad, x1:0.5, y1:0, x2:0.5, y2:1, stop:0 rgba(72, 72, 72, 255), stop:1 rgba(56, 56, 56, 255)); 47 | border:1px solid rgb(36, 36, 36); 48 | border-radius: 6px; 49 | min-width: 5em; 50 | min-height: 1em; 51 | padding: 6px 6px; 52 | margin: 5px 53 | } 54 | /**************按钮(鼠标悬停)**********/ 55 | QPushButton:hover { 56 | background-color: rgb(91, 91, 91); 57 | } 58 | /**************按钮(按下)*************/ 59 | QPushButton:pressed { 60 | background-color: rgb(68, 68, 68); 61 | } 62 | QSpinBox::up-button, QTimeEdit::up-button, 63 | QDateEdit::up-button, QDateTimeEdit::up-button, 64 | QDoubleSpinBox::up-button { 65 | subcontrol-position: right; 66 | border: 0px; 67 | } 68 | QSpinBox::down-button, QTimeEdit::down-button, 69 | QDateEdit::down-button, QDateTimeEdit::down-button, 70 | QDoubleSpinBox::down-button { 71 | subcontrol-position: left; 72 | border: 0px; 73 | } 74 | QSpinBox::up-arrow, QTimeEdit::up-arrow, 75 | QDateEdit::up-arrow, QDateTimeEdit::up-arrow, 76 | QDoubleSpinBox::up-arrow { 77 | image: url(image/right.png); 78 | } 79 | QSpinBox::down-arrow, QTimeEdit::down-arrow, 80 | QDateEdit::down-arrow, QDateTimeEdit::down-arrow, 81 | QDoubleSpinBox::down-arrow { 82 | image: url(image/left.png); 83 | } 84 | /*********定义Slider槽的形态**************/ 85 | QSlider::groove:horizontal { 86 | height: 6px; 87 | border-radius: 3px; 88 | } 89 | /*********定义Slider柄的形态**************/ 90 | QSlider::handle:horizontal { 91 | background-color: rgb(68, 68, 68); 92 | border-radius: 5px; 93 | border: 2px solid rgb(36, 36, 36); 94 | height: 8px; 95 | width: 8px; 96 | margin: -3px -3px; 97 | } 98 | /*********定义handle右边的背景**************/ 99 | QSlider::add-page:horizontal{ 100 | background: rgb(72, 72, 72); 101 | } 102 | /*********定义handle左边的背景**************/ 103 | QSlider::sub-page:horizontal{ 104 | background: rgb(36, 36, 36); 105 | } 106 | /****************定义进度条****************/ 107 | QProgressBar { 108 | border: 2px solid grey; 109 | border-radius: 5px; 110 | text-align: center; 111 | height: 12px; 112 | } 113 | /*************定义进度条背景**************/ 114 | QProgressBar::chunk { 115 | background-color: rgb(128, 128, 128); 116 | width: 8px; 117 | margin: 0.5px; 118 | } 119 | 120 | QTabWidget::pane { /* The tab widget frame */ 121 | border: 1px solid rgb(36, 36, 36); 122 | } 123 | QTabWidget::tab-bar { 124 | border: 1px solid rgb(36, 36, 36); 125 | } 126 | QTabBar::tab { 127 | background: qlineargradient(spread:pad, x1:0.5, y1:0, x2:0.5, y2:1, stop:0 rgba(100, 100, 100, 255), stop:1 rgba(82, 82, 82, 255)); 128 | border: 1px solid rgb(36, 36, 36); 129 | border-bottom-color: #C2C7CB; /* same as the pane color */ 130 | min-width: 12ex; 131 | min-height: 6ex; 132 | padding: 2px 4px; 133 | } 134 | QTabBar::tab:selected, QTabBar::tab:hover { 135 | border-top: 2px solid red; 136 | padding-top: 3px; 137 | background: qlineargradient(spread:pad, x1:0.5, y1:0, x2:0.5, y2:1, stop:0 rgba(72, 72, 72, 255), stop:1 rgba(56, 56, 56, 255)); 138 | } 139 | /*************QComboBox******************/ 140 | QComboBox::drop-down { 141 | subcontrol-origin: padding; 142 | subcontrol-position: top right; 143 | width: 20px; 144 | border: 0px; 145 | } 146 | QComboBox::down-arrow { 147 | image: url(image/down.png); 148 | } 149 | QComboBox::down-arrow:on { /* shift the arrow when popup is open */ 150 | top: 1px; 151 | left: 1px; 152 | } 153 | /*********下拉列表的item背景***************/ 154 | QComboBox QAbstractItemView { 155 | border: 0px; 156 | selection-background-color: rgb(100, 100, 100); 157 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Yikai Zhang 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 | # auto-buy-Python-tool 2 | 图形界面, 电脑小白也会用, 下载可直接运行! 京东自动购买口罩 实时抢购口罩 工具, 抗击疫情 中国加油! 3 | 4 | `4.0` :fire: 5 | 6 | 点击这里 下载`JDAutoBuy-release.zip`, 解压后可**直接运行!** 7 | 8 | ### 欢迎加星 9 | 10 | > 修复了商品下架后的问题, 更新了交互界面; 修复了可配货商品的判断, 更新了数量调整接口, 更新了是否监控下架商品选项 11 | 12 | :star2: 13 | 14 | 15 | 16 | 17 | 18 | ## 使用指南 19 | 20 | ### :notebook_with_decorative_cover: Tips: 登录一次之后本地会保存登录信息, 重启软件(注意重启之后也行)之后仍然可以记住账号登录信息, 重启之后只需点击"开始监控"就可以登录! 不必重复扫码! 21 | 22 | 运行界面**如下图**: 23 | 24 | ![interface](./assets/1581218076866.png) 25 | 26 | Update at 2020-3-2: Continuously monitor goods removed from JD.![monitorSoldOutGoods](./assets/1583151909197.png) 27 | 28 | Update at 2020-2-15: quantity can be modified![quantity](./assets/1581768213048.png) 29 | 30 | ### 填写方式: 31 | 32 | Tips: 软件启动时带有标准填写格式的默认值, 请留意. 33 | 34 | + **输入商品ID:** 比如`URL`为: https://item.jd.com/1835967.html 的商品ID为**1835967**. 35 | + **输入收件地区编码**: 使用Chrome浏览器(如果是其他浏览器请用同样方式打开**开发者工具**)登录京东并访问商品页, 选择派送地址后按`F12`查找`stock?`开头的`URL`讯息, 如下图: ![AreaID](./assets/1581218537205.png) 36 | + **接受讯息邮箱**: 您的接受讯息邮箱. 37 | + **滑动条**: 控制监控时查询的速度(频率). 38 | + **购买数量**: 调整一次购买数量. 39 | + **是否自动忽略下架商品**: 未打勾 - 下架商品上架时立即抢购, 打勾 - 自动忽略下架商品并删除. 40 | 41 | 42 | 43 | 以下选项您可以不看也会使用: 44 | 45 | **扫码登录**: 如果京东手机客户端无法扫码, 请用**微信**扫一扫试一下. 46 | 47 | **开始监控**: 如果**未登录点击此按钮**, 您之前登录成功过则会读取历史登录记录尝试登录, 否则会提示您先扫码登录. 48 | 49 | 以下是有货时购买的界面, 祝您成功. 50 | 51 | ![success](./assets/1581508416184.png) 52 | 53 | 更新后`2.0`运行界面: 54 | 55 | ![updateRun](./assets/1581508444771.png) 56 | 57 | Update at 2020-2-15 20:06:14: 最近比较难抢了, 因为京东一些商品是预约完再抢购, 预约完之后即被放入购物车, 导致监控有货无货较困难. 见谅. 58 | 59 | --- 60 | 61 | ## 以下是控制台版本程序的说明, 如果您使用图形界面版本, 可以不看 62 | 63 | **获取登录*cookie***: Chrome 登录京东后`F12`, 如下图. 64 | 65 | ![1580963259089](./assets/1580963259089.png) 66 | 67 | 68 | 69 | **获取商品URL**: 登录并访问商品页, 选择派送地址后查找**stock?**开头的URL讯息, 如下图. 70 | 71 | ![1580963623908](./assets/1580963623908.png) 72 | 73 | 请注意商品`URL`需要是您的地址编号, 如TXT文件中`area=`参数. 74 | 75 | 76 | 77 | **以上两步**获得的讯息填入`Please fill out this document.txt`文件. 78 | 79 | ```shell 80 | pip install -r requirements.txt 81 | python JDAutoBuyTool.py 82 | ``` 83 | 84 | 85 | 86 | **运行环境**: 87 | 88 | `Windows 10, Python 3` 89 | 90 | **运行示例**: 91 | 92 | ![1581038258274](./assets/1581038258274.png) 93 | 94 | --- 95 | 96 | 感谢[cycz](https://github.com/cycz)大佬, 参考了部分代码. 97 | 98 | 心情复杂, 也不懂抢口罩工具能不能帮上忙, **一定能尽快战胜疫情! 中国加油!** :star2: -------------------------------------------------------------------------------- /assets/1580963259089.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jjjenkinson/autobuy-jd/1834e6d14b598f352ca71665335a3e2979e9eeb9/assets/1580963259089.png -------------------------------------------------------------------------------- /assets/1580963623908.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jjjenkinson/autobuy-jd/1834e6d14b598f352ca71665335a3e2979e9eeb9/assets/1580963623908.png -------------------------------------------------------------------------------- /assets/1581038258274.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jjjenkinson/autobuy-jd/1834e6d14b598f352ca71665335a3e2979e9eeb9/assets/1581038258274.png -------------------------------------------------------------------------------- /assets/1581218076866.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jjjenkinson/autobuy-jd/1834e6d14b598f352ca71665335a3e2979e9eeb9/assets/1581218076866.png -------------------------------------------------------------------------------- /assets/1581218537205.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jjjenkinson/autobuy-jd/1834e6d14b598f352ca71665335a3e2979e9eeb9/assets/1581218537205.png -------------------------------------------------------------------------------- /assets/1581249279630.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jjjenkinson/autobuy-jd/1834e6d14b598f352ca71665335a3e2979e9eeb9/assets/1581249279630.png -------------------------------------------------------------------------------- /assets/1581508416184.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jjjenkinson/autobuy-jd/1834e6d14b598f352ca71665335a3e2979e9eeb9/assets/1581508416184.png -------------------------------------------------------------------------------- /assets/1581508444771.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jjjenkinson/autobuy-jd/1834e6d14b598f352ca71665335a3e2979e9eeb9/assets/1581508444771.png -------------------------------------------------------------------------------- /assets/1581768204211.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jjjenkinson/autobuy-jd/1834e6d14b598f352ca71665335a3e2979e9eeb9/assets/1581768204211.png -------------------------------------------------------------------------------- /assets/1581768213048.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jjjenkinson/autobuy-jd/1834e6d14b598f352ca71665335a3e2979e9eeb9/assets/1581768213048.png -------------------------------------------------------------------------------- /assets/1583151909197.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jjjenkinson/autobuy-jd/1834e6d14b598f352ca71665335a3e2979e9eeb9/assets/1583151909197.png --------------------------------------------------------------------------------