网页抓取解密(网易云音乐只需要解密params和encSecKey就可以开始快乐的了)

优采云 发布时间: 2021-12-11 04:02

  网页抓取解密(网易云音乐只需要解密params和encSecKey就可以开始快乐的了)

  网易云音乐只需要解密params和encSecKey就可以愉快的开始爬虫了。如果你没有足够的代理IP,你还是要慢慢爬,别废话,全开就好了。

  问

  老规矩,我们来看看我们要抓取的页面:

  

  查看网络请求:

  

  从名字上可以快速定位到哪个请求是POST请求,然后看看它提交了哪些参数。表格数据如下:

  

  提交的参数,即前面提到的params和encSecKey,都是经过加密的。看一下返回内容的格式:

  

  好的,我们已经知道了基本的东西,我们可以进入下一步,找到两个解密参数。

  分析

  在调试之前,我们要找到这两个值的位置,然后搜索,先定位JS文件,然后定位代码位置。您应该知道如何搜索,您可以全局搜索params或encSecKey。如果找到多个结果,不确定是哪个文件,可以进去搜索每个点的关键参数,判断是否是目标文件。这里我直接标记一下,找到正确的文件后就可以点击进入了。

  

  进入JS文件后,同时搜索关键参数params或encSecKey:

  

  找到encSecKey的位置,拉出这几行代码分析一下:

   var bVZ8R = window.asrsea(JSON.stringify(i0x), bqN0x(["流泪", "强"]), bqN0x(Wx5C.md), bqN0x(["爱心", "女孩", "惊恐", "大笑"]));

e0x.data = j0x.cs1x({

params: bVZ8R.encText,

encSecKey: bVZ8R.encSecKey

})

  粗略的讲,params和encSecKey来自bVZ8R.encText和bVZ8R.encSecKey,bVZ8R是window.asrsea的结果,window.asrsea有四个参数,JSON.stringify(i0x), bqN0x(["streaming", "强" ] ), bqN0x(Wx5C.md), bqN0x(["Love", "Girl", "Terrified", "Laughing"],首先看下面三个参数,从它们的固定值,你可以大胆猜想这三个values也是Fixed,之所以说是fixed,看看Wx5C.md:

  

  wx5C.md是固定数组,和bqN0x(["流泪", "强"])和bqN0x(["爱心", "girl", "horrified", "laughing"] 这个结果肯定是没有变化的,如图下面,测试了一下:

  

  大概把这些参数搞清楚了,剩下的就是搞清楚window.asrsea的具体实现,还有i0x是什么样的,进入调试环节。

  调试

  window.asrsea 到达断点。我的代码位置是13133行,点击下一页粉丝列表会激活断点。在激活断点的同时,我们也可以看到 i0x 的美妙之处。在控制台输入 i0x:

  

  limit、offset、total、userId其实是已知的,csrf_token的生成可以看这里。细心的童鞋早就应该发现了:

   i0x["csrf_token"] = v0x.gP3x("__csrf"); ## csrf_token在这里产生

X0x = X0x.replace("api", "weapi");

e0x.method = "post";

delete e0x.query;

var bVZ8R = window.asrsea(JSON.stringify(i0x), bqN0x(["流泪", "强"]), bqN0x(Wx5C.md), bqN0x(["爱心", "女孩", "惊恐", "大笑"]));

  我点击进入 v0x.gP3x 函数并查看:

  

  从代码中可以看出csrf_token来自于Cookie中的__csrf:

  

  那么这个值可以在请求网页的时候从cookie中获取,继续调试window.asrsea。一路点击Next进入功能。

  

  跳进ad(d,e,f,g)函数,往下看,发现window.asrsea等于这个d函数,哦,调试一下这个d函数:

   function d(d, e, f, g) {

var h = {}

, i = a(16);

return h.encText = b(d, g),

h.encText = b(h.encText, i),

h.encSecKey = c(i, e, f),

h

}

  输入一个函数:

  

  可以看出a函数生成随机数,继续运行,进入b函数:

  

  熟悉AES加密,继续运行,进入c函数:

  

  也是大家熟悉的RSA加密,网易可真慎重,各种加密。至此,整体框架已经调试完毕,剩下的无非就是拉取JS代码。

  蟒蛇运行

  这次不光是跑了结果,还带来了爬取和入库:

  获取参数和 encSecKey

   def get_enc(self,a):

with open('..//js//wangyiyun.js', encoding='utf-8') as f:

wangyiyun = f.read()

js = execjs.compile(wangyiyun)

logid = js.call('get_pwd', a)

print(logid)

return logid

  抓

   def get_fans(self):

resp = self.get_home_page()

print(resp.cookies)

print(resp.status_code)

time.sleep(6)

limit = 20

for i in range(1,110):

print("第{}页".format(i+1))

offset = limit*i

a = {"userId": "46991111", "offset": str(offset), "total": "false", "limit": str(limit), "csrf_token": ""}

print(a)

logid = self.get_enc(a)

data = {

"params":logid["encText"],

"encSecKey":logid["encSecKey"],

}

print(data)

fans_url = "https://music.163.com/weapi/user/getfolloweds?csrf_token="

resp = self.session.post(url=fans_url,data=data,headers=self.headers)

followed = json.loads(resp.text)

followed_list = []

for foll in followed["followeds"]:

foll_dict = {}

foll_dict["short_name"] = foll.get("py","") #缩写

foll_dict["userId"] = foll.get("userId","") #用户ID

foll_dict["nickname"] = foll.get("nickname","") #昵称

foll_dict["vipType"] = foll.get("vipType","") # vip

foll_dict["eventCount"] = foll.get("eventCount","")#动态

foll_dict["vipRights"] = str(foll.get("vipRights","")) #VIP权益

foll_dict["gender"] = foll.get("gender","") #性别

foll_dict["avatarUrl"] = foll.get("avatarUrl","") #头像

foll_dict["followed"] = foll.get("followed","")

foll_dict["followeds"] = foll.get("followeds","") #粉丝

foll_dict["follows"] = foll.get("follows","") #关注

foll_dict["playlistCount"] = foll.get("playlistCount","") #歌单

foll_dict["mutual"] = foll.get("mutual","") #

foll_dict["expertTags"] = str(foll.get("expertTags",""))

foll_dict["experts"] = str(foll.get("experts",""))

print(foll_dict)

followed_list.append(foll_dict)

self.mysql.insert("music",followed_list)

tm = random.randint(10,30)

time.sleep(tm)

  这里需要注意的是,要抓取指定页面,必须先访问该页面,不能直接请求链接”,因为它根本不携带有关哪个页面的信息。

  请求特定页面

   def get_home_page(self):

url = "https://music.163.com/#/user/home?id=1737833656"

resp = self.session.get(url)

return resp

来源: 从今天开始种树

作者: 罗华

链接: http://www.happyhong.cn/ni-xiang/10034.html

本文章著作权归作者所有,任何形式的转载都请注明出处。

  表结构

   @property

def create_table_sql(self):

create_table = """

CREATE TABLE IF NOT EXISTS music (

short_name varchar(30) ,

userId varchar(100) NOT NULL,

nickname varchar(30),

vipType varchar(30) ,

eventCount varchar(200),

vipRights varchar(900),

gender varchar(900),

avatarUrl varchar(200),

followed varchar(30),

followeds varchar(30),

follows varchar(30),

playlistCount varchar(30),

mutual varchar(30),

expertTags varchar(30),

experts varchar(30),

PRIMARY KEY (userId)

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"""

return create_table

  仓储

   def insert(self,table,data_list):

if len(data_list) > 0:

data_list = [{k: v

for k, v in data.items() if v is not None}

for data in data_list]

keys = ", ".join(data_list[0].keys())

values = ", ".join(["%s"] * len(data_list[0]))

sql = """INSERT INTO {table}({keys}) VALUES ({values}) ON

DUPLICATE KEY UPDATE""".format(table=table,

keys=keys,

values=values)

update = ",".join([

" {key} = values({key})".format(key=key)

for key in data_list[0]

])

sql += update

print(sql)

self.connect()

try:

ret = self.cursor.executemany(sql, [tuple(data.values()) for data in data_list])

self.conn.commit()

except Exception as e:

self.conn.rollback()

print("Error: ", e)

traceback.print_exc()

finally:

self.close()

  过程

  

  结束

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线