├── README.md ├── jd.py └── rk.py /README.md: -------------------------------------------------------------------------------- 1 | # JD_AutoSubmit 2 | Python爬虫,京东自动打码登录,指定商品自动加购物车,自动下单,指定时间抢购商品
3 | 可以根据指定的商品编号,自动购买下单,需要手动去京东付款
4 | 新版增加了库存监控功能 5 | 6 | ## 运行环境 7 | Python 3.x 8 | ## 第三方库 9 | [Requests](http://docs.python-requests.org/en/master/):为人类设计的HTTP库
10 | [Lxml](http://lxml.de/):高性能XML网页解析 11 | ## 自动打码登录模块 12 | [若快打码](http://www.ruokuai.com/login):自动识别验证码,免去人工输入 13 | ## 三方库安装方法 14 | pip install requests
15 | pip install lxml 16 | ## 使用说明 17 | 直接运行jd.py文件
18 | 程序运行时rk.py和jd.py必须放在同一文件目录下
19 | 按提示输入京东账号密码,以及若快账号密码,后续每一步操作都有提示,简单易懂
20 | [若快账号注册地址](http://www.ruokuai.com/login):目前一元可以识别250个验证码,正常使用一元可以用好久^_^
21 | ## 补充 22 | 代码仅供学习参考使用,严禁用于非法用途,因程序产生的一切问题与源码作者无关
23 | 不能保证代码能一直正确运行,如您发现有Bug,欢迎提交修改。 24 | ## QQ交流群:348885782 25 | -------------------------------------------------------------------------------- /jd.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import random 3 | import json 4 | import os 5 | import time 6 | import re 7 | from lxml import etree 8 | from rk import * 9 | 10 | 11 | url = 'https://passport.jd.com/new/login.aspx' 12 | 13 | headers = { 14 | 'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36', 15 | 'ContentType': 'text/html; charset=utf-8', 16 | 'Accept-Encoding':'gzip, deflate, sdch', 17 | 'Accept-Language':'zh-CN,zh;q=0.8', 18 | 'Connection' : 'keep-alive', 19 | } 20 | 21 | s = requests.Session() 22 | s.headers = headers 23 | 24 | 25 | # 请求登录页面 26 | req1 = s.get(url=url, headers=headers) 27 | 28 | sel = etree.HTML(req1.content) 29 | uuid = sel.xpath('//input[@id="uuid"]/@value')[0] 30 | 31 | eid = sel.xpath('//input[@id="eid"]/@value')[0] 32 | sa_token = sel.xpath('//input[@id="sa_token"]/@value')[0] 33 | pubKey = sel.xpath('//input[@id="pubKey"]/@value')[0] 34 | t = sel.xpath('//input[@id="token"]/@value')[0] 35 | 36 | 37 | r = random.random() 38 | login_url = 'https://passport.jd.com/uc/loginService' 39 | 40 | class JD(object): 41 | 42 | def __init__(self,username,password,rk_username,rk_pwd): 43 | self.username = username 44 | self.password = password 45 | self.rkclient = RClient(rk_username,rk_pwd) 46 | self.trackid = '' 47 | self.pid = '' 48 | 49 | # 账号登录函数 50 | def login(self): 51 | 52 | params = { 53 | 54 | 'uuid':uuid, 55 | 'eid':eid, 56 | # 'fp':'a2fd52211772d8fea0515bedca560b0b', 57 | '_t':t, 58 | 'loginType':'c', 59 | 'loginname':self.username, 60 | 'nloginpwd':self.password, 61 | 'chkRememberMe':'', 62 | 'authcode':'', 63 | 'pubKey':pubKey, 64 | 'sa_token':sa_token, 65 | # 'seqSid':'5574250748814772000' 66 | 67 | } 68 | 69 | 70 | 71 | headers = { 72 | 'Referer':'https://passport.jd.com/uc/login?ltype=logout', 73 | 'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36', 74 | 'X-Requested-With':'XMLHttpRequest' 75 | } 76 | 77 | # 验证码图片 78 | imgcode = 'http:' + sel.xpath('//img[@id="JD_Verification1"]/@src2')[0] 79 | img = requests.get(imgcode) 80 | # 把这个路径替换成自己电脑jd.py文件夹的路径,/Users/zhangkai/Desktop/JD 81 | with open('/Users/zhangkai/Desktop/JD/a.jpg', 'wb') as f: 82 | f.write(img.content) 83 | im = open('a.jpg','rb').read() 84 | print('开始识别验证码...') 85 | 86 | # print(imgcode) # 手动验证码连接 87 | 88 | # 自动打码 89 | imgcode1 = self.rkclient.rk_create(im, 3040)['Result'] 90 | print(imgcode1) 91 | 92 | 93 | if imgcode != '': 94 | 95 | # params['authcode'] = input('请输入验证码:') # 手动输验证码 96 | 97 | params['authcode'] = str(imgcode1) 98 | req2 = s.post(login_url, data=params, headers=headers) 99 | 100 | 101 | patt = '' 102 | self.trackid = re.compile(patt).findall(str(s.cookies)) 103 | 104 | js = json.loads(req2.text[1:-1]) 105 | 106 | 107 | if js.get('success'): 108 | print('登录成功') 109 | else: 110 | print('登录失败') 111 | else: 112 | req2 = s.post(login_url, data=params, headers=headers) 113 | 114 | patt = '' 115 | self.trackid = re.compile(patt).findall(str(s.cookies)) 116 | 117 | js = json.loads(req2.text[1:-1]) 118 | 119 | if js.get('success'): 120 | print('登录成功') 121 | else: 122 | print('登录失败') 123 | 124 | def addcart(self): 125 | 126 | self.pid = input('请输入要加入购物车的商品编号:') 127 | pcount = input('请输入加入数量:') 128 | add_carturl = 'https://cart.jd.com/gate.action?pid='+self.pid+'&pcount='+pcount+'&ptype=1' 129 | # add_carturl = 'https://cart.jd.com/gate.action?pid=3659204&pcount=1&ptype=1' 130 | 131 | req4 = s.get(add_carturl) 132 | 133 | if re.compile('(.*?)').findall(req4.text)[0] == '商品已成功加入购物车': 134 | print('商品已成功加入购物车') 135 | else: 136 | print('添加购物车失败') 137 | 138 | 139 | def submit(self): 140 | #购物车页面 141 | carturl = 'https://cart.jd.com' 142 | req5 = s.get(carturl) 143 | 144 | # 取消选择某个商品 145 | cancelitemurl = 'https://cart.jd.com/cancelItem.action?rd' + str(r) 146 | form_data = { 147 | 'outSkus':'', 148 | 'pid':self.pid, # 商品id 149 | 'ptype': '1', 150 | 'packId': '0', 151 | 'targetId': '0', 152 | 'promoID': '0', 153 | 'locationId': '1-2810-6501-0' # 地址代码 154 | } 155 | 156 | req6 = s.post(cancelitemurl, data=form_data) 157 | 158 | # 选择某个商品 159 | selectitemurl = 'https://cart.jd.com/selectItem.action?rd' + str(r) 160 | req7 = s.post(selectitemurl, data=form_data) 161 | 162 | 163 | timestamp = int(time.time() * 1000) 164 | # 订单结算页 165 | orderInfo = 'https://trade.jd.com/shopping/order/getOrderInfo.action?rid=' + str(timestamp) 166 | 167 | # 提交订单url 168 | submitOrder = 'https://trade.jd.com/shopping/order/submitOrder.action' 169 | 170 | submit_data = { 171 | 'overseaPurchaseCookies':'', 172 | 'submitOrderParam.sopNotPutInvoice':'false', 173 | 'submitOrderParam.trackID': self.trackid[0], 174 | 'submitOrderParam.ignorePriceChange': '0', 175 | 'submitOrderParam.btSupport': '0', 176 | 'submitOrderParam.eid': eid, 177 | 'submitOrderParam.fp': 'b31fc738113fbc4ea5fed9fc9811acc6', 178 | # 'riskControl': 'D0E404CB705B9732D8D7A53159E363F2140ADCDE164C1F9CABA71F1D7552B70E5C9C6041832CEB4B', 179 | } 180 | 181 | 182 | 183 | ordertime = input('''请选择: 184 | 1.设置下单时间 185 | 2.选择立即下单(可用于监控库存,自动下单) 186 | 请输入选择(1/2): 187 | ''') 188 | 189 | if ordertime == '1': 190 | set_time = input('请按照2017-05-01 23:11:11格式输入下单时间:') 191 | timeArray = time.mktime(time.strptime(set_time,'%Y-%m-%d %H:%M:%S')) 192 | while True: 193 | if time.time() >= timeArray: 194 | 195 | print('正在提交订单...') 196 | req8 = s.post(submitOrder, data=submit_data) 197 | js1 = json.loads(req8.text) 198 | print(js1) 199 | # 判断是否下单成功 200 | if js1['success'] == True: 201 | print('下单成功!') 202 | else: 203 | print('下单失败') 204 | break 205 | else: 206 | # print('等待下单...') 207 | continue 208 | # 直接下单 209 | elif ordertime == '2': 210 | while True: 211 | area = '1_2810_6501_0' # 地址编码,这里请替换成自己地区的编码 212 | stockurl = 'http://c0.3.cn/stock?skuId=' + self.pid + '&cat=652,829,854&area=' + area + '&extraParam={%22originid%22:%221%22}' 213 | resp = s.get(stockurl) 214 | jsparser = json.loads(resp.text) 215 | # 33 有货 34 无货 216 | if jsparser['stock']['StockState'] == 33 and jsparser['stock']['StockStateName'] == '现货': 217 | print('库存状态:',jsparser['stock']['StockStateName']) 218 | 219 | req8 = s.post(submitOrder, data=submit_data) 220 | print('正在提交订单...') 221 | js1 = json.loads(req8.text) 222 | 223 | # 判断是否下单成功 224 | if js1['success'] == True: 225 | print('下单成功!') 226 | break 227 | else: 228 | print('下单失败') 229 | # 3秒后重新尝试下单,可自行修改时间间隔 230 | time.sleep(3) 231 | continue 232 | elif jsparser['stock']['StockState'] != 33: 233 | print('无货,监控中...') 234 | time.sleep(3) # 请酌情修改时间间隔,最少1秒 235 | continue 236 | 237 | 238 | if __name__ == '__main__': 239 | 240 | jd_user = input('请输入京东账号:') 241 | jd_pwd = input('请输入京东密码:') 242 | rk_user = input('请输入若快账号:') 243 | rk_pwd = input('请输入若快密码:') 244 | a = JD(jd_user, jd_pwd, rk_user, rk_pwd) 245 | a.login() 246 | a.addcart() 247 | a.submit() 248 | 249 | -------------------------------------------------------------------------------- /rk.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding:utf-8 3 | 4 | import requests 5 | from hashlib import md5 6 | 7 | 8 | class RClient(object): 9 | 10 | def __init__(self, username, password): 11 | self.username = username 12 | self.password = md5(password.encode('utf-8')).hexdigest() 13 | self.soft_id = '80032' 14 | self.soft_key = '8c37f5b5c5784e2ebe7681f4ff325cee' 15 | self.base_params = { 16 | 'username': self.username, 17 | 'password': self.password, 18 | 'softid': '80032', 19 | 'softkey': '8c37f5b5c5784e2ebe7681f4ff325cee', 20 | } 21 | self.headers = { 22 | 'Connection': 'Keep-Alive', 23 | 'Expect': '100-continue', 24 | 'User-Agent': 'ben', 25 | } 26 | 27 | def rk_create(self, im, im_type, timeout=60): 28 | """ 29 | im: 图片字节 30 | im_type: 题目类型 31 | """ 32 | params = { 33 | 'typeid': im_type, 34 | 'timeout': timeout, 35 | } 36 | params.update(self.base_params) 37 | files = {'image': ('a.jpg', im)} 38 | r = requests.post('http://api.ruokuai.com/create.json', data=params, files=files, headers=self.headers) 39 | return r.json() 40 | 41 | def rk_report_error(self, im_id): 42 | """ 43 | im_id:报错题目的ID 44 | """ 45 | params = { 46 | 'id': im_id, 47 | } 48 | params.update(self.base_params) 49 | r = requests.post('http://api.ruokuai.com/reporterror.json', data=params, headers=self.headers) 50 | return r.json() 51 | 52 | 53 | if __name__ == '__main__': 54 | rc = RClient('username', 'password') 55 | im = open('a.jpg', 'rb').read() 56 | print (rc.rk_create(im, 3040)) 57 | 58 | --------------------------------------------------------------------------------