大家好,今天来为大家解答实时定位网站源码分享这个问题的一些问题点,包括定位追踪网站也一样很多人还不知道,因此呢,今天就来为大家分析分析,现在让我们一起来看看吧!如果解决了您的问题,还望您关注下本站哦,谢谢~
关注微信公众号:K哥爬虫,持续分享爬虫进阶、JS/安卓逆向等技术干货!
声明
本文章中所有内容仅供学习交流,抓包内容、敏感网址、数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请在公众号联系我立即删除!
逆向目标
本次的目标是拉勾网职位的爬取,涉及到的一些关键参数如下:
请求头参数:traceparent、X-K-HEADER、X-S-HEADER、X-SS-REQ-HEADER、x-anit-forge-code、x-anit-forge-tokenCookie值:user_trace_token、X_HTTP_TOKEN、__lg_stoken__POST请求数据加密,返回的加密职位信息解密,AES算法
参数比较多,但事实上有些参数固定、或者直接不要,也是可以的,比如Cookie的三个值,请求头的X-K-HEADER、X-SS-REQ-HEADER等可以固定,x-anit-forge-code和x-anit-forge-token可有可无。尽管如此,本文还是把每个参数的来源都分析了,可根据你实际情况灵活处理。
另外即便是把所有参数都补齐了,拉勾网对于单个IP还有频率限制,抓不了几次就要求登录,可自行搭配代理进行抓取,或者复制账号登录后的cookies到代码里,可以解除限制,如果是账号登录后访问,请求头多了两个参数,即x-anit-forge-code和x-anit-forge-token,经过测试这两个参数其实不要也行。
抓包分析
搜索职位,点击翻页,就可以看到一条名为positionAjax.json的Ajax请求,不难判断这就是返回的职位信息。重点参数已在图中框出来了。
未登录,正常IP,正常请求,Header以及Cookies:
异常IP,登录账号后再请求,Header以及Cookies:
请求数据和返回数据都经过了加密:
Cookies参数
先看cookies里的关键参数,主要是user_trace_token、X_HTTP_TOKEN和__lg_stoken__。
user_trace_token
通过接口返回的,直接搜索就可以找到,如下图所示:
请求参数,time是时间戳,a值随便,没有都可以,不影响,其他值都是定值,获取的关键代码如下:
defget_user_trace_token()->str:\n34;https://a.脱敏处理.com/json&34;Host&34;a.脱敏处理.com&34;Referer&34;https://www.脱敏处理.com/&34;User-Agent&34;lt&34;trackshow&34;t&34;ad&34;v&34;dl&34;https://www.脱敏处理.com/&34;dr&34;https://www.脱敏处理.com&34;time&34;user_trace_token&39;usestrict&34;&39;cookie&39;Hook捕获到cookie设置->&39;X_HTTP_TOKEN&34;cookie&39;0x2d&39;/&39;0x26&39;0x26&39;0x27&39;0x28&39;0x29&39;0x2a&39;0x2b&39;0x2c&39;Date&39;0x2d&39;/&39;0x2e&39;hostname&39;substr&获取cookie中的__lg_stoken__\ntoken_url=&34;\ntoken_headers={\n&34;:&34;,\n&34;:&34;,\n&34;:UA\n}\nparams={\n&34;:original_data[&34;],\n&34;:original_data[&34;]\n}\ntoken_response=requests.get(url=token_url,params=params,headers=token_headers,cookies=global_cookies,allow_redirects=False)\niftoken_response.status_code!=302:\nraiseException(&34;)\n34;Location&34;login&34;IP被关进小黑屋啦!需要登录!请补全登录后的Cookie,或者自行添加代理!&url的参数为待加密对象\nsecurity_check_params=parse_result.query\n34;name&发送请求,获取混淆的js\njs_url=&34;+security_check_js_name+&34;\njs_headers={\n&34;:&34;,\n&34;:security_check_url,\n&34;:UA\n}\njs_response=requests.get(url=js_url,headers=js_headers,cookies=global_cookies).text\n34;&34;\nwindow={\n&34;:{\n&34;:&34;,\n&34;:&39;\n}\n}\nfunctiongetLgStoken(){\nreturnwindow.gt.prototype.a()\n}\n&34;&34;getLgStoken&34;login&34;true&34;gate_login_token&34;54a31e93aa904a6bb9731bxxxxxxxxxxxxxx&34;_putrc&34;9550E53D830BE8xxxxxxxxxxxxxx&34;JSESSIONID&34;ABAAAECABIEACCA79BFxxxxxxxxxxxxxx&更新x-anit-forge-code和x-anit-forge-token\nurl=&34;\nheaders={\n&34;:&34;,\n&34;:&34;,\n&34;:UA\n}\nparams={\n&34;:original_data[&34;],\n&34;:original_data[&34;]\n}\nresponse=requests.get(url=url,params=params,headers=headers,cookies=global_cookies)\ntree=etree.HTML(response.text)\nnext_data_json=json.loads(tree.xpath(&39;__NEXT_DATA__&34;)[0])\nsubmit_code=next_data_json[&34;][&34;][&34;]\nsubmit_token=next_data_json[&34;][&34;][&34;]\n34;submitCode&submitToken为空,请检查JSESSIONID是否正确!&34;x-anit-forge-code&34;x-anit-forge-token&39;Hook捕获到%s设置->%s&39;traceparent&39;get-random-values&34;&34;00-&34;-&34;-&34;01&34;jsencrypt&34;ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=&34;&34;—–BEGINPUBLICKEY—–MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnbJqzIXk6qGotX5nD521Vk/24APi2qx6C+2allfix8iAfUGqx0MK3GufsQcAt/o7NO8W+qw4HPE+RBR6m7+3JVlKAF5LwYkiUJN1dh4sTj03XQ0jsnd3BYVqL/gi8iC4YXJ3aU5VUsB6skROancZJAeq95p7ehXXAJfCbLwcK+yFFeRKLvhrjZOMDvh1TsMB4exfg+h2kNUI94zu8MK3UA7v1ANjfgopaE+cpvoulg446oKOkmigmc35lv8hh34upbMmehUqB51kqk9J7p8VMI3jTDBcMC21xq5XF7oM8gmqjNsYxrT9EVK7cezYPq7trqLX1fyWgtBtJZG7WMftKwIDAQAB—–ENDPUBLICKEY—–&34;aesKey&34;rsaEncryptData&通过JS获取AESKey,并通过接口激活,接口激活后会返回一个secretKeyValue,后续请求头会用到\nglobalaes_key,secret_key_value\nurl=&34;\nheaders={\n&34;:&34;,\n&34;:&34;,\n&34;:&34;,\n&34;:&34;,\n&34;:UA\n}\nencrypt_data=lagou_js.call(&34;)\naes_key=encrypt_data[&34;]\nrsa_encrypt_data=encrypt_data[&34;]\ndata={&34;:rsa_encrypt_data}\nresponse=requests.post(url=url,headers=headers,json=data).json()\nsecret_key_value=response[&34;][&34;]
X-S-HEADER
X-S-HEADER你每次翻页都会改变,直接搜索关键字可定位:
中间有一个SHA256加密,最后返回的Rt(JSON.stringify({originHeader:JSON.stringify(e),code:t}))就是X-S-HEADER的值了,Rt()是一个AES加密,比较关键的,Vt(r)是一个URL,比如你搜索职位就是positionAjax.json,搜索公司就是companyAjax.json,可根据实际情况定制,然后Lt(t)就是搜索信息,字符串形式,包含了城市、页码、关键词等。
获取X-S-HEADER的JS代码大致如下:
CryptoJS=require(&39;)\n\njt=function(aesKey,originalData,u){\nvare={deviceType:1}\n,t=&34;.concat(JSON.stringify(e)).concat(u).concat(JSON.stringify(originalData))\n,t=(t=t,null===(t=CryptoJS.SHA256(t).toString())||void0===t?void0:t.toUpperCase());\n\nreturnRt(JSON.stringify({\noriginHeader:JSON.stringify(e),\ncode:t\n}),aesKey)\n}\n\nRt=function(t,aesKey){\nvarOt=CryptoJS.enc.Utf8.parse(&34;),\nDt=CryptoJS.enc.Utf8.parse(aesKey),\nt=CryptoJS.enc.Utf8.parse(t);\nt=CryptoJS.AES.encrypt(t,Dt,{\niv:Ot,\nmode:CryptoJS.mode.CBC,\npadding:CryptoJS.pad.Pkcs7\n});\nreturnt.toString()\n};\n\nfunctiongetXSHeader(aesKey,originalData,u){\nreturnjt(aesKey,originalData,u)\n}\n\n//测试样例\n//varurl=&34;\n//varaesKey=&34;\n//varoriginalData={&34;:&34;,&34;:&34;,&34;:&34;,&34;:&34;,&34;:&34;}\n//console.log(getXSHeader(aesKey,originalData,url))
请求/返回数据解密
前面抓包我们已经发现positionAjax.json是POST请求,FormData中的数据是加密的,返回的data也是加密的,我们分析请求头参数的时候,就涉及到AES加密解密,所以我们直接搜索AES.encrypt、AES.decrypt,下断点调试:
非常明显了,这部分的JS代码大致如下:
CryptoJS=require(&39;)\n\nfunctiongetRequestData(aesKey,originalData){\nreturnRt(JSON.stringify(originalData),aesKey)\n}\n\nfunctiongetResponseData(encryptData,aesKey){\nreturnIt(encryptData,aesKey)\n}\n\nRt=function(t,aesKey){\nvarOt=CryptoJS.enc.Utf8.parse(&34;),\nDt=CryptoJS.enc.Utf8.parse(aesKey),\nt=CryptoJS.enc.Utf8.parse(t);\nt=CryptoJS.AES.encrypt(t,Dt,{\niv:Ot,\nmode:CryptoJS.mode.CBC,\npadding:CryptoJS.pad.Pkcs7\n});\nreturnt.toString()\n};\n\nIt=function(t,aesKey){\nvarOt=CryptoJS.enc.Utf8.parse(&34;),\nDt=CryptoJS.enc.Utf8.parse(aesKey);\nt=CryptoJS.AES.decrypt(t,Dt,{\niv:Ot,\nmode:CryptoJS.mode.CBC,\npadding:CryptoJS.pad.Pkcs7\n}).toString(CryptoJS.enc.Utf8);\ntry{\nt=JSON.parse(t)\n}catch(t){}\nreturnt\n}\n\n//测试样例,注意,encryptedData数据太多,省略了,直接运行解密是会报错的\n//varaesKey=&34;\n//varencryptedData=&34;\n//varoriginalData={&34;:&34;,&34;:&34;,&34;:&34;,&34;:&34;,&34;:&34;}\n//console.log(getRequestData(aesKey,originalData))\n//console.log(getResponseData(encryptedData,aesKey))
大致的Python代码如下:
defget_header_params(original_data:dict)->dict:\n职位搜索URL,如果是搜索公司,那就是https://www.脱敏处理.com/jobs/companyAjax.json,根据实际情况更改\nu=&34;\nreturn{\n&34;:lagou_js.call(&34;),\n&34;:secret_key_value,\n&34;:lagou_js.call(&34;,aes_key,original_data,u),\n&34;:json.dumps({&34;:secret_key_value})\n}\n\n\ndefget_encrypted_data(original_data:dict)->str:\n34;getRequestData&携带加密后的请求数据和完整请求头,拿到密文,AES解密得到明文职位信息\nurl=&34;\nreferer=parse.urljoin(&34;,parse.urlencode(original_data))\nheaders={\n34;content-type&34;application/x-www-form-urlencoded;charset=UTF-8&34;Host&34;www.脱敏处理.com&34;Origin&34;https://www.脱敏处理.com&34;Referer&34;traceparent&34;traceparent&34;User-Agent&34;X-K-HEADER&34;X-K-HEADER&34;X-S-HEADER&34;X-S-HEADER&34;X-SS-REQ-HEADER&34;X-SS-REQ-HEADER&添加x-anit-forge-code和x-anit-forge-token\nheaders.update(x_anit)\n\ndata={&34;:encrypted_data}\nresponse=requests.post(url=url,headers=headers,cookies=global_cookies,data=data).json()\nif&34;inresponse:\nifnotresponse[&34;]and&34;inresponse[&34;]:\nraiseException(&34;%response[&34;])\nelse:\nraiseException(&34;)\nelse:\nresponse_data=response[&34;]\ndecrypted_data=lagou_js.call(&34;,response_data,aes_key)\nreturndecrypted_data
最终整合所有代码,成功拿到数据:
逆向小技巧
浏览器开发者工具Application-Storage选项,可以一键清除所有Cookies,也可以自定义存储配额:
Storage-Cookies可以查看每个站点的所有Cookies,HttpOnly打勾的表示是服务器返回的,选中一条Cookie,右键可以直接定位到哪个请求带了这个Cookie,也可以直接编辑值,还可以删除单个Cookie,当你登录了账号,但又需要清除某个Cookie,且不想重新登录时,这个功能或许有用。
完整代码
文中给出了部分关键代码,不能直接运行,部分细节可能没提及到,完整代码已放GitHub,均有详细注释,欢迎Star。所有内容仅供学习交流,严禁用于商业用途、非法用途,否则由此产生的一切后果均与作者无关,在仓库中下载的文件学习完毕之后请于24小时内删除!
仓库地址:https://github.com/kgepachong/crawler/
常见问题
JS代码里引用了三个库,npminstall安装一下即可,如果安装了还提示找不到库,那就是路径问题,推荐在当前目录下执行命令安装,或者在Python代码里指定完整路径,具体方法可自行百度。jsencrypt这个库,本地运行可能会报错windowisnotdefined,在\\node_modules\\jsencrypt\\bin\\jsencrypt.js源码中加入varwindow=global;即可,这是实现RSA加密的库,当然还有很多其他实现方法或者库,都可以。execjs执行JS的时候,可能会报编码错误&34;can&39;utf-8&34;utf-8″)
关于实时定位网站源码分享的内容到此结束,希望对大家有所帮助。
