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