├── nike.db ├── README.md ├── nike.db ├── .idea ├── vcs.xml ├── misc.xml ├── modules.xml ├── snkrs.iml └── workspace.xml ├── main2.py ├── .gitignore ├── WebLoginnk.py ├── snkrs.py ├── main.py └── loginnk.py / nike.db: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # snkrsbot 2 | snkrs多线程抢购 3 | -------------------------------------------------------------------------------- /nike.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/13476075014/snkrsbot/HEAD/nike.db -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/snkrs.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 11 | -------------------------------------------------------------------------------- /main2.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | from loginnk import * 3 | import re 4 | import requests 5 | from WebLoginnk import * 6 | import threading,sqlite3,time 7 | from multiprocessing import Process 8 | from multiprocessing import Queue 9 | 10 | def partdraw(chouqian): 11 | 12 | print("nihao") 13 | conn = sqlite3.connect("nike.db") 14 | conn.text_factory = str 15 | c = conn.cursor() 16 | allUser = c.execute("SELECT * from nike").fetchall() 17 | for user in allUser: 18 | username = user[2] 19 | password = user[3] 20 | refreshToken = user[1] 21 | # print("%s %s %s",username,password,refreshToken) 22 | #参与抽签 23 | partdraw() 24 | c.close() 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | -------------------------------------------------------------------------------- /WebLoginnk.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | import json 3 | import random 4 | import traceback 5 | import requests 6 | from selenium import webdriver 7 | from selenium.webdriver import ActionChains 8 | from selenium.webdriver.support.wait import WebDriverWait 9 | 10 | 11 | class WebLogin_Chrome: 12 | def __init__(self, username, password): 13 | self.cookies = None 14 | self.session = requests.session() 15 | self.userInfo = None 16 | 17 | self.username = username 18 | self.password = password 19 | 20 | def login(self): 21 | try: 22 | chromeOptions = webdriver.ChromeOptions() 23 | # 无界面 24 | # chromeOptions.add_argument('--headless') 25 | # 禁用gpu加速 26 | chromeOptions.add_argument('--disable-gpu') 27 | # 关闭图片 28 | prefs = {"profile.managed_default_content_settings.images": 2} 29 | chromeOptions.add_experimental_option("prefs", prefs) 30 | 31 | driver = webdriver.Chrome(chrome_options=chromeOptions) 32 | 33 | w_h = driver.get_window_size() 34 | width = w_h["width"] 35 | height = w_h["height"] 36 | 37 | clickWidth1 = (width - 500) / 2 38 | clickWidth2 = width / 2 + 250 39 | 40 | driver.get("https://www.nike.com/cn/zh_cn/") 41 | WebDriverWait(driver, 15).until(lambda x: x.find_element_by_class_name('login-text')) 42 | driver.find_element_by_class_name('login-text').click() 43 | 44 | # 随机位置点击绕过验证 45 | for i in range(random.randint(2, 5)): 46 | ActionChains(driver).move_by_offset(clickWidth1, 47 | random.randint(0, height)).click().perform() 48 | ActionChains(driver).move_by_offset(clickWidth2, 49 | random.randint(0, height)).click().perform() 50 | 51 | driver.find_element_by_name('verifyMobileNumber').send_keys(self.username) 52 | driver.find_element_by_name('password').send_keys(self.password) 53 | driver.find_element_by_class_name('nike-unite-submit-button').click() 54 | 55 | # 随机位置点击绕过验证 56 | for i in range(random.randint(2, 5)): 57 | ActionChains(driver).move_by_offset(clickWidth1, 58 | random.randint(0, height)).click().perform() 59 | ActionChains(driver).move_by_offset(clickWidth2, 60 | random.randint(0, height)).click().perform() 61 | try: 62 | WebDriverWait(driver, 5).until_not( 63 | lambda x: x.find_element_by_class_name('exp-join-login').is_displayed()) 64 | except: 65 | # print("等待超时...") 66 | pass 67 | if not driver.find_element_by_xpath('//*[@id="nike-unite-mobileLoginForm"]/div[1]').is_displayed(): 68 | WebDriverWait(driver, 10).until_not( 69 | lambda x: x.find_element_by_class_name('exp-join-login').is_displayed()) 70 | 71 | self.cookies = driver.get_cookies() 72 | 73 | driver.get("https://unite.nike.com/session.html") 74 | userInfo = driver.execute_script( 75 | "return localStorage.getItem('com.nike.commerce.nikedotcom.web.credential');") 76 | self.userInfo = json.loads(userInfo) 77 | except: 78 | traceback.print_exc() 79 | finally: 80 | driver.close() 81 | driver.quit() 82 | 83 | def getCookies(self): 84 | cookies = "" 85 | if self.cookies != None: 86 | for cookie in self.cookies: 87 | cookies += (cookie['name'] + "=" + cookie['value'] + ";") 88 | return cookies -------------------------------------------------------------------------------- /snkrs.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | import requests,time,json 3 | from selenium import webdriver 4 | 5 | chromeOptions = webdriver.ChromeOptions() 6 | #无界面 7 | #chromeOptions.add_argument('--headless') 8 | #关闭图片 9 | prefs = {"profile.managed_default_content_settings.images": 2} 10 | chromeOptions.add_experimental_option("prefs", prefs) 11 | #禁用gpu加速 12 | chromeOptions.add_argument('--disable-gpu') 13 | browser=webdriver.Chrome(chrome_options=chromeOptions) 14 | 15 | browser.get("https://www.nike.com/cn/zh_cn/") 16 | login=browser.find_element_by_class_name("login-text") 17 | login.click() 18 | login1=browser.find_elements_by_tag_name("a") 19 | login1[264].click() 20 | username=browser.find_element_by_name("emailAddress") 21 | username.send_keys("lktop@vip.qq.com") 22 | password=browser.find_element_by_name("password") 23 | password.send_keys("huanxiangmf1Q") 24 | loginbu=browser.find_elements_by_tag_name("input") 25 | loginbu[7].click() 26 | time.sleep(5) 27 | acookies = browser.get_cookies() 28 | cookie="" 29 | if acookies != None: 30 | for i in acookies: 31 | cookie += (i['name'] + "=" + i['value'] + ";") 32 | #print cookie 33 | head={ 34 | "accept":"*/*", 35 | "accept-encoding": "gzip, deflate, br", 36 | "accept-language": "zh-CN,zh;q=0.9", 37 | "cache-control": "no-cache", 38 | "cookie": '''AnalysisUserId=183.60.197.103.103401539491276992; anonymousId=7BE12371D7FF8715B6B0BD9D408C75CE; guidU=a6e97f21-5101-459e-adf7-e585e219da0d; neo.swimlane=45; cicPWIntercept=1; _gcl_au=1.1.1525637876.1539491304; ajs_user_id=null; ajs_group_id=null; ajs_anonymous_id=%227BE12371D7FF8715B6B0BD9D408C75CE%22; CONSUMERCHOICE_SESSION=t; RES_TRACKINGID=777245231343142; ResonanceSegment=1; _gscu_207448657=394913175rv8lz17; _smt_uid=5bc2c5f5.4e697c8b; lls=3; siteCatalyst_sample=79; dreamcatcher_sample=19; neo_sample=53; NIKE_CART=b:c; NIKE_COMMERCE_COUNTRY=CN; NIKE_COMMERCE_LANG_LOCALE=zh_CN; CONSUMERCHOICE=cn/zh_cn; cicIntercept=1; neo.experiments=%7B%22main%22%3A%7B%223333-interceptor-cn%22%3A%22a%22%2C%220001%22%3A%22a%22%7D%2C%22thirdparty%22%3A%7B%7D%2C%22snkrs%22%3A%7B%7D%2C%22ocp%22%3A%7B%7D%7D; dreams_sample=81; DAPROPS="sdevicePixelRatio:1|sdeviceAspectRatio:16/9|bcookieSupport:1"; Hm_lvt_ed406c6497cc3917d06fd572612b4bba=1541683422; _qzja=1.1540173633.1541683422347.1541683422347.1541683422347.1541683432979.1541683432989..0.0.5.1; _abck=B8713214F31DF576A68BE3559AA55356~0~YAAQZCCEtv3oRNRmAQAA12Z+8wA1hKH/hKkH/aWS5uiD9vQK7fTMBGtJolG9lWI2X/zmxA5eCMXJRHvtWU5nJCtIImlL+fI3e6M+mQOQ4tY/Un7VOL/bhNiKzu5GKPrEASi3mOXVN4KklzIHu96JWy8mWB2uC8pAaBmWHD+3ByQV0eVV6ytzPLpWUXpyJYenk/jZzTbSmhVRYLxTJk3CAzQ2bxRl9C32zVChw4dVr7Cun6UWrFNAapvi4a8/haYUAKGyLGBsE8mHMooCsqa5NZEpPQ+WwGtRBcNjxLdOgshDryU55ZOn~-1~-1~-1; guidS=2e3cc0e5-50d7-48eb-d25d-e9c6c470fb60; guidSTimestamp=1541738243660|1541738447570; slCheck=p3R8AIZyGAY7sAexQaSJunIzfRoO6K5Ikpxtb/VQzdf3hLCKiK5PcS2ry12OQUL5LemYkFAUOM+ji1VpQLgNM7hIvEq6OMyEjH5v1u+wcaBKdV3S1ix0bDwu4Rj4KQxi; llCheck=ldrPb4mb57cawquFbnCVqtixTR/Wg/sHvJquFPTX6FAOVQUzkoEcExAJ3ZckFnLiUFFDAyUp0UQMGdUm6Avrupr0srhhYy9fYfpsRFccGhV+gBug5rUbYnyY1Yysz9/t/LAvxcNylGXQbo+RKPMg9OBDxsTITFcCc5d9kdBw8Ww=; bm_sz=92BB9CA0B2E244F7604A25B55720F54E~QAAQxPLzPy3rzdJmAQAAZOSN+A+OJESmuKu62THFSHWbZBTYTWSRNERhJwuhSvWExBXB9xCiXDSoRr8tYQlZzzZpJVDW8OBcrgrWl6CeV3M4Vo+XiHzD6Czbdsku41wFDDolvLTytI/UV2MEAwkI7n/AwtwPxdhUrFOHVrlJi8Oc9NFG1f+j9uCGgpPk; ak_bmsc=B30A0C36228384015D971BA8262590CDB73CC567865500008685E55BFF6D4E65~pl4mrzyOo/LOsTaYhqWemib8HzeuwcplVP2DgjLArOUdbyr9FdHjUEoO5F14OKMkrrjgNgjvX7/3tyEFWRHypxF3AYFNXQe83KuzSeasvdHQcmKNPakWQaxUDZtOj443ilwUnCxk2FQijIop8Y5+cf3ZdgBZjOrvBg+8AhAVp0DDxUTsWcXk+W82d0rYLjsXgVz4MOfUjMnNIdCb4nFxkHt7KALAbZwze13up4ih0RtteGDRTt0YomPvUjxYw3yZ+J3XMIoMsstlxdgzExpDlXvEAwZLUVgDrkP0wC4FLLH7hZmFWi7piphD0KS9BIWqBNPdwcN22P8jJ9kIIelqKWSQ==; mm_wc_pmt=1; _gscbrs_207448657=1; AMCVS_F0935E09512D2C270A490D4D%40AdobeOrg=1; AMCV_F0935E09512D2C270A490D4D%40AdobeOrg=690614123%7CMCIDTS%7C17845%7CMCMID%7C81273656479516255450967188602063724350%7CMCAAMLH-1542373508%7C11%7CMCAAMB-1542373508%7CRKhpRz8krg2tLO6pguXWp5olkAcUniQYPHaMWWgdJ3xzPWQmdj0y%7CMCOPTOUT-1541775908s%7CNONE%7CMCAID%7CNONE%7CvVersion%7C3.1.0; APID=C7DF1D25802F715CFC07EA0268F217F9.sin-333-app-ap-0; sls=1; CART_SUMMARY=%7B%22profileId%22+%3A%2218571452869%22%2C%22userType%22+%3A%22DEFAULT_USER%22%2C%22securityStatus%22+%3A%221%22%2C%22cartCount%22+%3A0%7D; exp.swoosh.user=%7B%22granted%22%3A0%7D; RES_SESSIONID=173321429392054; ppd=homepage%7Cnikecom%3Ehomepage; utag_main=_st:1541770728072$ses_id:1541769412741%3Bexp-session; NIKE_CART_SESSION={%22bucket%22:%22jcart%22%2C%22country%22:%22CN%22%2C%22id%22:0%2C%22merged%22:false}; _gscs_207448657=41768707r37jpz19|pv:3; s_sess=%20c51%3Dhorizontal%3B%20prevList2%3D%3B%20s_cc%3Dtrue%3B%20tp%3D6122%3B%20s_ppv%3Dunified%252520profile%25253Elogin%252C15%252C15%252C947%3B; RT="sl=3&ss=1541768585969&tt=46230&obo=0&sh=1541768938553%3D3%3A0%3A46230%2C1541768922014%3D2%3A0%3A30002%2C1541768707214%3D1%3A0%3A4895&dm=nike.com&si=c7430edb-3a32-4e45-9f0f-da5df251b30a&bcn=%2F%2F17d98a5e.akstat.io%2F&ld=1541768938554&nu=https%3A%2F%2Fwww.nike.com%2Fcn%2Fzh_ch%2Fc%2Fnike-plus&cl=1541769101970&r=https%3A%2F%2Fwww.nike.com%2Fcn%2Fzh_cn%2F&ul=1541769101982&hd=1541769129944"; nike_locale=cn/zh_cn; bm_sv=86BA91B8A14E3ED6A91A03AB2314EED9~g5KC366LXL4lHnJyGJ8KXHvJ5zRyuIj1b2NsXu3JKAJJCvHCsaYhfxxeNAZrLjXZdqRF2MI6BZT1uD0ClpMQED9Swxl9ruus63OJfIqIqYXkz8dIpGNbfR9WJu1vJUSUpH86kAoD9mdxwdvIY1oDnMRNn8Pt3SSa6boOxsk76gc=; s_pers=%20c58%3Dno%2520value%7C1541770900873%3B%20s_dfa%3Dnikecomprod%7C1541770973836%3B''', 39 | "pragma": "no-cache", 40 | "referer": "https://www.nike.com/cn/zh_cn/e/nike-plus-membership", 41 | "user-agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36", 42 | } 43 | x=requests.get("https://www.nike.com/cn/zh_cn/e/nike-plus-membership",headers=head) 44 | print x.content 45 | #print(browser.page_source) 46 | time.sleep(10) 47 | #browser.close() 48 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | from loginnk import * 3 | import re 4 | import requests 5 | from WebLoginnk import * 6 | import threading,sqlite3,time 7 | from multiprocessing import Process 8 | from multiprocessing import Queue 9 | 10 | 11 | 12 | def getPostpayLink(productId, shoesLink): 13 | url = "https://api.nike.com/merch/products/v2/" + productId 14 | response = requests.get(url).json() 15 | postpayLink = shoesLink + "?LEStyleColor={styleColor}&LEPaymentType=Alipay".format( 16 | styleColor=response["styleColor"]) 17 | return postpayLink 18 | 19 | 20 | def buySet(shoesUrl): 21 | response = requests.get(shoesUrl).text 22 | 23 | launchId = re.findall(r"\"launchViewId\":\"(.*?)\"", response, re.S | re.I)[0] 24 | size = re.findall(r"\"sizes\":(.*?),\"_fetchedAt\"", response, re.S | re.I)[0] 25 | productId = re.findall(r"product\":{\"productId\":\"(.*?)\"", response, re.S | re.I)[0] 26 | 27 | shoesLink = re.findall(r"canonical\" href=\"(.*?)\"", response, re.S | re.I)[0] 28 | postpayLink = getPostpayLink(productId, shoesLink) 29 | 30 | stock = [] 31 | outOfStock = [] 32 | 33 | j_size = json.loads(size) 34 | 35 | for s in j_size: 36 | if j_size[s]["available"]: 37 | stock.append(j_size[s]["localizedSize"]) 38 | else: 39 | outOfStock.append(j_size[s]["localizedSize"]) 40 | stock.sort() 41 | outOfStock.sort() 42 | 43 | if len(outOfStock) > 0: 44 | print(" ".join(outOfStock) + "尺码缺货\n请选择" + " ".join(stock)) 45 | else: 46 | print("所有尺码有货\n请选择" + " ".join(stock)) 47 | 48 | shoesSize = input("-->") 49 | 50 | for s in j_size: 51 | if j_size[s]["localizedSize"] == shoesSize: 52 | usShoesSize = s 53 | skuId = j_size[s]["skuId"] 54 | 55 | # print("请设置好默认收货地址") 56 | 57 | # print("请选择支付方式 1.银联 2.微信 3.支付宝") 58 | # purMethod = input("-->") 59 | 60 | # shoesBuyUrl = shoesUrl + "/?productId=" + launchId + "&size=" + usShoesSize 61 | 62 | return shoesSize, launchId, skuId, productId, postpayLink 63 | 64 | if __name__ == '__main__': 65 | shoesSize, launchId, skuId, productId, postpayLink = buySet( 66 | "https://www.nike.com/cn/launch/t/air-max-270-volt-black-oil-grey/") 67 | 68 | threads = int(input("根据参与用户数量自行设置一个购买和监控的线程数:")) 69 | 70 | userInfoList = [] 71 | 72 | 73 | def bulkPurchase(orderQueue): 74 | def buy(refreshToken, username, password): 75 | try: 76 | app = BuySnkrs(refreshToken, skuId, launchId, productId, postpayLink) 77 | 78 | setShippingOptionsIdResponse = app.setShippingOptionsId() 79 | # print(setShippingOptionsIdResponse) 80 | 81 | setCheckoutIdResponse = app.setCheckoutId() 82 | # print(setCheckoutIdResponse) 83 | 84 | totalPrice, priceChecksum = app.getPriceChecksum() 85 | # print(totalPrice, priceChecksum) 86 | 87 | paymentToken = app.getPaymentToken(totalPrice) 88 | # print(paymentToken) 89 | 90 | launchEntrie = app.launchEntrie(paymentToken, priceChecksum) 91 | userInfo = [refreshToken, launchEntrie["id"], username, password] 92 | orderQueue.put(userInfo) 93 | except: 94 | traceback.print_exc() 95 | finally: 96 | td.release() 97 | 98 | conn = sqlite3.connect("nike.db") 99 | conn.text_factory = str 100 | c = conn.cursor() 101 | allUser = c.execute("SELECT * from nike").fetchall() 102 | 103 | td = threading.BoundedSemaphore(threads) 104 | threadlist = [] 105 | for user in allUser: 106 | username = user[2] 107 | password = user[3] 108 | refreshToken = user[1] 109 | #print("%s %s %s",username,password,refreshToken) 110 | td.acquire() 111 | t = threading.Thread(target=buy, args=(refreshToken, username, password)) 112 | t.start() 113 | threadlist.append(t) 114 | for x in threadlist: 115 | x.join() 116 | 117 | c.close() 118 | 119 | 120 | def orderStatus(orderQueue): 121 | def checkStatus(u): 122 | try: 123 | token, order, usr, pwd = u 124 | url = "https://unite.nikecloud.com/tokenRefresh?backendEnvironment=identity&locale=zh_CN&mobile=true&native=true&uxId=com.nike.commerce.snkrs.ios&sdkVersion=2.8.4&backendEnvironment=identity&platform=ios&browser=uniteSDK" 125 | data = {"client_id": "G64vA0b95ZruUtGk1K0FkAgaO3Ch30sj", "grant_type": "refresh_token", 126 | "refresh_token": token} 127 | r = requests.post(url, json=data).json() 128 | accessToken = r["access_token"] 129 | headers = {"authorization": "Bearer " + accessToken} 130 | response = requests.get("https://api.nike.com/launch/entries/v2/" + order, headers=headers).json() 131 | print(usr, response) 132 | try: 133 | result = response["result"] 134 | except: 135 | return 136 | if result["status"] == "WINNER": 137 | print("抢购成功, 帐号:%s 密码:%s (自行登陆手机app可查看订单)" % (usr, pwd)) 138 | userInfoList.remove(u) 139 | elif result["status"] == "NON_WINNER": 140 | print("%s 抢购失败" % usr) 141 | userInfoList.remove(u) 142 | except: 143 | traceback.print_exc() 144 | finally: 145 | td.release() 146 | 147 | while True: 148 | if not orderQueue.empty(): 149 | userInfo = orderQueue.get(True) 150 | userInfoList.append(userInfo) 151 | else: 152 | if len(userInfoList) != 0: 153 | td = threading.BoundedSemaphore(threads) 154 | threadlist = [] 155 | for u in userInfoList: 156 | td.acquire() 157 | t = threading.Thread(target=checkStatus, args=(u,)) 158 | t.start() 159 | threadlist.append(t) 160 | for x in threadlist: 161 | x.join() 162 | else: 163 | time.sleep(2) 164 | 165 | 166 | orderQueue = Queue() 167 | #buy = Process(target=bulkPurchase, args=(orderQueue,)) 168 | #status = Process(target=orderStatus, args=(orderQueue,)) 169 | #buy.start() 170 | #status.start() 171 | bulkPurchase(Queue()) 172 | orderStatus(Queue()) -------------------------------------------------------------------------------- /loginnk.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | import json 3 | import socket 4 | import ssl 5 | import traceback,time 6 | import uuid 7 | import requests 8 | from WebLoginnk import WebLogin_Chrome 9 | 10 | 11 | 12 | class LoginInit: 13 | def __init__(self, username, password): 14 | self.username = "+86" + username 15 | self.password = password 16 | 17 | self.host = "s3.nikecdn.com" 18 | self.visitorId = str(uuid.uuid4()) 19 | self.clientId = "G64vA0b95ZruUtGk1K0FkAgaO3Ch30sj" 20 | self.userAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 11_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15F79" 21 | 22 | webLogin = WebLogin_Chrome(username, password) 23 | webLogin.login() 24 | self.cookies = webLogin.getCookies() 25 | 26 | # 获取app登陆请求 27 | def getLoginRequests(self): 28 | payload = '{{"username":"{usr}","password":"{pwd}","client_id":"{clientId}","ux_id":"com.nike.commerce.snkrs.ios","grant_type":"password"}}'.format( 29 | usr=self.username, pwd=self.password, clientId=self.clientId) 30 | 31 | head = '''POST /login?appVersion=454&experienceVersion=375&uxid=com.nike.commerce.snkrs.ios&locale=zh_CN&backendEnvironment=identity&browser=Apple%20Computer%2C%20Inc.&os=undefined&mobile=true&native=true&visit=1&visitor={visitorId} HTTP/1.1 32 | Host: {host} 33 | Content-Type: application/json 34 | Origin: https://{host} 35 | Cookie: {cookies} 36 | Content-Length: {length} 37 | Connection: close 38 | Accept: */* 39 | User-Agent: {userAgent} 40 | Referer: https://s3.nikecdn.com/unite/mobile.html?mid=66794190406425515927935901233201301138?iOSSDKVersion=2.8.4&clientId=G64vA0b95ZruUtGk1K0FkAgaO3Ch30sj&uxId=com.nike.commerce.snkrs.ios&view=none&locale=zh_CN&backendEnvironment=identity 41 | Accept-Language: zh-cn'''.format(visitorId=self.visitorId, host=self.host, userAgent=self.userAgent, 42 | length=len(payload), cookies=self.cookies) 43 | 44 | data = head + "\r\n\r\n" + payload 45 | return data 46 | 47 | def getDataFromResponse(self, data): 48 | data = json.loads(data.split("\r\n\r\n")[1]) 49 | return data 50 | 51 | # 发送请求 52 | def sendRequestsToHost(self, data): 53 | sock = ssl.wrap_socket(socket.socket()) 54 | sock.connect((self.host, 443)) 55 | 56 | sock.sendall(bytes(data, encoding='utf-8')) 57 | # recv_data = sock.recv(10240).decode('utf-8') 58 | result = "" 59 | while True: 60 | try: 61 | recv_data = sock.recv(2048) 62 | result += recv_data.decode('utf-8') 63 | except socket.error as err_msg: 64 | print('Error receiving data: %s' % err_msg) 65 | if not len(recv_data): 66 | break 67 | sock.close() 68 | return result 69 | 70 | #ceshi=LoginInit('15245871026','huanxiangmf1Q') 71 | #print (ceshi.sendRequestsToHost(data=ceshi.getLoginRequests())) 72 | 73 | class BuySnkrs: 74 | def __init__(self, refreshToken, skuId, launchId, productId, postpayLink): 75 | self.refreshToken = refreshToken 76 | 77 | self.skuId = skuId 78 | self.launchId = launchId 79 | self.productId = productId 80 | self.postpayLink = postpayLink 81 | 82 | self.host = "s3.nikecdn.com" 83 | self.apiHost = "api.nike.com" 84 | self.visitorId = str(uuid.uuid4()) 85 | self.clientId = "G64vA0b95ZruUtGk1K0FkAgaO3Ch30sj" 86 | self.userAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 11_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15F79" 87 | 88 | self.apiUserAgent = "SNKRS/3.3.3 (iPhone; iOS 11.4; Scale/2.00)" 89 | self.xNewRelicID = "VQYGVF5SCBADUVBRBgAGVg==" 90 | self.xNikeCallerId = "nike:snkrs:ios:3.3" 91 | 92 | self.checkoutId = str(uuid.uuid4()) 93 | self.shippingId = str(uuid.uuid4()) 94 | self.paymentsId = str(uuid.uuid4()) 95 | 96 | self.times = self.getUtcTime() 97 | 98 | self.token = self.getTokenRefresh() 99 | 100 | # 格式化一些购买过程中所需的参数 101 | self.userCommerce = self.getUserCommerce() 102 | self.email = self.userCommerce["emails"]["primary"]["email"] 103 | 104 | # print(self.userCommerce["address"]) 105 | # for i in self.userCommerce["address"]: 106 | # address = self.userCommerce["address"][i] 107 | # break 108 | address = self.userCommerce["address"]["shipping"] 109 | state = address["province"] 110 | city = address["locality"] 111 | county = address["zone"] 112 | address1 = address["line1"] 113 | try: 114 | address2 = address["line2"] 115 | except: 116 | address2 = " " 117 | postalCode = address["code"] 118 | country = address["country"] 119 | self.addressInfo = {"state": state, "city": city, "address1": address1, "postalCode": postalCode, 120 | "address2": address2, "county": county, "country": country} 121 | 122 | name = address["name"]["primary"] 123 | lastName = name["given"] 124 | firstName = name["family"] 125 | self.recipientInfo = {"lastName": lastName, "firstName": firstName} 126 | 127 | phone = address["phone"]["primary"] 128 | self.contactInfo = {"phoneNumber": phone, "email": self.email} 129 | 130 | # 格式化最终抢购所需的参数 131 | self.launchRecipient = {"lastName": lastName, "firstName": firstName, "email": self.email, 132 | "phoneNumber": phone} 133 | 134 | self.launchAddress = {"state": state, "city": city, "address1": address1, "county": county, "country": "CN"} 135 | 136 | # 获取服务器时区的时间 137 | def getUtcTime(self): 138 | utcTime = time.gmtime() 139 | return utcTime 140 | 141 | # 获取最新发布的产品 142 | def gwtProductFeed(self): 143 | response = requests.get( 144 | "https://api.nike.com/commerce/productfeed/products/snkrs/threads?country=CN&limit=5&locale=zh_CN&skip=0&withCards=true").json() 145 | return response 146 | 147 | # 获取新的通知信息 148 | def getNotifications(self): 149 | times = time.strftime("%Y-%m-%dT%H%%3A%M%%3A%S.000%%2B0000", self.times) 150 | url = "https://api.nike.com/plus/v3/notifications/me/stored?since={time}&limit=10&locale=zh-Hans_CN".format( 151 | time=times) 152 | headers = { 153 | "deliveryId": "com.nike.onenikecommerce", 154 | "appid": "com.nike.commerce.snkrs.ios", 155 | "Authorization": "Bearer " + self.token, 156 | "User-Agent": self.apiUserAgent, 157 | "X-NewRelic-ID": self.xNewRelicID 158 | } 159 | response = requests.get(url, headers=headers).json() 160 | return response 161 | 162 | # 获取订单信息 163 | def getOrderHistory(self): 164 | url = "https://api.nike.com/commerce/ap/orderhistory?action=getOrderHistoryList&country=CN" 165 | headers = { 166 | "X-NewRelic-ID": self.xNewRelicID, 167 | "User-Agent": self.apiUserAgent, 168 | "Authorization": "Bearer " + self.token 169 | } 170 | response = requests.get(url, headers=headers).text 171 | return response 172 | 173 | # 刷新登陆凭证 174 | def getTokenRefresh(self): 175 | url = "https://unite.nikecloud.com/tokenRefresh?backendEnvironment=identity&locale=zh_CN&mobile=true&native=true&uxId=com.nike.commerce.snkrs.ios&sdkVersion=2.8.4&backendEnvironment=identity&platform=ios&browser=uniteSDK" 176 | data = {"client_id": self.clientId, "grant_type": "refresh_token", 177 | "refresh_token": self.refreshToken} 178 | r = requests.post(url, json=data).json() 179 | return r["access_token"] 180 | 181 | # 获取用户基本信息 182 | def getUserCommerce(self): 183 | url = "https://api.nike.com/user/commerce" 184 | headers = { 185 | "X-NewRelic-ID": self.xNewRelicID, 186 | "User-Agent": self.apiUserAgent, 187 | "Authorization": "Bearer " + self.token, 188 | "X-NIKE-UX-ID": "com.nike.commerce.snkrs.ios" 189 | } 190 | response = requests.get(url, headers=headers).json() 191 | return response 192 | 193 | def setShippingOptionsId(self): 194 | url = "https://api.nike.com/buy/shipping_options/v2" 195 | headers = { 196 | "Accept": "application/json", 197 | "Authorization": "Bearer " + self.token, 198 | "Content-Type": "application/json; charset=utf-8", 199 | "x-nike-caller-id": self.xNikeCallerId, 200 | "User-Agent": self.apiUserAgent, 201 | "X-NewRelic-ID": self.xNewRelicID 202 | } 203 | data = {"items": [{"id": self.shippingId, "shippingAddress": self.addressInfo, "skuId": self.skuId}], 204 | "currency": "CNY", "country": "CN"} 205 | response = requests.post(url, headers=headers, json=data).json() 206 | return response 207 | 208 | def setCheckoutId(self): 209 | url = "https://api.nike.com/buy/checkout_previews/v2/" + self.checkoutId 210 | headers = { 211 | "Accept": "application/json", 212 | "Authorization": "Bearer " + self.token, 213 | "Content-Type": "application/json", 214 | "x-nike-caller-id": self.xNikeCallerId, 215 | "User-Agent": self.apiUserAgent, 216 | "X-NewRelic-ID": self.xNewRelicID 217 | } 218 | data = {"request": {"email": self.email, 219 | "clientInfo": {"deviceId": "", "client": "com.nike.commerce.snkrs.ios"}, "currency": "CNY", 220 | "items": [{"recipient": self.recipientInfo, 221 | "shippingAddress": self.addressInfo, 222 | "id": self.shippingId, "quantity": 1, 223 | "skuId": self.skuId, 224 | "shippingMethod": "GROUND_SERVICE", 225 | "contactInfo": self.contactInfo}], 226 | "channel": "SNKRS", "locale": "zh_CN", "country": "CN"}} 227 | response = requests.put(url, headers=headers, json=data).json() 228 | return response 229 | 230 | def getPriceChecksum(self): 231 | url = "https://api.nike.com/buy/checkout_previews/v2/jobs/" + self.checkoutId 232 | headers = { 233 | "Accept": "application/json", 234 | "X-NewRelic-ID": self.xNewRelicID, 235 | "x-nike-caller-id": self.xNikeCallerId, 236 | "Authorization": "Bearer " + self.token, 237 | "User-Agent": self.apiUserAgent 238 | } 239 | response = requests.get(url, headers=headers).json() 240 | totalPrice = response["response"]["totals"]["total"] 241 | priceChecksum = response["response"]["priceChecksum"] 242 | return totalPrice, priceChecksum 243 | 244 | def getPaymentToken(self, totalPrice): 245 | url = "https://api.nike.com/payment/preview/v2" 246 | headers = { 247 | "Accept": "application/json; charset=utf-8", 248 | "Authorization": "Bearer " + self.token, 249 | "Content-Type": "application/json", 250 | "x-nike-caller-id": self.xNikeCallerId, 251 | "User-Agent": self.apiUserAgent, 252 | "X-NewRelic-ID": self.xNewRelicID 253 | } 254 | data = {"total": totalPrice, "items": [{"productId": self.productId, 255 | "shippingAddress": self.addressInfo}], 256 | "checkoutId": self.checkoutId, "currency": "CNY", "paymentInfo": [ 257 | {"id": self.paymentsId, "type": "Alipay", 258 | "billingInfo": {"name": self.recipientInfo, 259 | "contactInfo": self.contactInfo, 260 | "address": self.addressInfo}}], "country": "CN"} 261 | response = requests.post(url, headers=headers, json=data).json() 262 | paymentToken = response["id"] 263 | return paymentToken 264 | 265 | def getDataFromResponse(self, data): 266 | data = json.loads(data.split("\r\n\r\n")[1]) 267 | return data 268 | 269 | # 发送请求 270 | def sendRequestsToHost(self, data): 271 | sock = ssl.wrap_socket(socket.socket()) 272 | sock.connect((self.host, 443)) 273 | 274 | sock.sendall(bytes(data, encoding='utf-8')) 275 | # recv_data = sock.recv(10240).decode('utf-8') 276 | result = "" 277 | while True: 278 | try: 279 | recv_data = sock.recv(2048) 280 | result += recv_data.decode('utf-8') 281 | except socket.error as err_msg: 282 | print('Error receiving data: %s' % err_msg) 283 | if not len(recv_data): 284 | break 285 | sock.close() 286 | return result 287 | 288 | def sendRequestsToApiHost(self, data): 289 | sock = ssl.wrap_socket(socket.socket()) 290 | sock.connect((self.apiHost, 443)) 291 | 292 | sock.sendall(bytes(data, encoding='utf-8')) 293 | # recv_data = sock.recv(10240) 294 | result = "" 295 | while True: 296 | try: 297 | recv_data = sock.recv(2048) 298 | result += recv_data.decode('utf-8') 299 | except socket.error as err_msg: 300 | print('Error receiving data: %s' % err_msg) 301 | if not len(recv_data): 302 | break 303 | sock.close() 304 | return result 305 | 306 | def launchEntrie(self, paymentToken, priceChecksum): 307 | url = "https://api.nike.com/launch/entries/v2" 308 | headers = { 309 | "Authorization": "Bearer " + self.token, 310 | "Content-Type": "application/json", 311 | "x-nike-caller-id": self.xNikeCallerId, 312 | "User-Agent": self.apiUserAgent, 313 | "X-NewRelic-ID": self.xNewRelicID 314 | } 315 | data = {"deviceId": "", "postpayLink": self.postpayLink, "checkoutId": self.checkoutId, "currency": "CNY", 316 | "paymentToken": paymentToken, 317 | "shipping": {"recipient": self.launchRecipient, "method": "GROUND_SERVICE", 318 | "address": self.launchAddress}, "skuId": self.skuId, "channel": "SNKRS", 319 | "launchId": self.launchId, "locale": "zh_CN", "priceChecksum": priceChecksum} 320 | response = requests.post(url, headers=headers, json=data).json() 321 | return response -------------------------------------------------------------------------------- /.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 93 | 94 | 95 | 96 | print 97 | sendall 98 | buy 99 | WebLogin_Chrome 100 | sqlite3 101 | orderStatus 102 | bytes(data 103 | 根据 104 | BuySnkrs 105 | gwtProductFeed 106 | launchEntrie 107 | 108 | 109 | 110 | 112 | 113 | 126 | 127 | 128 | 129 | 130 | true 131 | DEFINITION_ORDER 132 | 133 | 134 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 |