python实现--京东模拟登入

为了完成京东模拟登入,需要获取登入的Request URL和Form Data。因此需要先在浏览器上进行一次登入请求:
第一步:输入用户名、输入密码123
第二步:按F12或者Fn+F12
第三步:选择network,过滤一下文件类型,选择xhr(Ajax文件格式),如图所示
python实现--京东模拟登入_第1张图片

请求参数分析

Request URL参数分析

首先来看Request URL:

https://passport.jd.com/uc/loginService?uuid=c4dcd3e0-75a4-4102-b84d-d9cd7f1cef5c&ReturnUrl=https%3A%2F%2Fwww.jd.com%2F&r=0.6514627039938361&version=2015

这个url包含请求参数,因此可以看作一个get请求,其中url是https://passport.jd.com/uc/loginService?需要四个参数uuid,ReturnRurl,r和version。
其中version参数是固定的,ReturnRurl参数和从哪个页面跳转过来有关,也可以认为是固定的。关键在于分析uuid和参数r,一个常用的思路是在网页源码里面去寻找,打开网页源码,选择source,如下图所示

简单说一下寻找过程,首先看登入页面的网址是passport.jd.com/,在左侧的page里面找这个文件,然后依次点开,就可以找到login.aspx?。当然也可以直接在登入页面,右键显示网页源代码。通过source里面的代码,可以找到uuid这个参数,但没有参数r。进一步,需要找到登入的js文件,在passport.jd.com/misc/jc/login2016.js里面,此次简记为login2016.js,后面的分析还需要用到这个文件。找到function loginSubmit(callback)这个函数,代码段如下

function loginSubmit(callback) {
        $('#loginsubmit').text('\u6b63\u5728\u767b\u5f55\u002e\u002e\u002e');
        if(window.location.href.indexOf("/popupLogin2013")!=-1){
            frameLoginSubmit(callback);
            return;
        }
        var loginUrl = "/uc/loginService";
        var uuid = $("#uuid").val();

        var authcode;
        if(useSlideAuthCode){
            // authcode = $("#s-authcode").attr('data-code');
            authcode = $("#loginsubmit").attr('data-code');
        }else{
            authcode = $('#authcode').val();
        }

        $.ajax({
            url: loginUrl + "?uuid=" + uuid + "&" + location.search.substring(1) + "&r=" + Math.random()+"&version=2015",
            type: "POST",
            dataType: "text",
            contentType: "application/x-www-form-urlencoded; charset=utf-8",
            data: {
                uuid:$('#uuid').val(),
                eid:$('#eid').val(),
                fp:$('#sessionId').val(),
                _t:$('#token').val(),
                loginType:$('#loginType').val(),
                loginname:$('#loginname').val(),
                nloginpwd:getEntryptPwd($('#nloginpwd').val()),
                authcode:authcode,
                pubKey:$('#pubKey').val(),
                sa_token:$('#sa_token').val(),
                seqSid:window._jdtdmap_sessionId,
                useSlideAuthCode:$("#useSlideAuthCode").val()

这里可以清楚的看到$.ajax里面的url,这个url有四个参数,其中location.search.substring(1)
对应ReturnRurl,r是Math.random()是一个随机数。

Form Data参数分析

这里的参数就很多了,把参数分成四类:

  1. js代码里面写成:$(’#xxx’).val(),例如uuid:$(’#uuid’).val
  2. 用户密码,$nloginpwd:getEntryptPwd($(’#nloginpwd’).val())
  3. seqSid
  4. authcode,和滑块验证码验证相关。

1类参数

第一种最好处理,它们都在登入的网页源代码中有显示,寻找过程类似于参数uuid。需要说明的是参数eidfp是网页源代码里面是空,但是在抓包的时候,发现这两个参数是需要有值的,通过多次提交,发现这两个参数是不变的。

eid: 5B4PGABPPZMEMRMCQMYLIT3EBUOP576CMIC6TVU2ZT26UI2YXWG7POGQIIZNCFMHF2LNDXDXTLC54I5V6WP355ZVE4
fp: 4576ae6a115a0bf9013d988afe393b64

2类参数

接着处理第二类参数,用户密码,密码值被传入了这个getEntryptPwd()函数,是一个加密函数。在文件login2016.js里面搜索这个函数,发现这样一段代码

function getEntryptPwd(pwd){
        var pubKey = $('#pubKey').val();
        if(!pwd || !pubKey || !SysConfig.encryptInfo){
            return pwd;
        }
        var encrypt = new JSEncrypt();
        encrypt.setPublicKey(pubKey);
        return encrypt.encrypt(pwd);
    }

谷歌一下,查到采用的是RSA加密,pubKey是公钥。假设这是一个标准的RSA加密算法,用python实现一下,需要安装依赖:crypto和pycryptodome
安装完后找到文件夹crypto,重命名成Crypto。RSA加密代码如下

这里是引用https://blog.csdn.net/Enderman_xiaohei/article/details/89325747

import base64
from Crypto.Cipher import PKCS1_v1_5 as Cipher_pksc1_v1_5
from Crypto.PublicKey import RSA

def encrpt(password, public_key):
    rsakey = RSA.importKey(public_key)
    cipher = Cipher_pksc1_v1_5.new(rsakey)
    cipher_text = base64.b64encode(cipher.encrypt(password.encode()))
    return cipher_text.decode()

if __name__ == '__main__':
    public_key = """-----BEGIN PUBLIC KEY-----""" + '\n' + pubKey + '\n' + """-----END PUBLIC KEY-----"""
    pass_word = '你的京东密码'
    print(encrpt(pass_word, public_key))
    print(public_key)

现在暂时还不能验证京东是不是采用这种标准的RSA加密,需要等到最后提交再来看对不对,先放一边。

3类参数

在登入的网页源代码里面没有找到sedSid,在source/Page里面找到seq.jd.com,在js文件夹里面最下面的一个js文件

https://seq.jd.com/jseqf.html?bizId=passport_jd_com_login_pc&platform=js&version=1

找到seqSid:_jdtdmap_sessionId

var _jdtdmap_sessionId = "4995149183628354885";
var _jdtdseq_config_data = {
    "bizId": "passport_jd_com_login_pc",
    "seqs": [{
        "elementId": "loginname",
        "special": "0",
        "selType": "id",
        "selVal": "loginname",
        "seq": ["input", "change", "focus", "blur", "keydown", "keyup", "sniffV"]
    }, {

因此只要get这个url,运用正则的方法,就可以获得seqSid了。

4类参数

authcode这个参数的分析是比较复杂的,首先感谢这篇的思路

https://zhuanlan.zhihu.com/p/54123999

按照这篇文章的说法,这个authcode是滑块验证码通过后返回的一个数值。回到network面板,这次筛选js文件:

https://iv.jd.com/slide/s.html?d=0aH003smSxmxxz007109000700f10j000800e10h000900e10i000800b10g000800910d000900910e000700910d000900610c000800610a000700610b000800610a000900210400070010000055001000000700100000090020000008002000000700100100090020010008001000000800200100080010010008001001000800000000080010010007000000000900000100090000000007000000000800000000090010010007000000000910100100xJ105005000910500600081060070007106006000910j00k0007107007000910e00d000710d00d000810d00b000810e00b000910c009000810d0090007104003000a10602900oE000000000000510n0007000000000800710v000800910v000900910x000800810v000800410c000600610n000b00710m000700510i000900510i0007000101002q00010600080001070007001106000900110700080021050009001106000700210400070011040009002109000900210700070031060009002108000700210700090021070009002106000b0001030002001103000a0011030007000000001X00010100070001010008000101000b00110200040001010009001101000900110300080011020007001102000a001102000700010100090011010006000101000a00110100070000000009000000000800000000070010000008000000000x00000000bw1020030008102003000810600600091030030005108007000a104003000710500500091050040007105005000a105003000610300300091020010007102002000a10300200071020010009101002000710200100091010010007101000000910100100081010000008101001000810100000070000000009000000000800000000081010000009000101000o000000000800000000080001010008000101000800010100080000000008001101000800010100080000000009001101000800000000080011010008000101000800100000080001010008002101000800110200080021010008002102000900310300080021020009002103000500310200090021020008002101000900210200080021020007002101000800210200090011010008002101000800110100080021010008001101000800210100080011010009002101000700110100090010000007001101000900000000080010000008001101000800000000090010000008001000000800000000080010000008000000000800100000080000000008001000000800000000080000010008001000000800000000080000010009000000000700000100080000000009000001000800000000080000010008000001000900000100060000000009000001000900000100080000000008000001000700000100090000020006000001000a000001000710100200090000010008000001000810100100080000010008000001000800000100071010000008000001000900000000090000010008101001000700000000090000000008000001000800000000081010010008000000000800000100070000000008000000000a000001000800000000080000000008000000000g000000000V0000000008000000000700000000090010000006000000000a00000000080000000009001101000f000000000800000000080000000009001000000800010100090000000005000000000a0010000008000101000800000000080000000008000000000800000000080000000008000000000900110100080000000007000000000900000000080000000008000101000g00000000080010000008000000000900000000070001010007000000000900000000090000000008001101000800000000080000000008000101000700100000090001010008001000000800010100080001010009001101000800000000080011010008000000000800000000080001010007001000000900010100080000000008000000000800110100070000000008000000000900010100090000000008000000000800010100080010000008000000000a00000000040001010009000000000900000000080000000008001000000E&c=5ba8a894fcb94425996c0de94cb475f1&w=0&appId=1604ebb2287&scene=login&product=bind-suspend&e=5B4PGABPPZMEMRMCQMYLIT3EBUOP576CMIC6TVU2ZT26UI2YXWG7POGQIIZNCFMHF2LNDXDXTLC54I5V6WP355ZVE4&s=493047111102798220&o=180******&lang=zh_CN&callback=jsonp_00890861844127846

这是一个get请求,url是https://iv.jd.com/slide/s.html?,参数有11个
分别是d,c,w,appId,scene,product,e,s,o,lang,和callback。
其中w,scene,product和lang是固定的参数。接下来逐个分析参数
appid,可以在登入的网页源代码中找到,slideAppId就是对应appid
e,代表参数eid
s,代表参数seqSid
o,代表用户名
参数c的值在这个get下面这个url后返回:

https://iv.jd.com/slide/g.html?appId=1604ebb2287&scene=login&product=bind-suspend&e=5B4PGABPPZMEMRMCQMYLIT3EBUOP576CMIC6TVU2ZT26UI2YXWG7POGQIIZNCFMHF2LNDXDXTLC54I5V6WP355ZVE4&lang=zh_CN&callback=jsonp_07506162875906321

返回结果

jsonp_07506162875906321({message: "success", challenge: "af860f44062d45aaa194e0a687d22b9d", static_servers: "//ivs.jd.com/",})
api_server: "//iv.jd.com/"
challenge: "af860f44062d45aaa194e0a687d22b9d"
message: "success"
o: "loginname"
static_servers: "//ivs.jd.com/"
success: "1"

c就是challenge,callback就用这个url里面的callback。

这样就剩一个参数d了,因为大都数登入的时候都不需要滑块验证,直接传入空字符

d = ''

python代码完整实现

from urllib import parse
import requests
import re
import base64
from Crypto.Cipher import PKCS1_v1_5 as Cipher_pksc1_v1_5
from Crypto.PublicKey import RSA
import json

def encrpt(password, public_key):
    rsakey = RSA.importKey(public_key)
    cipher = Cipher_pksc1_v1_5.new(rsakey)
    cipher_text = base64.b64encode(cipher.encrypt(password.encode()))
    return cipher_text.decode()


s = requests.session()
# 从html里面获取参数
get_params_url = 'https://passport.jd.com/new/login.aspx?'
response = s.get(url=get_params_url)

loginname = '180*******'
# 正则表达式获取
uuid = re.findall(r"""id="uuid" name="uuid" value="(.*?)"/>""", response.text)[0]
eid = '5B4PGABPPZMEMRMCQMYLIT3EBUOP576CMIC6TVU2ZT26UI2YXWG7POGQIIZNCFMHF2LNDXDXTLC54I5V6WP355ZVE4' # 隐藏参数1【存在与elenent】
fp = '4576ae6a115a0bf9013d988afe393b64'   #隐藏参数2 似乎固定参数【存在与element】
_t = '_t'
loginType = 'c'
pubKey = re.findall(r"""name="pubKey" id="pubKey" value="(.*?)" """, response.text)[0]
sa_token = re.findall(r"""id="sa_token" name="sa_token" value="(.*?)"/>""", response.text)[0]
appid = re.findall(r"""id = "slideAppId" value="(.*?)" """, response.text)[0]

response = s.get(url='https://seq.jd.com/jseqf.html?bizId=passport_jd_com_login_pc&platform=js&version=1')
seqSid = re.findall(r"""ar _jdtdmap_sessionId="(.*?)";""", response.text)[0]


# 获取challenge
callbacks = 'jsonp_03705059368865016'
slideChallengeUrl = 'https://iv.jd.com/slide/g.html?'
challengeParams = {
    'appid': appid,
    'scene': 'login',
    'product': 'bind-suspend',
    'e': eid,
    'lang': 'zh_CN',
    'callbacks': callbacks
}
challengeResponse = s.get(url=slideChallengeUrl+parse.urlencode(challengeParams))
c = json.loads(challengeResponse.text)['challenge']

# 获取authcode
getAuthcodeUrl = 'https://iv.jd.com/slide/s.html?'
d = ''    # 未知,和滑动轨迹相关
authcodeData = {
    'd': d,
    'c': c,
    'w': '0',
    'appid': appid,
    'scene': 'login',
    'product': 'bind-suspend',
    'e': eid,
    's': seqSid,
    'o': loginname,
    'lang': 'zh_CN',
    'callbacks': callbacks
}

response = s.post(url=getAuthcodeUrl, data=authcodeData)
authcode = json.loads(response.text)['validate']


print('uuid: ' + uuid)
print('pubKey: ' + pubKey)
print('sa_token: ' + sa_token)
print('seqSid: ' + seqSid)
print('challenge: ' + c)
print('authcode: ' + authcode)
public_key = """-----BEGIN PUBLIC KEY-----""" + '\n' + pubKey + '\n' + """-----END PUBLIC KEY-----"""
pass_word = '你的京东密码'
nloginpwd = encrpt(pass_word, public_key)
print('nloginpwd: ' + nloginpwd)
# print(public_key)

query_string = {
    'uuid': uuid,
    'ReturnUrl': 'https://www.jd.com/',
    'r': '0.17803919186799178',
    'version': '2015'
}
query_data = parse.urlencode(query_string)
url = 'https://passport.jd.com/uc/loginService?'+query_data


form_data = {
    'uuid': uuid,
    'eid': eid,
    'fp': fp,
    '_t': _t,
    'loginType': loginType,
    'loginname': loginname,
    'nloginpwd': nloginpwd,
    'authcode': authcode,
    'pubKey': pubKey,
    'sa_token': sa_token,
    'seqSid': seqSid,
    'useSlideAuthCode': '1'
}
response = s.post(url=url, data=form_data)
print(response.content)
print(form_data)
# # 查看全部订单---用于检测登入是否成功
get_order_url = 'https://order.jd.com/lazy/getOrderProductInfo.action'
form_data = {
    'orderWareIds': '6772447,28963064241,100003322095,3633865,1524452394,20104267538,39859829911,39859829912,39859829913,5399004,5148241,100000440283',
    'orderWareTypes': '0,0,0,0,0,0,0,0,0,0,0,0',
    'orderIds': '102533901401,101975046353,101885954715,101994752966,101725563313,100911288261,100911288261,100911288261,100911288261,100689520591,100689520591,100185092518',
    'orderTypes': '0,22,0,0,22,22,22,22,22,0,0,0',
    'orderSiteIds': '0,0,0,0,0,0,0,0,0,0,0,0',
    'sendPays': '0,0,0,0,0,0,0,0,0,0,0,0'
}

response = s.post(url=get_order_url, data=form_data)
print(response.text)

至此,整个京东模拟登入就完整实现了。可以通过查询购物车里面的东西来判断是否登陆成功。

你可能感兴趣的:(python)