title: CSDN逆向
date: 2021-12-13 22:32:05
tags: js 爬虫逆向
CSDN逆向分析思路
1.先定义表结构
注意事项
- char类型,要设置最大的长度
- 对于无法确定最大长度的 可以设置为text类型
- 设计表的时候,采集到的数据经量格式化
- default值尽量设置,null=true
from peewee import *
db = MySQLDatabase('spider',host='localhost',port=3306,user='root',password='1234')
class BaseModel(Model):
class Meta:
database = db # This model uses the "people.db" database. 这张表对应哪个库
class Topic(BaseModel):
title = CharField()
Content = TextField()
id = IntegerField()
author = CharField()
create_time = DateTimeField()
answer_nums = IntegerField(default=0)
chick_nums = IntegerField(default=0)
praised_nums = IntegerField(default=0)
class Answer(BaseModel):
topic_id = IntegerField()
author = CharField()
create_time = DateTimeField()
Content = TextField()
praised_nums = IntegerField()
class Author(BaseModel):
name = CharField()
id = IntegerField()
chick_nums = IntegerField() # 访问数
original_nums = IntegerField(default=0) # 原创数
rate = IntegerField(default=-1) # 排名
answer_nums = IntegerField(default=0) # 评论数
praised_nums = IntegerField(default=0) # 获赞数
desc = TextField(null=True) # 描述
industry = CharField(null = True) # 关注的标签
followers = IntegerField(default=0) #粉丝数
if __name__ == '__main__':
# 创建出框架
db.create_tables([Topic,Answer,Author])
2.简单确定反爬步骤
-
当我们拿到一个网站,首先可以尝试查看页面源代码 看是否包含
-
查看所有js文件 搜索关键词 如果有则证明写在js文件中
-
刚开始没有 极有可能在点击之后出现 在all里面可以找到data
-
分析url的构成 尝试写代码 发送请求获取响应
import requests url = "https://bizapi.csdn.net/community-cloud/v1/homepage/community/by/tag?deviceType=PC&tagId=4" headers = { "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36" } resp = requests.get(url,headers=headers) print(resp.status_code) # 400
-
当加入了UA等常参数 仍然返回错误状态码时,采用暴力操作,将请求头全部加入 HTTP是无状态协议 也就是只要我能模仿出参数 浏览器就会通过
-
可是运行之后 我们发现返回403 表示没有权限
-
此时我们分析一下请求 不可能通过通用的一些协议来反爬 关键是找我们不熟悉的 以下四个我们不熟悉
x-ca-key: 203899271 x-ca-nonce: 036b20a8-ee16-4537-b475-ac9c7dbc7865 x-ca-signature: QyWaJYtvndqtkQbBjvgniTMk69WaSD9r3sjPMcGZ5uc= x-ca-signature-headers: x-ca-key,x-ca-nonce
一个判断方法是 参数是否固定 此时我们用无痕浏览重新打开网页 此时参数如下
x-ca-key: 203899271 x-ca-nonce: d00c7765-1d7b-4d5f-b5dc-4f348346b948 x-ca-signature: eGrfMJvN+t9hftBqcbXBHoMSUpst+9ybt2KrRm4LJQg= x-ca-signature-headers: x-ca-key,x-ca-nonce
我们发现 x-ca-nonce --暂时的 临时的只使用一次的 x-ca-signature --签名 这两个值不是固定的 也就是说这就是反爬的点
-
我们此时的任务是:分析那个临时参数怎么来的 签名咋来的
(ps:签名是浏览器校验身份的一种密钥)
-
拿着x-ca-signature 去js文件一个一个找
-
可是我们发现 是被压缩过的 此时打开 headers 找域名csdnim.cn 打开sources 找到这个域名的文件 打开
可以发现 是通过p函数的
-
在想进入的函数打个断点
-
在界面随便点进去一个 发现进入调试模式 此时进入函数内部 step into
-
如果此函数实现 没有其它函数 可以直接使用python模拟生成
import execjs
nonce_func =execjs.compile("""p = function(e) {
var t = e || null;
return null == t && (t = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (function(e) {
var t = 16 * Math.random() | 0;
return ("x" === e ? t : 3 & t | 8).toString(16)
}
))),
t
}""")
print(nonce_func.call("p", ))
# 2840f71f-8c29-4df1-ab90-8d519ca25fc2
-
通过调试 看看他的算法实现
i:bK9jk5dBEtjauy6gXL7vZCPJ1fOy076H 固定的
"GET
application/json, text/plain, */*
x-ca-key:203899271
x-ca-nonce:21b07f14-581f-49e3-b1e0-30b3d7b5e028
/community-cloud/v1/homepage/community/by/tag?deviceType=PC&tagId=1"
-
传递两个参数就可得到
-
接着就是用python去模拟这些算法 得到返回值,然后赋值给headers中的内容
-
import requests import execjs from base64 import b64decode, b64encode import hmac import hashlib # 一个密钥 nonce_func = execjs.compile(""" p = function(e) { var t = e || null; return null == t && (t = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (function(e) { var t = 16 * Math.random() | 0; return ("x" === e ? t : 3 & t | 8).toString(16) } ))), t } """) def gen_sign(nonce_str,url): data = "GET\n" data +="application/json, text/plain,*/*\n" data += "\n\n\n" # data += "\n" # data += "\n" data += "x-ca-key:203899271\n" data += "x-ca-nonce:{}\n".format(nonce_str) data += url print(data) # "/community-cloud/v1/homepage/community/by/tag?deviceType=PC&tagId=3" # data = 'GET\napplication/json, text/plain,*/*\n\n\n\nx-ca-key:203899271\nx-ca-nonce' \ # f':{nonce_str}\n/community-cloud/v1/homepage/community/by/tag?deviceType=PC&tagId=3' app_secret_key = "bK9jk5dBEtjauy6gXL7vZCPJ1fOy076H" data = data.encode("utf-8") sign = b64encode(hmac.new(app_secret_key.encode('utf-8'),data,digestmod=hashlib.sha256).digest()).decode() return sign template ="""GET application/json, text/plain,*/* x-ca-key:203899271 x-ca-nonce:49d2d8b8-f978-4291-8cdc-4d6d4ef2b732 /community-cloud/v1/homepage/community/by/tag?deviceType=PC&tagId=5""" # url = "/community-cloud/v1/homepage/community/by/tag?deviceType=PC&tagId=3" nonce_str = nonce_func.call("p",) # print("随机值"+nonce_str) headers = { "accept": "application/json, text/plain,*/*", "accept-encoding": "gzip, deflate, br", "accept-language": "zh-CN,zh;q=0.9", "origin":"https://bbs.csdn.net", "referer":"https://bbs.csdn.net/forums/qing_gee?category=4", "sec-ch-ua": """Not A;Brand";v="99", "Chromium";v="96", "Google Chrome";v="96" """, "sec-ch-ua-mobile":"?0", "sec-ch-ua-platform": "Windows", "sec-fetch-dest": "empty", "sec-fetch-mode": "cors", "sec-fetch-site": "same-site", "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36", "x-ca-key": "203899271", "x-ca-nonce": nonce_str, # nonce 随机的 只使用一次 # 签名 "x-ca-signature": gen_sign(nonce_str,"/community-cloud/v1/homepage/community/by/tag?deviceType=PC&tagId=3"), # 签名 算法+密钥 "x-ca-signature-headers": "x-ca-key,x-ca-nonce", # 固定 } # print("签名"+gen_sign(nonce_str,'/community-cloud/v1/homepage/community/by/tag?deviceType=PC&tagId=3')) url = 'https://bizapi.csdn.net/community-cloud/v1/homepage/community/by/tag?deviceType=PC&tagId=3' resp = requests.get(url,headers=headers) print(resp.status_code) print(resp.text)