网上看到有人要抓这网站,刚有空所以研究下,写下过程,比较简单。
首先老三样,抓包,看参数,可以看到,header中有验证参数.
看了下就这一下验证参数,拿这个参数和body里的参数到postman中模拟发送下看看,成功,说明就这一个参数,解决这个就能正常抓取。
Authorization 肯定是在发送前在js生成的,F12 筛选js文件, 刷新页面,ctrl+f 搜索 js中搜索下 secretKeyVersion看看,明显是第一个,因为其他的都是请求里的,咱们要找js里的,然后 到对应 JS里面看看,点击Sources , 找到c73f210.js 这个JS。
将JS格式化一下,方便调试,然后 在这个JS中搜索secretKeyVersion ,定位到关键字位置。
可以看到,从这里加入到header的,sign也在,所以确定是这块,现在 就是看一下这个 sign是怎么生成的,有个写死字符串,
可能是key - - 好多人都在js 中写死- 然后给 e.headers.Authorization = JSON.stringify({ 这一行下断,页面翻页,让触发请求,会断到
这个地方,因为他拿数据会用到这个sign。
到断点后就可以看看这个Ct.c是个啥了, 直接把 Object(Ct.c) 粘贴到Console下打印看看,应该 是加密方法,那后台那个括号里面就应该是参数了。跟进去看看,
在打印出来的这个函数上点一下就能自动跟踪到对应 方法了。
到加密方法了,应该是用AES 的ECB模式加密的,咱们自己模拟请求的话得实现这个,先不管,看看他用的啥库,一般不会自己写的,都用的公共库。
在r.a.AES.encrypt 这一行下断,让代码执行到这一行,然后把这个方法拿到console执行一下,跟踪到对应加密方法里。
现在来猜猜他用的是不是公共 js库,翻一翻找找一些常量,不可变参数(因为js代码大部分都会混淆的),例如
然后去github搜索下代码试试,比较下就可以确认是用的cryptoJS(如果是自己实现的话就要自己动手了),这就好办,下载一份试试,测试下
我模拟加密了下效果一模一样。
OK,加密过程搞明白 ,现在开始模拟,我用的 python , 有二种方法,一种模拟执行js,一种自己根据他的加密方式实现一套,我在网上查了查,有人实现过,
拿过来改改就能用。没有这个包的同学Crypto , 用pip install pycrypto 安装。
from Crypto.Cipher import AES
import base64
import requests
class EncryptClass:
def add_to_16(self, s):
while len(s) % 16 != 0:
s += (16 - len(s) % 16) * chr(16 - len(s) % 16)
return str.encode(s) # 返回bytes
def encry(self, text, key='WTAHAPPYACTIVITY'):
aes = AES.new(str.encode(key), AES.MODE_ECB) # 初始化加密器,本例采用ECB加密模式
encrypted_text = str(base64.encodebytes(aes.encrypt(self.add_to_16(text))), encoding='utf8').replace('\n', '') # 加密
encrypted_text = encrypted_text.replace('/', "_").replace('+', "-") # ddd.replace(/\//g, "^")
return encrypted_text
# -*- coding:utf-8 -*-
from encrypt import EncryptClass
import requests
import json
import time
word = '{"appId":"1","timestamp":' + str(int(time.time())) +',"serverCode":"0"}'
key = 'WTAHAPPYACTIVITY' # 此处问加密key值
encrypt = EncryptClass()
sign = encrypt.encry(word, key)
# print(sign)
headers = {
"from": "web",
"Host": "gate.8btc.com",
'content-type': 'application/json',
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.182 Safari/537.36",
"Authorization": json.dumps({
"secretKeyVersion": 1,
"sign": str(sign)
})
}
post_data = {
"operationName": "listArticle",
# offset 用来翻页的,改变这个就行,每次+20
"variables":{"first":20,"offset":40,"informationFlow":True,"tag":6250},
"query" : "query listArticle($first: Int = 20, $offset: Int, $category: Int, $tag: Int, $informationFlow: Boolean, $country: String) { articleGraph { list: listArticle(page: {first: $first, offset: $offset, pattern: OFFSET}, param: {categoryId: $category, tagId: $tag, country: $country, informationFlow: $informationFlow}) { ...articleListFragment __typename } __typename }}fragment articleListFragment on BaseArticleConnection { edges { node { id template post { title thumbnail desc postDate isOriginal __typename } extra { tags { name termId slug taxonomy __typename } authorInfo { id uid base { displayName avatar __typename } __typename } __typename } ... on Venture { meta { cat amount round area investors date project __typename } __typename } ... on Weekly { weeklyNum __typename } ... on Special { themeNum __typename } ... on Policy { country __typename } __typename } __typename } pageInfo { totalCount __typename } __typename}"
}
url_api = "https://gate.8btc.com/one-graph-auth/graphql"
res = requests.post(url_api, headers = headers, json = post_data)
result_data = res.json()
for item in result_data['data']['articleGraph']['list']['edges']:
# print(item['node']['extra']['post'])
print(json.dumps(item['node']['post']['title'], sort_keys=True, indent=2, ensure_ascii=False))
看看效果,稍等改造下就能用啦。OK结束。