700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > python3抓取网易云音乐评论

python3抓取网易云音乐评论

时间:2023-09-07 05:25:33

相关推荐

python3抓取网易云音乐评论

闲来无事,爬点网易云音乐评论进行分析,准备做音乐推荐模型来用......

记得以前爬取网易云歌曲的时候,有个api,get请求就能获取得到数据,发现现在用不了,没事那就重新写呗

要爬取评论,必须先获取歌的id才可以,我是从歌手开始爬起:

流程是先获取左边的大列表:

每个大列表中获取乐队和歌手

进入每个歌手或乐队,抓取每首歌的id:

抓取id,就是这么简单,抓过网易云的朋友都知道,有了歌id抓取评论,还需要进一步,破解js,网易云的评论是可以通过一个post请求获取的json数据,那问题就来了.......哈哈

问题就在,post请求的时候携带了2个参数,解决不了这个参数,都是罔谈,这个问题已有知乎上有大神破解了,有兴趣的朋友可以自己尝试破解下,R_SO_4_4878146这个后面的数据不觉得眼熟吗,歌的id;意思就是每一首歌,你只要拼接id,携带2个参数发起post请求,就能获取到json数据

破解过程就不再叙述了,知乎上就有,直接上代码截图

同步:采用requests请求,我是采用了redis存储,方便而进行抓和取分离,实现分布式

为了防止重复请求,程序本身设计了去重,如果url请求过,就跳过,这个只是简单的实现,在爬虫架构设计中,重复请求是有条件和次数限制

同步的速度是真不敢恭维,歌手和乐队加起来有10万,每个歌手和乐队有很多歌,这要全部爬取,任务量太大,才有多进程完全没必要,采用多线程,资源消耗太大,那就采用异步咯:asyncio,aiohttp,之前我做过一个测试,采用异步请求并发1000,进行百万url请求加回调,30分钟左右完成(有部分网和电脑因素),关键资源占用比线程少太多太多,速度比线程快太多.其实不喜欢这个异步,也可以采用:from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor,这个异步包,也是很强大,之前就是用的它写爬虫:

异步:

上评论代码,此类是进行加密,只需要传给page,页码,就会返回给你数据,直接携带data请求就ok

class WangYiMusicAES:def __init__(self):# 网易音乐的固定参数self.encSecKey = "00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7"self.iv = "0102030405060708"self.pubKey = "010001"self.fourth_param = "0CoJUm6Qyw8W8jud"def create_random_char(self):# "随机16个字符"return (''.join(map(lambda xx: (hex(ord(xx))[2:]), str(os.urandom(16)))))[0:16]def aesEncrypt(self,text,key):"""params加密"""pad = 16 - len(text) % 16text = text + pad * chr(pad)encryptor = AES.new(key, AES.MODE_CBC, self.iv)encrypt_text = encryptor.encrypt(text)encrypt_text = base64.b64encode(encrypt_text)encrypt_text = str(encrypt_text, encoding="utf-8")return encrypt_textdef rsaEncrypt(self,text):"""加密encSecKey"""text = text[::-1]rs = int(codecs.encode(text.encode('utf-8'), 'hex_codec'), 16) ** int(self.pubKey, 16) % int(self.encSecKey, 16)return format(rs, 'x').zfill(256)def __call__(self, page):"返回加密结果"text = {'username': '','password': '','rememberLogin': 'true','offset': page * 20}text = json.dumps(text)secKey = self.create_random_char()# 需要加密两次,paramsencText = self.aesEncrypt(self.aesEncrypt(text,self.fourth_param),secKey)encSecKey = self.rsaEncrypt(secKey)data = {'params': encText,'encSecKey': encSecKey}return data

抓取评论的同步代码,贴出主要代码,里面的while循环,发现more为false时,代表无评论,0代表第一页评论:

def comments(self,json_data):# 抓取评论contents = jsonpath(json_data,"$..comments")[0]print("获取到{}条评论".format(len(contents)))for content in contents:nickname = jsonpath(content,"$..nickname")[0]content = jsonpath(content,"$..content")[0]print("{}:{}".format(nickname,content))# TODO 需要将评论存在哪里看自己了more = jsonpath(json_data,"$..more")if len(more)>0:return more[0]return Falsedef comment_page(self,song_id):# 评论页码url = '/weapi/v1/resource/comments/R_SO_4_{}?csrf_token='.format(song_id)page = 0more = Truewhile more:data = self.aes(page)print("{}:第{}页评论".format(song_id, page + 1))json_data = self._request(url,data)more = ments(json_data)page += 1

采用异步线程池:核心与同步区别就是这里,可以设置最大并发数,一般都是cpu*5

def run(self):song = self.redis.srandmember("music", 1000)if song:with ThreadPoolExecutor(max_workers=4) as thd:for sg in song:# song_id = list(song)[0]s = eval(sg)for id, url in s.items():print(url)# ment_page(id)thd.submit(ment_page,id)

不知道为啥,上gif图就没法显示,在此链接可以看到效果图,和源代码

/Derek520/WangYiMusic

下来就是对评论进行处理,肯定会用到中文分词,jieba或者snownlp比较喜欢用这两个,PyNLPIR这个家伙也很好用,就是会有过期问题

重点提示:挂代理,挂代理,挂代理,当你爬取到7万左右的时候,就会被封,公司的被我爬的封掉了,不过我是解决公司的问题,大家上班都挂着耳机听音乐,所以现在大家都别想在网易听音乐,哈哈哈.....这贡献也是杠杠的,

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。