爬取网易云音乐歌词

最近迷上了古风歌手等什么君的歌,比较好奇她都写了些什么,就打算写个爬虫获取下歌词。
整体想法是,先去网易云音乐网页端去分析网页,获取正确的网页源码;然后再使用bs4的BeautifulSoup去解析网页源码,获得歌曲的ID;再根据歌曲ID获取歌词,写入本地文件。
那么就开工吧

1.分析网页


打开等什么君的歌手网页,打开F12,找到歌手信息的请求,可以看到是GET请求参数为 id=30285885 ,并且有防盗链referer:https://music.163.com ,以及user-agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36,同时HTTP/1.1 的所有请求报文中必须包含一个Host头字段。

2.获取网页HTML

根据分析实现一个获取网页html的方法:

def get_html(url):
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                      'Chrome/83.0.4103.61 Safari/537.36',
        'Referer': 'http://music.163.com/',
        'Host': 'music.163.com'
    }
    try:
        # print(url)
        response = requests.get(url, headers=headers)
        one_html = response.text
        # print(one_html)
        return one_html
    except Exception as ex:
        print(ex)
        pass

使用requests的get方法,设置headers,再使用response的text属性获得网页HTML

3.分析获取的HTML

在获取到的html中有个h2的内容是歌手名称



在获取到的html中歌曲列表在一个ul中



这样想要的都有了,下面就是提取出来了,代码如下:
def get_singer_info(singer_html):
    soup = BeautifulSoup(singer_html, 'html.parser')
    singer_name = soup.find('h2', id='artist-name').get_text()
    # print(singer_name)
    links = soup.find('ul', class_='f-hide').find_all('a')
    song_ids = []
    song_names = []
    for link in links:
        song_id = link.get('href').split('=')[-1]
        song_name = link.get_text()
        # print(song_id)
        # print(song_name)
        song_ids.append(song_id)
        song_names.append(song_name)
    return singer_name, zip(song_names, song_ids)

使用BeautifulSoup的 "html.parser" 获取soup实例,然后使用find去找到名字所在的h2然后使用get_text方法得到标签内容,再找到歌曲所在ul。再获取所有a标签,再循环获取歌曲名和ID,使用ZIP把歌曲名和ID一一对应成字典。

4.获取歌词

再点击一首歌,分析获取歌词的请求:


可以看到是POST请求,而且还是用token校验的,这样对我们来说就不好搞了呀。
通过查资料明白了,可以通过网易云的Api获取。
网易云的相关Api可以参考这篇文章:收藏这些API,获取网易云音乐数据超轻松
获取歌词可以使用这个Api:

https://music.163.com/api/song/lyric?id={歌曲ID}&lv=1&kv=1&tv=-1

代码如下:

def get_lyric(song_id):
    try:
        lyric_url = 'http://music.163.com/api/song/lyric?id=' + str(song_id) + '&lv=1&kv=1&tv=-1'
        lyric_html = get_html(lyric_url)
        # print(lyric_html)
        json_dict = json.loads(lyric_html)
        # print(json_dict)
        initial_lyric = json_dict['lrc']['lyric']
        # print(initial_lyric)
        regex_rule_1 = re.compile(r'\[.*]')
        middle_lyric = re.sub(regex_rule_1, '', initial_lyric).strip()
        regex_rule_2 = re.compile(r'.*[::].*')
        final_lyric = re.sub(regex_rule_2, '', middle_lyric).strip()
        # print(final_lyric)
        return final_lyric
    except Exception as ex:
        print(ex)
        pass

请求此地址返回的是json串:



使用json.loads把json转换成字典,再获取lrc的lyric
这样获取的内容前面带有歌词出现的时间以及作词作曲等介绍,对我们来说这些都是脏数据,应该清洗掉,我这使用正则处理。

5.写入本地

获取到歌词后要做的就是把歌词写入本地了,我这里提供了两种方法,一种是分开写入,另一种是写入一个文件:

def write_dir_txt(singer_name, song_name, lyric):
    print('正在写入歌曲:{}'.format(song_name))
    if lyric is not None:
        if not os.path.exists(singer_name):
            os.makedirs(singer_name)
        with open(singer_name + '/{}.txt'.format(song_name), 'a', encoding='utf-8') as fp:
            fp.write(lyric)


def write_fil_txt(singer_name, lyric):
    print('正在写入{}歌曲...'.format(singer_name))
    if lyric is not None:
        with open('{}.txt'.format(singer_name), 'a', encoding='utf-8') as fp:
            fp.write(lyric)

注意:这里需要加上if lyric is not None的判断,因为有些歌曲是伴奏是没有歌词的,避免异常退出。

6.通过歌手ID获取

可以通过在网页上获取的歌手ID获取歌手的歌曲歌词,代码如下:

def lyric_by_singerid(singer_id):
    start_url = 'http://music.163.com/artist?id={}'.format(singer_id)
    html = get_html(start_url)
    singer_name, song_infos = get_singer_info(html)
    # print(singer_infos)
    for song_info in song_infos:
        lyric = get_lyric(song_info[1])
        write_dir_txt(singer_name, song_info[0], lyric)
        # write_fil_txt(singer_name, lyric)

7.通过歌手名字获取

通过歌手的ID获取歌词还是有些不太友好,就想着用歌手名字来获取。



看搜索的请求还是如同获取歌词的请求一样不能直接获取,所以还是使用网易云的Api:

http://music.163.com/api/search/get/web?csrf_token=hlpretag=&hlposttag=&s={搜索内容}&type=1&offset=0&total=true&limit=20

limit:返回数据条数(每页获取的数量),默认为20,可以自行更改
offset:偏移量(翻页),offset需要是limit的倍数
type:搜索的类型
type=1 单曲
type=10 专辑
type=100 歌手
type=1000 歌单
type=1002 用户
type=1004 MV
type=1006 歌词
type=1009 主播电台

我们这里搜索歌手所以type使用100

def lyric_by_singername(singer_name):
    search_url = 'http://music.163.com/api/search/get/web?csrf_token=hlpretag=&hlposttag=&' \
                 's={}&type=100&offset=0&total=true&limit=20'.format(quote(singer_name))
    search_html = get_html(search_url)
    # print(search_html)
    search_dict = json.loads(search_html)
    singer_infos = search_dict['result']['artists'][0]
    singer_id = singer_infos['id']
    # print(singer_infos)
    # print(singer_id)
    lyric_by_singerid(singer_id)

使用quote对汉字进行编码
然后解析获取到的json串获得歌手的ID
再调用上面的根据歌手ID获取歌词

8.获取结果


至此一个完整的获取网易云音乐歌手所以歌曲的歌词的爬虫就写好了。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,657评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,889评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,057评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,509评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,562评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,443评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,251评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,129评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,561评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,779评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,902评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,621评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,220评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,838评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,971评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,025评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,843评论 2 354