美文网首页我爱编程
用python爬取qq音乐中五月天的歌曲歌词

用python爬取qq音乐中五月天的歌曲歌词

作者: FancyFanyc | 来源:发表于2018-01-19 14:25 被阅读0次

    1、任务目标
    ① 爬五月天正规专辑的所有歌曲的歌词
    ② 按照年份进行情感分析,并制作词云
    2、方法
    在qq音乐上用Python进行爬虫,总共499首歌曲,其中包括演唱会和电影原声带等,需要进行数据清洗。
    3、情感语义分析

    弯路部分:
    原本是想用Beautiful Soup 来抓歌词,Beautiful Soup是python的一个库,最主要的功能是从网页抓取数据,但是后来发现此路不通。

    其一,因为qq音乐里的url是固定不变的,并不是每一页是一个单独的url。点击下一页,这个url永远在那里不变,摔!!


    image.png

    打开之后跳转到的是歌手的首页,并不是我们要的单曲页。


    2.png

    因为我是完全没有学过php,后来搜索了一圈才知道,好像这个翻页是用js写的(还是什么ajax?),就是实际上看不到的……反正我是找了好久也没找到那个对应499首歌曲的对应页面的url。

    其二,因为Beautiful Soup要依赖标签定位,而可以看到有的歌曲有mv注释,有的歌曲有热门注释,所以源码里标签并不是非常一致。

    因为是小白,这个地方也摸索了半天,后来才发现怎么也提取不到《我不愿 让你一个人》的歌名,才知道是标签xx.[1]这种写法有问题,其他歌曲都是通过xx.[1]就可以定位,而这首歌由于没有mv,所以要提取歌名的话,对应标签是xx.[0],写半天却发现此路不通。

    综上,后来分析了一下,就是由于自己对php太小白,啥也不懂,所以才浪费了这么久。还有就是,其实刚开始上手某种语言时,都会经历这种比较爬坡绕路的时期,不要怕,坚持一下,多搜索下前人经验,总会有办法的。还好我没放弃~~~

    好吧,那我们开始寻找另一条路。

    然后我不甘心,把所有能打开的url都打开了一遍,看看都是些什么鬼。

    最后让我找到了这个网址:

    https://c.y.qq.com/v8/fcg-bin/fcg_v8_singer_track_cp.fcg?g_tk=5381&jsonpCallback=MusicJsonCallbacksinger_track&loginUin=0&hostUin=0&format=jsonp&inCharset=utf8&outCharset=utf-8¬ice=0&platform=yqq&needNewCode=0&singermid=000Sp0Bz4JXH0o&order=listen&begin=0&num=30&songstatus=1

    3.png
    打开是酱紫的:
    image.png
    小小兴奋一下,仔细看里面有专辑名、歌名、歌手名,甚至还有歌词的id。
    image.png
    到这里就有思路了,可以用正则表达式把歌名、专辑名、歌词链接等关键字都筛选出来就好了呀~
    突然有种柳暗花明的感觉呢!

    但是这仅仅是499首单曲里第一页的内容,其他页呢?
    通过观察发现,在url里这里很不一样!
    https://c.y.qq.com/v8/fcg-bin/fcg_v8_singer_track_cp.fcg?g_tk=5381&jsonpCallback=MusicJsonCallbacksinger_track&loginUin=0&hostUin=0&format=jsonp&inCharset=utf8&outCharset=utf-8&notice=0&platform=yqq&needNewCode=0&singermid=000Sp0Bz4JXH0o&order=listen&begin=0&num=30&songstatus=1

    begin=0&num=30决定了每页第一首歌曲的序号及歌曲数目。
    只要做个循环就可以翻页了都爬下来了嘛~

    代码走起,先来看看最基本的,爬了第一页的歌曲:
    import re
    import pandas as pd
    import requests
    response = requests.get("https://c.y.qq.com/v8/fcg-bin/fcg_v8_singer_track_cp.fcg?g_tk=5381&jsonpCallback=MusicJsonCallbacksinger_track&loginUin=0&hostUin=0&format=jsonp&inCharset=utf8&outCharset=utf-8&notice=0&platform=yqq&needNewCode=0&singermid=000Sp0Bz4JXH0o&order=listen&begin=0&num=30&songstatus=1")
    response = response.text
    print(response)

    image.png
    songname = '"songname":"(.?)","songorig"'
    res1 = re.findall(songname,response)
    for i in res1:
    print(i)
    image.png
    同理,爬了专辑名、歌词还有一个musicid后面会用到。
    然后只要将每一页的歌曲都抓出来就好了,用一个循环增加页码即可。
    import re
    import requests
    for i in range(0,481,30):
    response = requests.get("https://c.y.qq.com/v8/fcg-bin/fcg_v8_singer_track_cp.fcg?g_tk=5381&jsonpCallback=MusicJsonCallbacksinger_track&loginUin=0&hostUin=0&format=jsonp&inCharset=utf8&outCharset=utf-8&notice=0&platform=yqq&needNewCode=0&singermid=000Sp0Bz4JXH0o&order=listen&begin="+str(i)+"&num=30&songstatus=1")
    response = response.text
    #print(response)
    songname = '"songname":"(.
    ?)","songorig"'
    album = '"albumname":"(.?)","alertid"'
    strMedia = '"strMediaMid":"(.
    ?)","stream"'
    musicid = '"songid":(.*?),"songmid"'
    res1 = re.findall(songname,response)
    res2 = re.findall(album,response)
    res3 = re.findall(strMedia,response)
    res4 = re.findall(musicid,response)
    for i in range(0,len(res1)):
    if res2 == '' or res3 == '' or res4 == '' :
    continue
    print (str(i),'\t',res1[i],'\t',res2[i],'\t',"//y.qq.com/n/yqq/song/"+res3[i]+".html",'\t',res4[i]) image.png

    这里最开始print的for循环写的是:
    for i in range(0,30)
    拉到最后报错说list index out of range
    但代码改成for i in range(0,len(res1))之后还是有问题,实际抓取出来只有409首歌,剩下的3页90首歌因为有的专辑名为空,会同样出现list index out of range的问题,只是不报错,而是直接跳过去继续打印下一页的内容了。
    后来加上if语句,将为空的元素跳过继续执行循环就好了。

    关于数组有时候很容易懵b。但还是那句话,刚开始学,在还没有那么扎实的理论功底时,这样边试错、边实战是对代码理解最深刻、学得最快的方式。然后在实操之后,可以再反过来,重新看一下基础的理论知识,巩固一下基本功,此时自己的理解力肯定跟两眼一抹黑,从头学的时候不一样了,理解会更深刻的。
    接下来是导出到excel中,然后根据歌词的链接,再去抓取歌词。最后就可以对歌词进行分析了~

    我是直接把print出来的内容copy到txt文档中,再copy到excel即可,怎么快怎么来。
    按照专辑分类,将演唱会、日语专辑等删除,按照年份对原始先做一次清理。
    最后整理完一共是124首歌。

    image.png
    然后找到歌词页,继续解析网页源码,结果发现源码里并没有直接给出歌词,shit!
    image.png
    完全陷入困境,不知从何下手。
    然后搜了好多大神的方法,让我找到了一位大神的github:
    (https://github.com/lhtlht/qqmusic)
    潜心研究了快一天啊!
    最后稍微看明白一些,原来能够有效区分不同歌曲的key有两个,一个是在url中的歌曲号musicid(之前没注意,没有爬下来,后来加上的),一个是在referer里用到的歌词号songmid(也就是我们之前抓到的strMedia)
    image.png
    image.png
    然后对大神的代码做了调整,改了好久啊,才跑成功,更改如下:
    (简书的编辑器会吞空格……看我公众号的原版吧,无奈)
    #抓取歌词函数
    import requests
    import json
    import pandas as pd
    import re
    def getLyric(musicid,songmid):
    url = 'https://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric.fcg?nobase64=1&musicid='+musicid+'&callback=jsonp1&g_tk=5381&jsonpCallback=jsonp1&loginUin=0&hostUin=0&format=jsonp&inCharset=utf8&outCharset=utf-8&notice=0&platform=yqq&needNewCode=0'
    header = {
    'user-agent':'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36',
    'referer':'https://y.qq.com/n/yqq/song/{}.html'.format(songmid)
    }
    paramters = {
    'nobase64':'1',
    'callback':'jsonp1',
    'g_tk':'5381',
    'jsonpCallback':'jsonp1',
    'loginUin':'0',
    'hostUin':'0',
    'format':'jsonp',
    'inCharset':'utf8',
    'outCharset':'utf-8',
    'notice':'0',
    'platform':'yqq',
    'needNewCode':'0'
    }
    html = requests.get(url=url,params=paramters,headers=header)
    res = json.loads(html.text.lstrip('jsonp1(').rstrip(')'))
    #由于一部分歌曲是没有上传歌词,因此没有默认为空
    lyric = json.loads(html.text.lstrip('jsonp1(').rstrip(')'))['lyric']
    #对歌词内容做稍微清洗
    dr1 = re.compile(r'&#\d.;',re.S)
    dr2 = re.compile(r'[\d+]',re.S)
    dd = dr1.sub(r'',lyric)
    dd = dr2.sub(r'\n',dd).replace('\n\n','\n')
    return dd

    带入一首《志明与春娇》的musicid和 songmid试试看:
    lyric = getLyric('4830147','001Sh6UI3dh9mE')
    print (lyric)


    image.png

    写到这里,快哭了好吗!!!

    然后把大神对于歌词格式的更改稍微改了一下,便于导出。
    从excel中导入musicid 和 songmid。

    #抓取歌词函数 getLyric 及从excel传参
    import requests
    import json
    import pandas as pd
    import re
    import openpyxl
    wb = openpyxl.load_workbook(r'D:\lyric.xlsx') #打开excel文件
    #print(wb.get_sheet_names()) #获取工作簿所有工作表名
    sheet = wb.get_sheet_by_name('清洗') #获取工作表
    #print(sheet.title) #获取sheet页的名称
    def getLyric(musicid,songmid):
    url = 'https://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric.fcg?nobase64=1&musicid='+musicid+'&callback=jsonp1&g_tk=5381&jsonpCallback=jsonp1&loginUin=0&hostUin=0&format=jsonp&inCharset=utf8&outCharset=utf-8&notice=0&platform=yqq&needNewCode=0'
    header = {
    'user-agent':'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36',
    'referer':'https://y.qq.com/n/yqq/song/{}.html'.format(songmid)
    }
    paramters = {
    'nobase64':'1',
    'callback':'jsonp1',
    'g_tk':'5381',
    'jsonpCallback':'jsonp1',
    'loginUin':'0',
    'hostUin':'0',
    'format':'jsonp',
    'inCharset':'utf8',
    'outCharset':'utf-8',
    'notice':'0',
    'platform':'yqq',
    'needNewCode':'0'
    }
    html = requests.get(url=url,params=paramters,headers=header)
    res = json.loads(html.text.lstrip('jsonp1(').rstrip(')'))
    #由于一部分歌曲是没有上传歌词,因此没有默认为空
    lyric = json.loads(html.text.lstrip('jsonp1(').rstrip(')'))['lyric']
    #对歌词内容做稍微清洗
    dr1 = re.compile(r'&#\d.;',re.S)
    dr2 = re.compile(r'[\d+]',re.S)
    dd = dr1.sub(r'',lyric)
    dd = dr2.sub(r'\n',dd).replace('\n',',')
    return dd

    lyric_list = []
    for i in range(2,126,1):
    lyric_list = getLyric(str(sheet.cell(row=i,column=5).value),str(sheet.cell(row=i,column=4).value))
    print (lyric_list,'\n')


    image.png

    同上,copy到txt再直接粘贴到excel就好了,至此,歌词爬虫总算搞定了~
    撒花~~~


    image.png
    这篇是比较理论的部分,下一篇会进行歌词的分析,结合年份看看我们主唱大人这几年的心-路-历-程,毕竟小伙子也变成发福中年大叔了嘛~哈哈

    谢谢大家!
    然后本人再次强调,小白Python选手,记性不好,单纯为个人记录之用。
    本文可分享,未经允许请勿转载!
    整理后的excel文档如果有人想用来分析,请在公众号(fancyfanyc)后台回复mayday即可获得下载链接。
    请大神们多多指教,轻拍,喵~
    江湖之大,后会有期,咱们下篇见~

    相关文章

      网友评论

        本文标题:用python爬取qq音乐中五月天的歌曲歌词

        本文链接:https://www.haomeiwen.com/subject/nwmooxtx.html