爬虫之抓js教程

网友投稿 936 2022-10-02

爬虫之抓js教程

爬虫之抓js教程

在初学的爬虫过程中,很多人还不知道有些字段是如何生成的,怎样模拟生成这些字段来拼接头部。为了再次纪念【宏彦获水】成语初次面世,特地用【百度登陆】写下一篇登陆百度的教程,以供大家参考。

前面学习了如何在 ​​get​​​ 的时候想服务器发送多变的请求数据,从而达到搜索的效果,而实际上 ​​搜索是简单的登陆​​​ !所以本文将要介绍如何向百度服务器发送 ​​post​​ 数据,从而达到模拟登陆百度的效果。

在 ​​firebug​​​ 中,找到如下一行 ​​POST?login​​ :

如果百度后台认为此 登陆表单请求 是正确的后,会在 头信息 -> 响应头信息 中返回一个 ​​Set-Cookie​​​ 。当我们登陆成功后,关闭浏览器,下次再打开浏览器的时候发现百度还是处于一种登陆的状态,这就是和 ​​Cookie​​​ 有关。在百度登陆成功后会返回一个 ​​Cookie​​ 储存到浏览器中,下次再打开百度的时候,浏览器中的 头信息 -> 请求头信息 中会携带一个 ​​Cookie​​​ ,这个 ​​Cookie​​​ 就是百度服务器判断你以前是否登陆过百度。而这个 ​​Cooike​​​ 就是 ​​Set-Cookie​​ 加工而来的!那么重点来了,如果要用代码模拟登陆百度,应该要具备以下几个步骤:

构造请求表单请求成功后获取​​Cookie​​​ (这个​​Cookie​​​ 并非​​Set-Cookie​​)在请求头部​​header​​​ 中携带这个​​Cookie​​ ,就可以以登陆过后的身份访问百度

原理讲清楚了,那么下面开始实践!

构造请求表单

可以发现,请求的表单有

staticpagecharsettokentplsubproapiverttcodestringsafeflguisPhonedetectgidquick_userlogintypelogLoginTypeidcloginmergesploginusernamepasswordverifycodemem_passrsakeycrypttypeppui_logintimecountrycodefp_uidfp_infologinversiondstkdvtraceidcallback

其中,被红框框起来的表单是多次请求变化的:

callbacktttokenppui_logintimersakeyverifycode

而 ​​ds​​​、​​tk​​ 在第一次请求网页直接生成了:

​​json​​​,所以得到 ​​ds​​​、​​tk​​:

jsonpCallbackb5819({"code":0,"data":{"tk":"1966\/wzQ9fSm481E1Dd6MPpdaM08fX2AB5MkNq1aMZHDBoekhU51\/8+yOdlYGlLXJVKpduaYRnOVNhfERmTiBXB1Vw==","as":"a82478bc","ds":"oLZa10fYIvKavmDHTaWvTF5D9f3NBzweejdgFGUJB9yI6TFVGHZ8EtWhXcLshwfDL0sU7ymlQe3uVByWIXCym03HZTZxZmGaXl8Jw+unuO5D3SN29KiMO0oj1fSH58BU"}})

其中很明显可以看出来的是:

​​tt​​ 时间戳​​verifycode​​ 验证码

那么就剩下几个请求表单还暂时无法得知,首先查找 ​​callback​​:

一直搜索,最后发现 ​​callback​​​ 和 ​​getUniqueId​​ 的生成有关:

那么换着 ​​getUniqueId​​​ 来搜索,得到如下 ​​javascrip​​ 代码:

e.getUniqueId = function (e) {return e + Math.floor(2147483648 * Math.random()).toString(36)},

和上面的 ​​JavaScrip​​​ 整理起来,那么 ​​callback​​ 的生成代码为:

function callback(){ return 'bd__cbs__'+Math.floor(2147483648 * Math.random()).toString(36) }

找到 ​​callback​​​ 后,接下来要去寻找 ​​token​​​ 。在 ​​firebug​​​ 中寻找 ​​token​​ 第一次在哪里出现。最后发现首次出现在网址:

​​Json​​ :

bd__cbs__3cagws({"errInfo": {"no": "0"}, "data": {"rememberedUserName": "", "codeString": "", "token": "6245a75e6ba48d39033a8c31dfcb37c7", "cookie": "1", "usernametype": "", "spLogin": "rate", "disable": "", "loginrecord": {'email': [], 'phone': []}}})

第一次 ​​token​​​ 出现的地方找到了,那么分析一下请求出 ​​token​​ 的网址,网址中涉及到的变量有:

tplapiverttclassgidlogintypecallback

为了查看哪些变量是变化的,就再次进行多次登陆。最后发现,变化的是:

ttgidcallback

其中 ​​tt​​​ 为长时间戳, ​​callback​​​ 在前面已经找到并且能生成了,那么只剩下 ​​gid​​​ 这个变量。老规矩,按照下面的步骤再去找出 ​​gid​​ :

搜索发现 ​​gid​​​ 是由 ​​gid: e.guideRandom​​ 这个函数生成的:

那么接着搜搜这个函数 ​​guideRandom​​​ ,找到如下 ​​JavaScrip​​ 代码:

this.guideRandom = function () {return 'xxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (e) {var t = 16 * Math.random() | 0,n = 'x' == e ? t : 3 & t | 8;return n.toString(16)}).toUpperCase()}(),

整理一下让其可以在 ​​python​​ 中运行:

function gid(){ return 'xxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (e) { var t = 16 * Math.random() | 0, n = 'x' == e ? t : 3 & t | 8; return n.toString(16) }).toUpperCase() }

这样,根据 ​​gid​​​ 和 ​​callback​​​ 就能得到 ​​token​​ 了!

下面继续寻找 ​​ppui_logintime​​ ,按照规矩来:

接着搜索 ​​timeSpan​​ ,得到如下信息:

s.timeSpan = (new Date).getTime() - e.initTime

现在还是看不出什么东西,那么就继续搜索 ​​initTime​​ ,得到如下代码:

_initApi: function (e) {var t = this;t.initialized = !0,t.initTime = (new Date).getTime(),passport.data.getApiInfo({apiType: 'login',gid: t.guideRandom || '',loginType: t.config && t.config.diaPassLogin ? 'dialogLogin' : 'basicLogin'}).success(function (n) {var i = t.fireEvent('getApiInfo', {rsp: n});

继续查找 ​​initApi​​ ,找到位置:

那么最后还剩下一个变量 ​​rsakey​​​ ,在查找网页的时候发现第一次出现 ​​rsakey​​ 的地方是:

​​key​​ ,虽然名字不一样,但是值是一样的:

bd__cbs__tpdrlq({"errno": '0', "msg": '', "pubkey": '-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDiA2HxDW2iVnunx7faCBG3YGBy\nvvF+ysFAIXIVjFTseU7x\/f+Gpr1VTWe2Kxc2dlzBkn5NuRHVxbyXCawu0QlMUfb8\nI2ukM1cIlL0e+B1nBnIp03oXjFvQNhIu58SI6vCoihWX6Qwhb6ZOvJdA249zCNBU\nlTyd7RVwgwaAthI6gQIDAQAB\n-----END PUBLIC KEY-----\n', "key": 'wS27H0665CWXK64i2VP02AYtjQUTujkb'})

分析一下这个网址,出现的变量有:

tokentplapiverttgidcallback

这些变量在前面都能找到,所以也就是说,根据 ​​gid​​​ 、 ​​callback​​​ 、 ​​token​​​ 就能得到 ​​rsakey​​ 了!

下面开始讲解怎么用 ​​python​​​ 来实现模拟百度登陆!首先需要构造一个持续登陆的链接,持续登陆的链接能够一直自我保存打开网页或者登陆后留下的 ​​cookie​​ ,当然这是存放在内存中的,例如:

headers = {"User-Agent": "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:32.0) Gecko/20100101 Firefox/32.0"}session = requests.session()session.get("headers=headers)

​​session​​​ 就是一个持续的链接,一般用 ​​python​​​ 访问网页是这样子调用的 ​​requests.get​​​ ,这样子的访问不会保存历史访问留下的 ​​cookie​​​ ,而用 ​​session.get​​​ 能持续保存 ​​cookie​​​ ,只要后面访问都用 ​​session.get​​​ 或者 ​​session.post​​ 即可。

获取callback

​​callback​​​ 是由 ​​JavaScrip​​ 生成的:

function callback(){ return 'bd__cbs__'+Math.floor(2147483648 * Math.random()).toString(36) }

所以直接在 ​​python​​​ 中运行这个 ​​JavaScrip​​​ 就行了。 ​​python​​​ 运行 ​​JavaScrip​​​ 需要安装库 ​​pyexecjs​​​,在命令指示符下直接输入 ​​pip3 install pyexecjs​​ 即可。调用方式为:

import execjsjs = '''function callback(){ return 'bd__cbs__'+Math.floor(2147483648 * Math.random()).toString(36) }'''ctx = execjs.compile(js)callback = ctx.call("callback")

获取traceid

​​traceid​​​ 同样是可以用 ​​JavaScrip​​ 生成的,直接调用即可:

import execjsjs = '''function traceid(){ var e = {a: 1, b: 1, c: 1} e.traceID = { headID: e.traceID && e.traceID.headID || "", flowID: e.traceID && e.traceID.flowID || "", cases: e.traceID && e.traceID.cases || "", initTraceID: function(e) { var t = this; e && e.length > 0 ? (t.headID = e.slice(0, 6), t.flowID = e.slice(6, 8)) : t.destory() }, createTraceID: function() { var e = this; return e.headID + e.flowID + e.cases }, startFlow: function(e) { var t = this , n = t.getFlowID(e); 0 === t.flowID.length || t.flowID === n ? (t.createHeadID(), t.flowID = n) : t.finishFlow(n) }, finishFlow: function() { var e = this; e.destory() }, getRandom: function() { return parseInt(90 * Math.random() + 10, 10) }, createHeadID: function() { var e = this , t = (new Date).getTime() + e.getRandom().toString() , n = Number(t).toString(16) , i = n.length , s = n.slice(i - 6, i).toUpperCase(); e.headID = s }, getTraceID: function(e) { var t = this , n = e && e.traceid || ""; t.initTraceID(n) }, getFlowID: function(e) { var t = { login: "01", reg: "02" }; return t[e] }, setData: function(e) { var t = this; return e.data ? e.data.traceid = t.createTraceID() : e.url = e.url + (e.url.indexOf("?") > -1 ? "&" : "?") + "traceid=" + t.createTraceID(), e }, destory: function() { var e = this; e.headID = "", e.flowID = "" } }; e.traceID.initTraceID() e.traceID.createHeadID() return e.traceID.createTraceID() + "01" }'''ctx = execjs.compile(js)traceid = ctx.call("traceid")

获取gid

​​gid​​​ 同样是可以用 ​​JavaScrip​​ 生成的,直接调用即可:

import execjsjs = '''function gid(){ return 'xxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (e) { var t = 16 * Math.random() | 0, n = 'x' == e ? t : 3 & t | 8; return n.toString(16) }).toUpperCase() }'''ctx = execjs.compile(js)gid = ctx.call("gid")

获取时间tt

时间 ​​tt​​​ 是一个毫秒级别的长时间,而 ​​python​​​ 生成的时间戳是短时间,所以要在短时间戳后面加上毫秒的长度即可,这里处理的方法是:在短时间戳的后面加上 ​​3​​ 位数的随机数,从而构造出长时间戳。

import timeimport randomtimerandom = random.randint(100, 999)nowtime = int(time.time())tt = str(nowtime) + str(timerandom)

获取token

有了 ​​callback​​​ 、 ​​gid​​​ 、 ​​tt​​​ 后,可以获取到 ​​token​​ ,构造请求参数:

tokendata = { "tpl": "pp", "subpro": "", "apiver": "v3", "tt": tt, "class": "login", "gid": gid, "logintype": "basicLogin", "callback": callback }

更新头部,携带头部访问:

headers.update(dict(Referer="Accept="*/*", Connection="keep-alive", Host="passport.baidu.com"))resp = session.get(url="params=tokendata, headers=headers)

顺利抓到包含 ​​token​​ 的返回值,将其放到字典里面即可:

data = json.loads(re.search(r".*?\((.*)\)", resp.text).group(1).replace(""", """))token = data.get('data').get('token')

顺利返回 ​​token​​ !

获取rsakey

获取 ​​rsakey​​ 只需要构造如下请求参数即可:

tt = get_tt()get_data = { "token": token, "tpl": "pp", "subpro": "", "apiver": "v3", "tt": tt, "gid": gid, "callback": callback,}

在得到的返回值中提取出 ​​rsakey​​​ 和 ​​pubkey​​ 既可:

tt = get_tt()rsakeydata = { "token": token, "tpl": "pp", "subpro": "", "apiver": "v3", "tt": tt, "gid": gid, "callback": callback,}resp = session.get(url="headers=headers, params=rsakeydata)data = json.loads(re.search(r".*?\((.*)\)", resp.text).group(1).replace("'", '"'))dicts = {}dicts["rsakey"] = data.get("key")dicts["pubkey"] = data.get("pubkey")

加密密码

百度登陆的密码加密方式是很简单的 ​​RSA​​​ 加密,这个只是用 ​​JavaScrip​​​ 就能实现,翻译成 ​​python​​ 的代码为:

def base64_password(password, pubkey): pub = rsa.PublicKey.load_pkcs1_openssl_pem(pubkey.encode("utf-8")) encript_passwd = rsa.encrypt(password.encode("utf-8"), pub) return base64.b64encode(encript_passwd).decode("utf-8")

需要安装库 ​​rsa​​ ,只需要在命令指示符下输入:

pip3 install rsa

登陆

构造一个登陆的 ​​postdata​​ :

post_data = { "staticpage": " "charset": "utf-8", "token": token, "tpl": "pp", "subpro": "", "apiver": "v3", "tt": tt, "codestring": "", "safeflg": 0, "u": " "isPhone": "", "detect": 1, "gid": gid, "quick_user": 0, "logintype": "basicLogin", "logLoginType": "pc_loginBasic", "idc": "", "loginmerge": "true", "foreignusername": "", "username": username, "password": newpassword, "mem_pass": "on", # 返回的key "rsakey": rsakey, "crypttype": 12, "ppui_logintime": 33554, "countrycode": "", "dv": dv, "callback": "parent." + callback }

直接登陆:

resp = session.post(url="data=post_data, headers=headers)

如果检测到自己在账号包含在返回的 ​​html​​ 里面,则说明登陆成功:

if username in resp.content.decode("utf-8", "ignore"): print("登录成功") else: print("登录失败")

登陆成功后有两种方式在登陆状态下访问网页:

持续使用​​session​​获取登录后的​​cookie​​

第一种方法在本次程序跑完后就会自动将后台保存下来的 ​​cookie​​​ 丢弃掉,如果下次需要访问则需要重新登陆;第二种方法只要在头部增加这个 ​​cookie​​​ 值,就能一直使用 ​​cookie​​​ 保证是登陆状态,获取登录后的 ​​cookie​​ 的方法为:

cookies = requests.utils.dict_from_cookiejar(session.cookies)print(cookies)

等到的 ​​cookies​​​ 为一个字典,将这个字典保存在本地的 ​​json​​ 中:

import jsonfile = open("cookie.json","w")file.write(json.dumps(cookies))file.close()

下次访问携带这个 ​​cookies​​ 即可:

json_file = open("cookie.json")cookies = json.load(json_file)json_file.close()header = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64; rv:32.0) Gecko/20100101 Firefox/32.0', 'Host': 'passport.baidu.com', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-Encoding': 'gzip, deflate', 'Accept-Language': 'zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3', 'Connection': 'keep-alive'}home_page = requests.get("headers=headers,cookies=cookies).content.decode("utf-8", "ignore")print(home_page)

这里需要提醒的是 ​​cookie​​​ 会过期,一般是 ​​7​​​ 天,如果发现使用 ​​cookie​​​ 登陆失败,那么就需要重新使用账号密码登陆获取 ​​cookie​​。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:浅谈小程序开发商城系统的步骤(小程序商城搭建步骤)
下一篇:浅谈微信小程序开发和APP开发的区别(微信小程序是微信开发的吗)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~