Python爬虫—爬取网易云音乐【热歌榜】歌曲的精彩评论(写入txt文本文件或者MySQL数据库)

  最近在学Python爬虫,看了Blibili爬取网易云音乐评论的视频,视频中是将一首歌的评论存入json文件,我在此代码的基础上扩展了三点:
    1.爬取热歌榜200首歌曲的精彩评论;
    2.解析评论,爬取评论的内容、时间、用户、歌曲名字等数据;**
    3.将爬取的数据存入txt文本文件或者mysql数据库中。

  下面是我的一小点分析,代码附在最后
no1
n02
no3
no4
no5


  下面是参考代码,逻辑有点乱,一些功能没有用函数封装,大家可以继续优化。

存入txt文本文件代码
# -*- coding: utf-8 -*-
# @Time    : 2021/11/10 11:21
# @Author  : MuTutuMumei
# @File    : Comment_txt.py

# 爬取每首歌的ID和名称,改变参数ID获得不同歌曲的评论
# 爬取评论信息内容的步骤:
#1.找到未加密的参数        #window.arsea(参数,xxx,xxx,xxx)
#2.想办法把参数进行加密(必须参考网易的逻辑),params=>encText,encSecKey=>encSecKey
#3.请求到网易,拿到评论信息

from Crypto.Cipher import AES
from base64 import b64encode
import requests,json
import time
import re
from lxml import etree

if __name__ == "__main__":

    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36 Edg/95.0.1020.40'
    }

    # 服务于d的
    f = "00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7"
    g = "0CoJUm6Qyw8W8jud"
    e = "010001"
    i = "oStLTrr0FaYKC6IE"  # 手动固定的,网易是随机的

    def get_encSecKey():  # 因为i是固定的,所以这也是固定的
        return "bf0c12e363f8fca9793ddab0cf6e1ea72b5d1c84c136a11147ce1b8b25da43ba385a7df0b5c97f0f9fe8904a23e318757cef5b8fe9da78ba447bfffc89a3fd3fc99db34631b69dffabe2bf6849961452f751fc71302bc3259177f70b4fdbf9ae19a5bd58b1d8422f4f0c1319f32099cbf6bf871bf59e459f05247c009f0f41f5"

    #把参数进行加密
    def get_params(data):  #默认这里收到的是字符串
        first = enc_params(data,g)
        second = enc_params(first, i)
        return second  #返回的就是pramas

    #转化成16的倍数,为下方的加密算法服务
    def to_16(data):
        pad = 16 - len(data)%16
        data += chr(pad)*pad
        return data

    #加密过程
    def enc_params(data,key):
        iv = "0102030405060708"
        data = to_16(data)
        aes = AES.new(key = key.encode("utf-8"),IV = iv.encode('utf-8'),mode = AES.MODE_CBC)
        bs = aes.encrypt(data.encode("utf-8"))   #加密,加密的长度是16的倍数
        return str(b64encode(bs),"utf-8")  #转化成字符串返回

    #处理加密过程
    '''
     function a(a) { a=16
            var d, e, b = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", c = "";
            for (d = 0; a > d; d += 1)
                e = Math.random() * b.length, #生成随机数
                e = Math.floor(e), #取整
                c += b.charAt(e); #取出b中对应位置的字符
            return c
        }
        function b(a, b) {
            var c = CryptoJS.enc.Utf8.parse(b)
              , d = CryptoJS.enc.Utf8.parse("0102030405060708")
              , e = CryptoJS.enc.Utf8.parse(a) #e是数据
              , f = CryptoJS.AES.encrypt(e, c, { #c就是加密密钥 
                iv: d, #iv是偏移量
                mode: CryptoJS.mode.CBC # 模式:CBC加密
            });
            return f.toString()
        }
        function c(a, b, c) {
            var d, e;
            return setMaxDigits(131),
            d = new RSAKeyPair(b,"",c),
            e = encryptedString(d, a)
        }
        function d(d, e, f, g) { d:数据json串  e:"010001" f:   g = "0CoJUm6Qyw8W8jud"
            var h = {}
              , i = a(16); #16位随机值
            return h.encText = b(d, g), g是密钥
            h.encText = b(h.encText, i), #返回的就是params i是密钥
            h.encSecKey = c(i, e, f), #返回的是encSecKey e和f定死,能产生变数的只能是i
            h
        }'''

    #获取歌曲ID的列表,得到的是列表,从列表中正则解析出ID,再添加到一个列表中
    url_song = 'https://music.163.com/discover/toplist?id=3778678'
    resp = requests.get(url=url_song, headers=headers).text
    tree = etree.HTML(resp)
    song = tree.xpath('//div[@data-key="song_toplist-3778678"]/ul[@class="f-hide"]/li/a/@href')
    #歌曲名称在首页获取
    song_name = tree.xpath('//div[@data-key="song_toplist-3778678"]/ul[@class="f-hide"]/li/a/text()')
    obj = re.compile(r'\d+', re.S)
    songID_list = []
    for it in song:
        song_num = obj.findall(it)
        song_num_str = ''.join(song_num)
        songID_list.append(song_num_str)
    #print(song_list)

    Comment_mum = int(input('请输入每首歌要爬取的热评数量(不能超过15首):'))
    song_mum = int(input('请输入你要爬取评论的top歌曲数量(不能超过200首):'))
    print('开始爬虫!!!')

    song_count = 0  #这里记录第几首歌曲,获取歌曲名称的时候使用
    #request请求到歌曲详情页评论的地址
    for it in songID_list[0:song_mum]:
        url_comment = "https://music.163.com/weapi/comment/resource/comments/get?csrf_token="
        #请求方式是POST
        data = {
            'csrf_token': "",
            'cursor': "-1",
            'offset': "0",
            'orderType': "1",
            'pageNo': "1",
            'pageSize': "1",   #因为精彩热评只在第一页
            'rid': "R_SO_4_" + it,   #组合获得不同歌曲的评论
            'threadId': "R_SO_4_" + it
        }
        response = requests.post(url_comment,data={
            "params":get_params(json.dumps(data)),
            "encSecKey":get_encSecKey()
        },headers=headers)
        result = json.loads(response.content.decode('utf-8'))

        #注意文件打开的方式
        fp = open('./网易云评论.txt', 'a+', encoding='utf-8')
        fp.write('hotComments' + ' ' + '\n')
        #爬取hotComments并写入txt文本文件
        #字典镶嵌列表,列表镶嵌字典,注意如何使用  https://www.cnblogs.com/jiba/p/14945833.html
        for hot in range(0,Comment_mum):
            fp.write('昵称:' + result['data']['hotComments'][hot]['user']['nickname'] + '\n')#昵称
            fp.write('歌曲名称:' + song_name[song_count] + '\n')  # 昵称
            fp.write('评论:' + result['data']['hotComments'][hot]['content'] + '\n')#评论
            # "time": 1561597817178
            # 13位的数字串是毫秒级别的时间戳,通过下边的代码转换为表转格式
            timeNum = result['data']['hotComments'][hot]['time']
            timeTemp = float(timeNum / 1000)
            tupTime = time.localtime(timeTemp)
            stadardTime = time.strftime("%Y-%m-%d %H:%M:%S", tupTime)
            fp.write('评论时间:' + stadardTime + '\n')#时间
            if result['data']['hotComments'][hot]['user']['vipRights'] == None:    #判断是否是VIP
                fp.write('vip:yes' + '\n')
            else:
                fp.write('vip:no' + '\n')
            fp.write('点赞数:' + str(result['data']['hotComments'][hot]['likedCount']) + '\n')#点赞数
            fp.write('-------------------------------------' + '\n')
        song_count = song_count + 1   #递增歌曲的名称
    fp.close()

    print('爬取完毕!!!')

  代码运行结果:
no10
no12

存入Mysql数据库代码
# -*- coding: utf-8 -*-
# @Time    : 2021/11/10 23:34
# @Author  : MuTutuMumei
# @File    : Comment_MYSQL.py

from Crypto.Cipher import AES
from base64 import b64encode
import requests,json
import time
import re
from lxml import etree
import pymysql

if __name__ == "__main__":
    #数据库参数设置
    db = pymysql.connect(host="localhost",
                         port=3306,
                         user="root",
                         passwd="123456",
                         database="wayimusic_comment",
                         charset="utf8",
                         autocommit=True) #在connect() 中加上参数autocommit并且给它赋值True这样就能自动检查是否真的入库
    cursor = db.cursor()

    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36 Edg/95.0.1020.40'
    }

    # 关于解密参数的一些数据,服务于d的
    f = "00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7"
    g = "0CoJUm6Qyw8W8jud"
    e = "010001"
    i = "oStLTrr0FaYKC6IE"  # 手动固定的,网易是随机的

    def get_encSecKey():  # 因为i是固定的,所以这也是固定的
        return "bf0c12e363f8fca9793ddab0cf6e1ea72b5d1c84c136a11147ce1b8b25da43ba385a7df0b5c97f0f9fe8904a23e318757cef5b8fe9da78ba447bfffc89a3fd3fc99db34631b69dffabe2bf6849961452f751fc71302bc3259177f70b4fdbf9ae19a5bd58b1d8422f4f0c1319f32099cbf6bf871bf59e459f05247c009f0f41f5"

    #把参数进行加密
    def get_params(data):  #默认这里收到的是字符串
        first = enc_params(data,g)
        second = enc_params(first, i)
        return second  #返回的就是pramas

    #转化成16的倍数,为下方的加密算法服务
    def to_16(data):
        pad = 16 - len(data)%16
        data += chr(pad)*pad
        return data

    #加密过程
    def enc_params(data,key):
        iv = "0102030405060708"
        data = to_16(data)
        aes = AES.new(key = key.encode("utf-8"),IV = iv.encode('utf-8'),mode = AES.MODE_CBC)
        bs = aes.encrypt(data.encode("utf-8"))   #加密,加密的长度是16的倍数
        return str(b64encode(bs),"utf-8")  #转化成字符串返回

    #获取歌曲ID的列表,得到的是列表,从列表中正则解析出ID,再添加到一个列表中
    url_song = 'https://music.163.com/discover/toplist?id=3778678'
    resp = requests.get(url=url_song, headers=headers).text
    tree = etree.HTML(resp)
    song = tree.xpath('//div[@data-key="song_toplist-3778678"]/ul[@class="f-hide"]/li/a/@href')
    #歌曲名称在首页获取
    song_name = tree.xpath('//div[@data-key="song_toplist-3778678"]/ul[@class="f-hide"]/li/a/text()')
    obj = re.compile(r'\d+', re.S)
    songID_list = []
    for it in song:
        song_num = obj.findall(it)
        song_num_str = ''.join(song_num)
        songID_list.append(song_num_str)
    #print(song_list)

    Comment_mum = int(input('请输入每首歌要爬取的热评数量(不能超过15首):'))
    song_mum = int(input('请输入你要爬取评论的top歌曲数量(不能超过200首):'))
    print('开始爬虫!!!')

    song_count1 = 0  #这里记录第几首歌曲,获取歌曲名称的时候使用
    song_count2 = 0
    comment_count = 0 #记录数据库的评论数量
    #request请求到歌曲详情页评论的地址
    for it in songID_list[0:song_mum]:
        url_comment = "https://music.163.com/weapi/comment/resource/comments/get?csrf_token="
        #请求方式是POST
        data = {
            'csrf_token': "",
            'cursor': "-1",
            'offset': "0",
            'orderType': "1",
            'pageNo': "1",
            'pageSize': "1",   #因为精彩热评只在第一页
            'rid': "R_SO_4_" + it,   #组合获得不同歌曲的评论
            'threadId': "R_SO_4_" + it
        }
        response = requests.post(url_comment,data={
            "params":get_params(json.dumps(data)),
            "encSecKey":get_encSecKey()
        },headers=headers)
        result = json.loads(response.content.decode('utf-8'))

        #将评论信息存入MYSQL数据库
        for hot in range(0,Comment_mum):
            nickname = result['data']['hotComments'][hot]['user']['nickname'] #昵称
            songName = song_name[song_count1] # 昵称
            hot_comment = result['data']['hotComments'][hot]['content'] #评论
            # "time": 1561597817178
            # 13位的数字串是毫秒级别的时间戳,通过下边的代码转换为表转格式
            timeNum = result['data']['hotComments'][hot]['time']
            timeTemp = float(timeNum / 1000)
            tupTime = time.localtime(timeTemp)
            sta_Time = time.strftime("%Y-%m-%d %H:%M:%S", tupTime)

            if result['data']['hotComments'][hot]['user']['vipRights'] == None:    #判断是否是VIP
                Vip = 0
            else:
                Vip = 1
            likedCount = result['data']['hotComments'][hot]['likedCount'] #点赞数

            sql = "insert into comment(ID,nickName,songName,comment,`datatime`,VIP,likedNum) " \
                  "values(%d,'%s','%s','%s','%s',%d,%d)"%(comment_count,nickname,songName,hot_comment,sta_Time,Vip,likedCount)
            #  "insert into '表名'(字段名) values(值)"
            try:
                cursor.execute(sql)
                db.commit()  # 都插入成功,将结果提交给数据库
                print(str(comment_count)+' 歌曲:“'+songName+'”的评论信息'+'已经存入MYSQL数据库!!!')
            except Exception as e:
                db.rollback()  # 如果提交失败,结果回退到上一次提交的结果
                print("执行MySQL时出错:%s" %e)
            comment_count = comment_count + 1
        song_count1 = song_count1 + 1  # 递增歌曲的名称
    cursor.close()
    db.close()

  Mysql数据库的表结构:
no13
  运行结果:
no14
  数据表结果:
no15

这里提供一种思路: 1. 分析网易云歌排行榜的URL,获取其API接口。 2. 使用Python爬虫访问API接口,获取歌排行榜的数据。 3. 解析数据,提取出所需的歌曲名、歌手和歌曲类型信息。 4. 连接MySQL数据库,将数据写入对应的表中。 具体实现步骤如下: 1. 分析网易云歌排行榜的URL,获取API接口。可以通过浏览器开发者工具查看网页源代码,找到对应的API接口。以当前(2021年6月)的网易云歌排行榜为例,API接口为:https://interface3.music.163.com/api/playlist/detail?id=3778678 2. 使用Python爬虫访问API接口,获取歌排行榜的数据。可以使用requests库发起GET请求,获取API接口返回的JSON格式数据。代码如下: ```python import requests url = 'https://interface3.music.163.com/api/playlist/detail?id=3778678' response = requests.get(url) data = response.json() ``` 3. 解析数据,提取出所需的歌曲名、歌手和歌曲类型信息。可以使用JSON解析库(如json)对数据进行解析,提取出所需的信息。代码如下: ```python # 定义一个空列表,用于存储歌曲信息 songs = [] # 遍历每个歌曲信息,提取出所需的信息 for track in data['result']['tracks']: name = track['name'] # 歌曲名 artists = ','.join([artist['name'] for artist in track['artists']]) # 歌手 album = track['album']['name'] # 专辑名 song_type = track['album']['type'] # 歌曲类型 # 将歌曲信息以元组的形式添加到列表中 songs.append((name, artists, album, song_type)) ``` 4. 连接MySQL数据库,将数据写入对应的表中。可以使用Python中的MySQL驱动程序(如pymysql)连接MySQL数据库,并执行相应的SQL语句将数据写入对应的表中。代码如下: ```python import pymysql # 连接MySQL数据库 conn = pymysql.connect(host='localhost', user='root', password='password', db='test', charset='utf8mb4') cursor = conn.cursor() # 定义插入数据的SQL语句 sql = "INSERT INTO hot_songs (name, artists, album, song_type) VALUES (%s, %s, %s, %s)" # 遍历歌曲信息列表,依次插入数据 for song in songs: cursor.execute(sql, song) # 提交事务并关闭数据库连接 conn.commit() cursor.close() conn.close() ``` 完整代码如下:
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

穆图图木每

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值