窦唯
1.1 API 分析
网易云音乐的评论区一直为人们所津津乐道,不少人因其优质的评论被圈粉。近日看到篇通过 SnowNLP 对爬取的云音乐评论进行情感分析的文章,便乘此研究下如何爬取云音乐评论并对其进行情感分析。
首先,通过浏览器的开发者工具观察云音乐歌曲评论的页面请求,发现评论是通过 Ajax 来传输的,其 POST 请求的 params 和 enSecKey 参数是经过加密处理的,这问题已有人给出了解决办法。但在前面提到的那篇文章里,发现了云音乐未被加密的 API(=。=):
在该 URL 中,R_SO_4_ 后的那串数字是歌曲的 id,而 limit 和 offset 分别是分页的每页记录数和偏移量。但有了这个 API 还不够,还需要获取歌曲列表的 API,否则得手动查找和输入歌曲 id。然后又十分愉快地,找到了搜索的 API:
这条 URL,s= 后面的是搜索条件,type 则对应的是搜索结果的类型(1=单曲, 10=专辑, 100=歌手, 1000=歌单, 1006=歌词, 1014=视频, 1009=主播电台, 1002=用户)。
有了这两个 API,就可以开始编写爬虫了。
Warning:
本文代码基于 Win10 + Py3.7 环境,由于为一次性需求,且对数据量估计不足(实际爬取近 16w 条),未过多考虑效率和异常处理问题,仅供参考。
1.2 爬虫
按照惯例,首先导入爬虫的相关库。
import requests
import re
import urllib
import math
import time
import random
import pandas as pd
import sqlite3
构造请求头。
my_headers = {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
'Accept-Encoding': 'gzip, deflate',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Host': 'music.163.com',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36'
}
接下来构建了 6 个用于爬虫的函数:
getJSON(url, headers): 从目标 URL 获取 JSON
countPages(total, limit): 根据记录总数计算要抓取的页数
parseSongInfo(song_list): 解析歌曲信息
getSongList(key, limit=30): 获取歌曲列表
parseComment(comments): 解析评论
getSongComment(id, limit=20): 获取歌曲评论
def getJSON(url, headers):
""" Get JSON from the destination URL
@ param url: destination url, str
@ param headers: request headers, dict
@ return json: result, json
"""
res = requests.get(url, headers=headers)
res.raise_for_status() #抛出异常
res.encoding = 'utf-8'
json = res.json()
return json
def countPages(total, limit):
""" Count pages
@ param total: total num of records, int
@ param limit: limit per page, int
@ return page: num of pages, int
"""
page = math.ceil(total/limit)
return page
def parseSongInfo(song_list):
""" Parse song info
@ param song_list: list of songs, list
@ return song_info_list: result, list
"""
song_info_list = []
for song in song_list:
song_info = []
song_info.append(song['id'])
song_info.append(song['name'])
artists_name = ''
artists = song['artists']
for artist in artists: