整个界面可能会显得不太美观,但是我尽力让大家看得舒服一点。废话不多说。直接打开jd开始试一试。(使用的是谷歌浏览器)
一、打开京东和F12开发者模式。
这里提一个小点(F12界面建议独立出来不要影响浏览器本身的页面,后面会有CSS反爬,字体反爬等)
下面打开链接登陆界面 https://passport.jd.com/new/login.aspx
然后F12小框一打,找到二维码的链接
其实只看这个链接然后去匹配抓取是不可行的。首先我们可以看出其中有许多的请求参数,这个需要自己多刷新几次,多看。
现在我们进入NETWORK,查看这些请求参数到底是何方神圣。
然后一看,就nm个时间戳,上代码完事一拼。
一个简易的小链接构建完成。这里其实已经可以获取到二维码了,但是我们在原请求中,很简单的看出还有许许多多的cookie,并且这里我没有把cookie写出来。其实不是我没写,而是在requests库中,有个session可以自动处理cookie,我们只需要按照network中顺序将二维码前面的链接中包含的set-cookie的回应的链接构建一遍然后请求,就会或得正确的cookie了。
其中的很多cookie其实没有什么鸟用,我也经过了筛选,这个就要自己去试一试了。
然后继续介绍二维码登陆。
当我们请求到了二维码图片后,在我们本地会一直像一个链接发起请求,去询问服务端我是不是已经扫了码,
然后我们这边也可以构建同样的请求来达到相同的结果。
然后一看,卧槽,这个token是什么东西,我是谁,我从哪来。其实这个好搞。
我们打开搜索按钮,给我找他的来源。3秒我要他的所有资料,我相信以各位的能力,怕是够呛吧。tui。应该没什么问题吧。
就是他了,断点一加,谁都不爱。艹,一点都不押韵。然后重新请求。
对不起搞错了。
这不就是之前请求的cookie中的数据嘛,盘他
这个calback就不用问了,没什么b用。
然后这两步构建完成了。其实大体上就已经完成了。再加上一个检测就完工了。最后附上代码,我写不下去了。溜了。
import requests,time,json,random
from PIL import Image
import functools
from log import logger
def parse_json(s):
begin = s.find('{')
end = s.rfind('}') + 1
return json.loads(s[begin:end])
def response_status(resp):
if resp.status_code != requests.codes.OK:
print('Status: %u, Url: %s' % (resp.status_code, resp.url))
return False
return True
def check_login(func):
"""用户登陆态校验装饰器。若用户未登陆,则调用扫码登陆"""
@functools.wraps(func)
def new_func(self, *args, **kwargs):
if not self.is_login:
logger.info("{0} 需登陆后调用,开始扫码登陆".format(func.__name__))
self.login_by_QRcode()
return func(self, *args, **kwargs)
return new_func
class User(object):
def __init__(self):
self.user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36'
self.log_url = 'https://passport.jd.com/new/login.aspx'
self.s = requests.Session()
self.is_login = False
self.headers = {'User-Agent': self.user_agent}
def _get_login_page(self):
url = "https://passport.jd.com/new/login.aspx"
page = self.s.get(url, headers=self.headers)
return page
def loging(self):
if self.is_login:
logger.info('登录成功')
self.open_order_page
self._get_login_page()
ticket = None
retry_times = 85
for _ in range(retry_times):
self.get_QR_code()
ticket = self._get_QRcode_ticket()
if ticket:
break
time.sleep(2)
else:
print('二维码过期,请重新获取扫描')
if not self._validate_QRcode_ticket(ticket):
print('二维码信息校验失败')
print('二维码登录成功')
self.is_login = True
self.nick_name = self.get_user_info()
self.open_order_page()
def get_QR_code(self):
QR_code_url = 'http://qr.m.jd.com/show?appid=133&size=147&t=%d'%(time.time()*1000)
headers = {':authority': 'qr.m.jd.com',
':method': 'GET',
':path': '/show?appid=133&size=147&t=',
':scheme': 'https',
'referer': 'https://passport.jd.com/new/login.aspx',
'sec-fetch-dest': 'image',
'sec-fetch-mode': 'no-cors',
'sec-fetch-site': 'same-site',
'user-agent':self.user_agent}
response = self.s.get(url = QR_code_url,).content
with open('QRcode.jpg','wb') as f:
f.write(response)
image = Image.open('QRcode.jpg')
image.show()
time.sleep(10)
def _validate_QRcode_ticket(self, ticket):
url = 'https://passport.jd.com/uc/qrCodeTicketValidation'
headers = {
'User-Agent': self.user_agent,
'Referer': 'https://passport.jd.com/uc/login?ltype=logout',
}
resp = self.s.get(url=url, headers=headers, params={'t': ticket})
if not response_status(resp):
return False
resp_json = json.loads(resp.text)
if resp_json['returnCode'] == 0:
return True
else:
logger.info(resp_json)
return False
def _get_QRcode_ticket(self):
url = 'https://qr.m.jd.com/check'
payload = {
'appid': '133',
'callback': 'jQuery{}'.format(random.randint(1000000, 9999999)),
'token': self.s.cookies.get('wlfstk_smdl'),
'_': str(int(time.time() * 1000)),
}
headers = {
'User-Agent': self.user_agent,
'Referer': 'https://passport.jd.com/new/login.aspx',
}
resp = self.s.get(url=url, headers=headers, params=payload)
if not response_status(resp):
print('获取二维码扫描结果异常')
return False
resp_json = parse_json(resp.text)
if resp_json['code'] != 200:
print('Code: %s, Message: %s', resp_json['code'], resp_json['msg'])
return None
else:
print('已完成手机客户端确认')
self.is_login = True
a = resp_json['ticket']
return a
@check_login
def open_order_page(self):
url = 'https://order.jd.com/center/list.action'
payload = {
'search': 0,
'd': 1,
's': 4096,
} # Orders for nearly three months
headers = {
'User-Agent': self.user_agent,
'Referer': 'https://passport.jd.com/uc/login?ltype=logout',
}
resp = self.s.get(url=url, params=payload, headers=headers)
print(resp.text)
print(self.s.cookies)
@check_login
def get_user_info(self):
"""获取用户信息
:return: 用户名
"""
url = 'https://passport.jd.com/user/petName/getUserInfoForMiniJd.action'
payload = {
'callback': 'jQuery{}'.format(random.randint(1000000, 9999999)),
'_': str(int(time.time() * 1000)),
}
headers = {
'User-Agent': self.user_agent,
'Referer': 'https://order.jd.com/center/list.action',
}
try:
resp = self.s.get(url=url, params=payload, headers=headers)
resp_json = parse_json(resp.text)
# many user info are included in response, now return nick name in it
# jQuery2381773({"imgUrl":"//storage.360buyimg.com/i.imageUpload/xxx.jpg","lastLoginTime":"","nickName":"xxx","plusStatus":"0","realName":"xxx","userLevel":x,"userScoreVO":{"accountScore":xx,"activityScore":xx,"consumptionScore":xxxxx,"default":false,"financeScore":xxx,"pin":"xxx","riskScore":x,"totalScore":xxxxx}})
return resp_json.get('nickName') or 'jd'
except:
return 'jd'
a = User()
a.loging()
还有一个配置代码好用且免费。
#!/usr/bin/env python
# -*- encoding=utf8 -*-
import logging
import logging.handlers
LOG_FILENAME = 'jd-assistant.log'
logger = logging.getLogger()
def set_logger():
logger.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s %(levelname)s: %(message)s')
console_handler = logging.StreamHandler()
console_handler.setFormatter(formatter)
logger.addHandler(console_handler)
file_handler = logging.handlers.RotatingFileHandler(
LOG_FILENAME, maxBytes=10485760, backupCount=5, encoding="utf-8")
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
set_logger()
相当于做个笔记了,后面可以自行增加cookie序列来成功完成自动登陆,自动下单的任务就简单多了。仅做学习交流使用,如有任何侵权随时删除。