网易云评论爬虫

Zss 发表于:

PS:之前写过一次网易云的爬虫,但是写的很零散,没有一点逻辑自己都理不清楚了

加上巩固一下多进程的使用方法,所以加深印象重新写一次,把思路都理清楚了

目的:爬取网易云中华语男歌手从a到z中的所有歌手的热门50单曲的精彩评论,筛选点赞数高的评论

——————————————-  网页分析   ——————————————-

一.分析获取到所有的歌手URL

首先开个百度啥的跳到网易云了,网易云音乐的首页找到了华语乐坛的

url 是 http://music.163.com/#/discover/artist/cat?id=1001&initial=65,这个url真的是坑死了坑,怎么坑能,这个和chrome抓包的url不一致

中间多了一个#号,我没有直接拿的网页上显示的地址去测试导致使用postman来测试这个接口的时候,一直不能返回正确的rsp,

正确的应该是包含这个页面中各个歌手名字及其跳转的url,估计是给重定向了,所以以后在查看url的时候一定还是得在抓取的包中去查看

直接看图吧:

使用postman来测试一下,如图,ok,这些是我们所需要的信息,千万不要加#!!!!

这个网页的信息已经找到了,所以我们要做的也就是提取这些信息了,打开chromeF12,定位,发现这个网页中歌手前十个和后面的九十个是两种不同显示方式,一条xpath是抓取前面十个,

一条是后面的九十个,把两条合并一下,这个xpath就可以抓取到这一页这一百个歌手的href了,再将每个href前面加上‘http://music.163.com’,也就构造了这一页所有的歌手的url地址了

//ul[@class="m-cvrlst m-cvrlst-5 f-cb"]//li/div/a/@href|//li[@class="sml"]/a[1]/@href

那么这一页的歌手的url都获取到了,那么a到z页的呢?

当我调成A  URL为:http://music.163.com/#/discover/artist/cat?id=1001&initial=65

当我调成B  URL为:http://music.163.com/#/discover/artist/cat?id=1001&initial=66

当我调成C  URL为:http://music.163.com/#/discover/artist/cat?id=1001&initial=67

最后的数字不一样而已,Z所以对应的是90,那么这个使用一个列表生成器生成所有字母所对应的URL就可以了,

列表生成式,感觉这个东西特别好使,据说速度也很快,和format配合简直棒

singer_url_list = ['http://music.163.com/discover/artist/cat?id=1001&initial={}'.format(str(i))for i in range(65,91)]

二.分析每个歌手的前五十首歌曲的URL

再一次给这个#号恶心了,在没有使用#号的url返回的歌手信息都在一个ul标签里面,而我一直在网页中已经加载出来的网页中去查找歌名

写除了又臭又长Xpath,虽然也可以用,但是受不了。。。这。。。 //*[@id=”song-list-pre-cache”]/div/div/table/tbody/tr/td[2]/div/div/div/span/a/@href

把#号去掉写出来的xpath似乎好多了

'//ul[@class="f-hide"]//li/a/@href'

既然我们把一个歌手的五十首热门歌曲的href爬取到了,本以为还是再构造一次url,其实不是,只需要获取到后面歌曲id的数字就好了,为什么呢?

因为在之后的爬取中,这就是所需要的数据,之后的评论使用的是这个歌曲的id,用来作为post提交到api接口,返回json数据,评论是全部存储在json数据中,而不是返回的html

所以把href给分割一下留下id号码就好了

i.strip('/song?id=')

三.分析评论的获取

点击一首歌曲,打开自带的抓包工具可以刷新一次页面抓包可以看到评论是以json格式返回的,并不是html返回的

所以我只需要构造这个接口的参数来传入不同的且正确的参数就可以获取到所有的评论了

不太清楚form data中的两个值所对应的是什么,应该是加密过的一窜字符,但是测试时发现这串东西就算每次提交一样的也可以返回正确的评论,也就没再去深究了

测试了下在网上抓包copy一个form data,每次提交数据都使用这个也可以返回

所以构造一下获取评论的url地址,是有歌曲的id所构成的

基本的样子。。。

——————————————————-   代码   ————————————————————-

#coding:utf-8#
from Singer import Singer_url
from Music import Music_url
from Comment import Comment

if __name__ == '__main__':
    singer = Singer_url()
    singer_url = singer.main()
    music = Music_url()
    music.main(singer_url)
    comment = Comment()
    comment.main(music.music_id)

#coding:utf-8#
import requests,json,time,random,os,sys
from multiprocessing.pool import ThreadPool as Pool
reload(sys)
sys.setdefaultencoding('utf-8')
class Comment(object):
    def __init__(self):
        self.headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36'}
        self.params = {'params':'PcfPB2lApkjqleQtxFTvL/qgx6/QmTCutniBcx1iIWbE4ffjVnWvXUpwVWNAkVqeFbib2tTHOSc0oJjsXva20tUGDD2d+krd2O2Luj88bk7T/USCzoZi/TcA3POe8HEZFJLeCMRmnwMlH+X497OmcexG9m2EYM/rBuYNxKt1KopMr1CZgZaoutjBGkUkhpXb',
    'encSecKey':'c7d9d4f4dc8b1c81b6f987becd0d425859e94ffb250a44ea354638819913a9afd240cabe3778ccff3e5f5846c1c3663b89d6936e52674f8e4472964789b0666665303d14dd877f1a14ef51b669a4bcd4b5de65b281813c5ee028282cae2807647db3c815f6ab5c775696e3bf3f05aad9cbf089ca6eedbbf605a64eeba8e0aec5'
    }
        self.data = {'热门评论':'','点赞数':'','歌曲id':''}

    def get_comment(self,music_id):
        time.sleep(random.uniform(0.1,1))
        url ='http://music.163.com/weapi/v1/resource/comments/R_SO_4_{}?csrf_token='.format(str(music_id))  #抓取json热门评论数据
        a = requests.post(url,data=self.params,headers=self.headers)
        b=json.loads(a.text)
        for i in b['hotComments']:
            if int(i['likedCount'])>3000:
                if i['content'] not in self.data['热门评论']:
                    self.data['热门评论'] = i['content']
                    self.data['点赞数'] = i['likedCount']
                    self.data['歌曲id'] = music_id
                    a = '\n\n'
                    file = open(r'zss.txt','a')
                    file.write('评论:  {}'.format(i['content']))
                    file.write(a)
                    file.close()

    def main(self,music_id_list):
        pool = Pool(10)
        time.sleep(random.uniform(0.1,1))
        pool.map(self.get_comment,music_id_list)
        pool.close()
#coding:utf-8#
import requests,time,random
from lxml import etree
from multiprocessing.pool import ThreadPool as Pool

class Music_url(object):
    def __init__(self):
        self.music_id = []
        self.headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) Appl\
        eWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36'}

    def get_music_id(self,singer_url):
        rsp = requests.get(url=singer_url,headers=self.headers).content
        xml = etree.HTML(rsp)
        for i in  xml.xpath('//ul[@class="f-hide"]//li/a/@href'):
            self.music_id.append(i.strip('/song?id='))
        plan = (float((len(self.music_id)))/61774)*100
        if plan >=100:plan = 100
        print('正在抓取所有的歌曲id,目前进度为:%.2f%%'%(plan))

    def main(self,singer_list):
        pool = Pool(12)
        time.sleep(random.uniform(0.1,1))
        pool.map(self.get_music_id,singer_list)
#coding:utf-8#
import requests
from lxml import etree
from multiprocessing.pool import ThreadPool as Pool

class Singer_url(object):
    def __init__(self):
        self.headers  = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) Appl\
        eWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36'}
        self.singer_url_list = []

    def get_page_url(self):
        page_url = ['http://music.163.com/discover/artist/cat?id=1001&initial={}'.format(str(i))for i in range(65,91)]
        return page_url

    def get_singer_url(self,singer_url):
        rsp = requests.get(singer_url,headers = self.headers).content
        xml = etree.HTML(rsp)
        for i in xml.xpath('//ul[@class="m-cvrlst m-cvrlst-5 f-cb"]//li/div/a/@href|//li[@class="sml"]/a[1]/@href'):
            self.singer_url_list.append('http://music.163.com{}'.format(str(i)))


    def main(self):
        pool = Pool(10)
        page_url = self.get_page_url()
        pool.map(self.get_singer_url,page_url)
        pool.close()
        pool.join()
        return self.singer_url_list