JS逆向获取网易云音乐评论并保存到mongodb数据库

JS逆向获取网易云音乐评论

前言:

这段时间,一直在研究JS逆向,今天小试牛刀一下,利用JS逆向技术获取网易云音乐评论。
在这里插入图片描述

一、分析网页

其实网易云音乐评论的api很好找到的,我们通过F12进入到浏览器(chrome)的开发者模式,因为音乐的评论是动态加载的网页,所以我们可以直接定位到network下的XHR选项,如图:

在这里插入图片描述

经过我们一个个的查找分析,定位到get?csrf_token=这个网页,这个里面就是包含评论信息的内容:
在这里插入图片描述

可以看出这个网页数据属于json格式的数据,里面包含了评论的内容,评论者的信息,评论的发布时间等:

在这里插入图片描述

既然知道了,网页的api在哪,那就好办了,直接请求这个地址就可以了,可是没有这么简单:
在这里插入图片描述

在这里插入图片描述

从图中可以看出,该api的methodpost请求,那么就需要传递post请求的data参数,可以看出该data参数是经过加密的数据,我们必须要找到如何加密这些参数的位置,从而找出如何加密的过程。

在这里插入图片描述

我们通过全局搜索params关键字,经过一个个的分析查找,我们找到了加密这些参数的JS网址文件,打开这个JS文件并格式化显示后,继续通过搜索params定位到了加密这些参数的方法的地方:

在这里插入图片描述

我们可以看出加过断点的这段JS代码就是我们加密这些参数的方法,可是这里面各种各样的中英文参杂到底是什么意思啊,经过分析我们知道这个window.asrsea这个方法里面有4个参数,但是需要我们获取到4个参数才行,经过断点分析后,我们能获取到这4个参数的具体信息:

在这里插入图片描述

这个就是这4个参数的具体信息,第一个参数是一个动态的字典,里面包含的歌曲的id,包含的评论翻页的数,包含了每页评论的条目数,包含了当前的时间戳,其余3个参数都是固定的。因为篇幅有限,具体的JS改写就不在这里过多叙述了。大致的思路就是,通过逆向改写这个JS文件,得到这两个加密的参数,然后通过构建好的参数,对这个api发送请求,获取响应数据,最后提取数据并保存到mongodb数据库。

本案例所用到的模块:
# 导入需要的包
import execjs
import requests
import time
import json
from pymongo import MongoClient

二、构建post请求的data参数

    def get_token_params(self):
        """
        构建JS传递的参数的方法
        :return:
        """
        token_param = {
            "rid": f"R_SO_4_{self.song_id}",
            "threadId": f"R_SO_4_{self.song_id}",
            "pageNo": str(self.page),
            "pageSize": "20",
            "cursor": f"{str(self.timestamp)}",
            "offset": "40",
            "orderType": "1",
            "csrf_token": ""}
        return json.dumps(token_param)

    def get_post_data(self):
        """
        逆向JS并获取post请求的data数据的方法
        :return:
        """
        token_param = self.get_token_params()
        with open('./wyy_comment.js', 'r', encoding='utf-8') as jsfile:
            js_code = execjs.compile(jsfile.read())
            result = js_code.call('get_token', f'{token_param}')
        return {
            "params": result.get('encText'),
            "encSecKey": result.get('encSecKey'),
        }

三、发送请求,获取响应数据

 def params_url(self, url):
        """
        发送请求,获取响应数据的方法
        :param url:
        :return:
        """
        data = self.get_post_data()
        response = requests.post(url, headers=self.headers, data=data)
        if response.status_code == 200:
        	return response.json()
        else:
           print('网页请求不成功')
四、提取评论的数据信息并保存到mongodb数据库
    def get_comment_data(self, json_str):
        """
        提取评论数据的方法
        :param json_str:
        :return:
        """
        for json_data in json_str.get('data').get('comments'):
            time_temp = time.localtime(json_data.get('time') // 1000)
            comment_time = time.strftime("%Y-%m-%d %H:%M:%S", time_temp)
            yield {
                # 提取评论者名字
                'comment_nickname': json_data.get('user').get('nickname'),
                # 提取评论者id
                'comment_userId': json_data.get('user').get('userId'),
                # 提取评论内容
                'comment_content': json_data.get('content'),
                # 提取评论发布时间
                'comment_time': comment_time,
                # 提取评论id
                'comment_commentId': json_data.get('commentId'),
            }

    def save_mongo(self, comment_data):
        """
        保存到mongodb数据库的方法
        :param comment_data:
        :return:
        """
        self.wyy_comment.insert_one(comment_data)

    def run(self):
        """
        实现主要逻辑思路的方法
        :return:
        """
        # 1.发送请求,获取响应数据
        json_str = self.params_url(self.API_COMMENT_URL)
        # 2.提取音乐评论数据
        comment_list = self.get_comment_data(json_str)
        for comment_data in comment_list:
            # 3.保存数据到mongodb数据库
            self.save_mongo(comment_data)
            print('保存mongo数据库成功')

五、具体实现思路

    def run(self):
        """
        实现主要逻辑思路的方法
        :return:
        """
        # 1.发送请求,获取响应数据
        json_str = self.params_url(self.API_COMMENT_URL)
        # 2.提取音乐评论数据
        comment_list = self.get_comment_data(json_str)
        for comment_data in comment_list:
            # 3.保存数据到mongodb数据库
            self.save_mongo(comment_data)
            print('保存mongo数据库成功')
效果展示:

在这里插入图片描述

由于JS代码太长了,在这里只展示JS改写后的部分代码:

在这里插入图片描述

六、完整代码

# 导入需要的包
import execjs
import requests
import time
import json
from pymongo import MongoClient


class WyyCommentSpider:
    """爬取网易云音乐评论"""
    def __init__(self,song_id,page):
        self.API_COMMENT_URL = 'https://music.163.com/weapi/comment/resource/comments/get?csrf_token='
        self.headers = {
            'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36 FS'
        }
        self.timestamp = int(time.time()) * 1000
        client = MongoClient(host='localhost', port=27017)
        self.wyy_comment = client['test']['comment']
        self.song_id = song_id
        self.page = page


    def get_token_params(self):
        """
        构建JS传递的参数的方法
        :return:
        """
        token_param = {
            "rid": f"R_SO_4_{self.song_id}",
            "threadId": f"R_SO_4_{self.song_id}",
            "pageNo": str(self.page),
            "pageSize": "20",
            "cursor": f"{str(self.timestamp)}",
            "offset": "40",
            "orderType": "1",
            "csrf_token": ""}
        return json.dumps(token_param)

    def get_post_data(self):
        """
        逆向JS并获取post请求的data数据的方法
        :return:
        """
        token_param = self.get_token_params()
        with open('./wyy_comment.js', 'r', encoding='utf-8') as jsfile:
            js_code = execjs.compile(jsfile.read())
            result = js_code.call('get_token', f'{token_param}')
        return {
            "params": result.get('encText'),
            "encSecKey": result.get('encSecKey'),
        }

    def params_url(self, url):
        """
        发送请求,获取响应数据的方法
        :param url:
        :return:
        """
        data = self.get_post_data()
        response = requests.post(url, headers=self.headers, data=data)
        assert response.status_code == 200
        return response.json()

    def get_comment_data(self, json_str):
        """
        提取评论数据的方法
        :param json_str:
        :return:
        """
        for json_data in json_str.get('data').get('comments'):
            time_temp = time.localtime(json_data.get('time') // 1000)
            comment_time = time.strftime("%Y-%m-%d %H:%M:%S", time_temp)
            yield {
                # 提取评论者名字
                'comment_nickname': json_data.get('user').get('nickname'),
                # 提取评论者id
                'comment_userId': json_data.get('user').get('userId'),
                # 提取评论内容
                'comment_content': json_data.get('content'),
                # 提取评论发布时间
                'comment_time': comment_time,
                # 提取评论id
                'comment_commentId': json_data.get('commentId'),
            }

    def save_mongo(self, comment_data):
        """
        保存到mongodb数据库的方法
        :param comment_data:
        :return:
        """
        self.wyy_comment.insert_one(comment_data)

    def run(self):
        """
        实现主要逻辑思路的方法
        :return:
        """
        # 1.发送请求,获取响应数据
        json_str = self.params_url(self.API_COMMENT_URL)
        # 2.提取音乐评论数据
        comment_list = self.get_comment_data(json_str)
        for comment_data in comment_list:
            # 3.保存数据到mongodb数据库
            self.save_mongo(comment_data)
            print('保存mongo数据库成功')


if __name__ == '__main__':
    song_id = input('请输入你需要搜索的歌曲评论的ID:')
    for page in range(1,10):
        wyy_comment_spider = WyyCommentSpider(song_id,page)
        wyy_comment_spider.run()
写在后面的话:

本案例需要了解一些JS逆向方面的知识,了解一点JavaScript基本用法,函数的调用等。另外网易云音乐爬取歌曲,也是像本案例一样,需要逆向出这两个参数,就可以提取出歌曲的真实url地址了,只不过提取歌曲比较麻烦些,但是总的关键都是需要逆向破解加密的参数。

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值