爬虫——获取网易歌词

  • 通过网易提供的API和相应的爬虫技术下载某个歌手全部歌曲的歌词
    通过接口来得到歌曲的歌词
    'http://music.163.com/api/song/lyric?' + 'id=' + str(song_id) + '&lv=-1&kv=-1&tv=-1'
  1. 获取歌曲id
    https://music.163.com/artist?id=5771
    去掉url中的‘#’后才是可以直接爬取的网页。view-source:https://music.163.com/artist?id=5771 通过网页查看源代码,可以找到歌曲的名称个对应的id

  2. 通过BeautifuSoup4或者lxml来获取网页上的内容
    歌曲的名称和id直接在a标签中,获取上层的div,div的class属性div的class属性
| <ul class="f-hide"><li><a href="[/song?id=167827](https://music.163.com/song?id=167827)">素颜</a></li><li><a href="[/song?id=167876](https://music.163.com/song?id=167876)">有何不可</a></li><li><a href="[/song?id=2016442586](https://music.163.com/song?id=2016442586)">合拍</a></li><li><a href="[/song?id=411214279](https://music.163.com/song?id=411214279)">雅俗共赏</a></li><li><a href="[/song?id=167873](https://music.163.com/song?id=167873)">多余的解释</a></li><li><a href="[/song?id=27646687](https://music.163.com/song?id=27646687)">玫瑰花的葬礼</a></li><li><a href="[/song?id=167655](https://music.163.com/song?id=167655)">幻听</a></li><li><a href="[/song?id=167882](https://music.163.com/song?id=167882)">清明雨上</a></li><li><a href="[/song?id=167691](https://music.163.com/song?id=167691)">天龙八部之宿敌</a></li><li><a href="[/song?id=167850](https://music.163.com/song?id=167850)">庐州月</a></li><li><a href="[/song?id=167870](https://music.163.com/song?id=167870)">如果当时</a></li><li><a href="[/song?id=28854182](https://music.163.com/song?id=28854182)">惊鸿一面</a></li><li><a href="[/song?id=2012390001](https://music.163.com/song?id=2012390001)">没想到</a></li><li><a href="[/song?id=167844](https://music.163.com/song?id=167844)">灰色头像</a></li><li><a href="[/song?id=167732](https://music.163.com/song?id=167732)">千百度</a></li><li><a href="[/song?id=167937](https://music.163.com/song?id=167937)">断桥残雪</a></li><li><a href="[/song?id=573384240](https://music.163.com/song?id=573384240)">如约而至</a></li><li><a href="[/song?id=167885](https://music.163.com/song?id=167885)">城府</a></li><li><a href="[/song?id=167744](https://music.163.com/song?id=167744)">半城烟沙</a></li><li><a href="[/song?id=1449406576](https://music.163.com/song?id=1449406576)">温泉</a></li><li><a href="[/song?id=412902950](https://music.163.com/song?id=412902950)">最佳歌手</a></li><li><a href="[/song?id=27646702](https://music.163.com/song?id=27646702)">我想牵着你的手</a></li><li><a href="[/song?id=28802028](https://music.163.com/song?id=28802028)">山水之间</a></li><li><a href="[/song?id=402073807](https://music.163.com/song?id=402073807)">燕归巢</a></li><li><a href="[/song?id=167929](https://music.163.com/song?id=167929)">你若成风</a></li><li><a href="[/song?id=1488737309](https://music.163.com/song?id=1488737309)">如果当时2020</a></li><li><a href="[/song?id=1913262091](https://music.163.com/song?id=1913262091)">留香</a></li><li><a href="[/song?id=1842784921](https://music.163.com/song?id=1842784921)">乌鸦</a></li><li><a href="[/song?id=167888](https://music.163.com/song?id=167888)">认错</a></li><li><a href="[/song?id=1992391270](https://music.163.com/song?id=1992391270)">曼陀山庄</a></li><li><a href="[/song?id=448144319](https://music.163.com/song?id=448144319)">今年勇</a></li><li><a href="[/song?id=554191378](https://music.163.com/song?id=554191378)">我乐意</a></li><li><a href="[/song?id=34040693](https://music.163.com/song?id=34040693)">千古</a></li><li><a href="[/song?id=167705](https://music.163.com/song?id=167705)">想象之中</a></li><li><a href="[/song?id=2016388352](https://music.163.com/song?id=2016388352)">歌曲:合拍</a></li><li><a href="[/song?id=167841](https://music.163.com/song?id=167841)">叹服</a></li><li><a href="[/song?id=415792563](https://music.163.com/song?id=415792563)">摄影艺术</a></li><li><a href="[/song?id=167712](https://music.163.com/song?id=167712)">拆东墙</a></li><li><a href="[/song?id=1978137630](https://music.163.com/song?id=1978137630)">纸上雪</a></li><li><a href="[/song?id=167679](https://music.163.com/song?id=167679)">全球变冷</a></li><li><a href="[/song?id=862099032](https://music.163.com/song?id=862099032)">明智之举</a></li><li><a href="[/song?id=1975753022](https://music.163.com/song?id=1975753022)">诗画中国</a></li><li><a href="[/song?id=167894](https://music.163.com/song?id=167894)">星座书上</a></li><li><a href="[/song?id=1397105439](https://music.163.com/song?id=1397105439)">雨幕</a></li><li><a href="[/song?id=167715](https://music.163.com/song?id=167715)">医生</a></li><li><a href="[/song?id=167717](https://music.163.com/song?id=167717)">微博控</a></li><li><a href="[/song?id=167727](https://music.163.com/song?id=167727)">降温</a></li><li><a href="[/song?id=167709](https://music.163.com/song?id=167709)">河山大好</a></li><li><a href="[/song?id=1842801466](https://music.163.com/song?id=1842801466)">冰柜</a></li><li><a href="[/song?id=569213279](https://music.163.com/song?id=569213279)">大千世界</a></li></ul> | 

获取该div下的子孙a,获取a标签的href和文本内容就可以得到song_id和song_name了。


通过xpath或者BeautifulSoup4可以找到对应的专辑名和专辑id。

  • 获取专辑里的所有歌曲id
    通过爬取对应的标签后获取歌曲的id和歌曲名。
    def get_all_song_id(self, album_ids):

        with requests.Session() as session:
            all_song_ids, all_song_names = [], []
            for album_id in album_ids:
                one_album_url = "https://music.163.com/album?id="+str(album_id)
                response = session.get(one_album_url, headers=headers)
                text = response.text
                html = etree.HTML(text)
                album_song_ids = html.xpath("//ul[@class='f-hide']/li/a/@href")
                album_song_names = html.xpath("//ul[@class='f-hide']/li/a/text()")
                album_song_ids = [ids.split('=')[-1] for ids in album_song_ids]

                all_song_ids.append(album_song_ids)
                all_song_names.append(album_song_names)

        return all_song_ids, all_song_names
  • 得到该歌手的全部歌曲名称和id
    通过python的json模块解析结果simplejson具有同样的效果

获取歌手全部歌词的关键主要流程代码,本次将爬取的结果以文件的形式保存:

 try:
                with open('G:/lyric/xs/'+str(song_name)+".txt", 'w+') as f:
                    f.write(self.parse_lyric(json_text))
                    # print(song_name)
                    # print(self.parse_lyric(json_text))
                    # print('-' * 30)
            except Exception as e:
                pass

歌词输出保存地址为G:/lyric/xs/

if __name__ == "__main__":
    sing_id_xs = '5771'            # 许嵩
    c = CrawlerLyric()
    c.get_all_song_lyric(sing_id_xs)
    #c.get_top50(sing_id_xs)
    # c.test0(sing_id_xs)
c.get_top50(sing_id_xs)

https://music.163.com/api/song/lyric?id=402073807&lv=1&kv=1&tv=-1

  • 待解决 新专辑歌词无法通过
    url_song = 'http://music.163.com/api/song/lyric?' + 'id=' + str(song_id) + '&lv=1&kv=1&tv=-1'
    找到
    <div id="lyric-content" class="bd bd-open f-brk f-ib" data-song-id="1842784921" data-third-copy="false" , copy-from>

    该页面无法找到歌词,导致结果文本保存为空
  • 解决 url返回的是json数据格式的结果,修改接口参数&lv=-1&kv=-1&tv=-1


    以歌曲id名为文档名输出

'1842784921', '1842801269', '1842801328', '1842802095', '1842801466', '1842802179', '1842801494', '1842801496', '1842801513', '1842802205',
'乌鸦', '假摔', '科幻', '万古', '冰柜', '超市', '隔代', '野人', '三尺', '庞贝',

再次以文本输出结果,w+复写得到不为空的歌词内容。


歌词输出结果

代码部分

import requests
from lxml import etree
import simplejson
import re
import operator
from functools import reduce
ua = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'
headers = {
    'User-agent': ua
}
class CrawlerLyric:
    def __init__(self):
        self.author_name = ""

    def get_url_html(self, url):
        with requests.Session() as session:
            response = session.get(url, headers=headers)
            text = response.text
            html = etree.HTML(text)
        return html

    def get_url_json(self, url):

        with requests.Session() as session:
            response = session.get(url, headers=headers)
            text = response.text
            text_json = simplejson.loads(text)
        return text_json

    def parse_song_id(self, html):

        song_ids = html.xpath("//ul[@class='f-hide']//a/@href")
        song_names = html.xpath("//ul[@class='f-hide']//a/text()")
        self.author_name = html.xpath('//title/text()')
        song_ids = [ids[9:len(ids)] for ids in song_ids]
        return self.author_name, song_ids, song_names

    def parse_lyric(self, text_json):
        try:
            lyric = text_json.get('lrc').get('lyric')
            regex = re.compile(r'\[.*\]')
            final_lyric = re.sub(regex, '', lyric).strip()
            return final_lyric
        except AttributeError as k:
            print(k)
            pass

    def get_album(self, html):
        album_ids = html.xpath("//ul[@id='m-song-module']/li/p/a/@href")
        album_names = html.xpath("//ul[@id='m-song-module']/li/p/a/text()")
        album_ids = [ids.split('=')[-1] for ids in album_ids]
        return album_ids, album_names

    def get_top50(self, sing_id):
        url_singer = 'https://music.163.com/artist?id='+str(sing_id)  #
        html_50 = self.get_url_html(url_singer)
        author_name, song_ids, song_names = self.parse_song_id(html_50)
        print(author_name, song_ids, song_names)
        for song_id, song_name in zip(song_ids, song_names):
            url_song = 'http://music.163.com/api/song/lyric?' + 'id=' + str(song_id) + '&lv=1&kv=1&tv=-1'
            json_text = self.get_url_json(url_song)
            print(song_name)
            print(self.parse_lyric(json_text))
            print('-' * 30)

    def get_all_song_id(self, album_ids):

        with requests.Session() as session:
            all_song_ids, all_song_names = [], []
            for album_id in album_ids:
                one_album_url = "https://music.163.com/album?id="+str(album_id)
                response = session.get(one_album_url, headers=headers)
                text = response.text
                html = etree.HTML(text)
                album_song_ids = html.xpath("//ul[@class='f-hide']/li/a/@href")
                album_song_names = html.xpath("//ul[@class='f-hide']/li/a/text()")
                album_song_ids = [ids.split('=')[-1] for ids in album_song_ids]

                all_song_ids.append(album_song_ids)
                all_song_names.append(album_song_names)
        return all_song_ids, all_song_names

    def get_all_song_lyric(self,singer_id):
        album_url = "https://music.163.com/artist/album?id="+str(singer_id)+"&limit=150&offset=0"
        html_album = self.get_url_html(album_url)
        album_ids, album_names = self.get_album(html_album)
        all_song_ids, all_song_names = self.get_all_song_id(album_ids)
        all_song_ids = reduce(operator.add, all_song_ids)
        all_song_names = reduce(operator.add, all_song_names)
        print(all_song_ids)
        print(all_song_names)
        for song_id, song_name in zip(all_song_ids, all_song_names):
            url_song = 'http://music.163.com/api/song/lyric?' + 'id=' + str(song_id) + '&lv=-1&kv=-1&tv=-1'
            json_text = self.get_url_json(url_song)
            print(song_name)
            try:
                with open('G:/lyric/xs/'+str(song_name)+".txt", 'w+') as f:
                    f.write(self.parse_lyric(json_text))
                    # print(song_name)
                    # print(self.parse_lyric(json_text))
                    # print('-' * 30)
            except Exception as e:
                pass
    def test0(self,singer_id):
        a=['1842784921', '1842801269', '1842801328', '1842802095', '1842801466', '1842802179', '1842801494', '1842801496', '1842801513', '1842802205']
        for song_id in a:
            url_song = 'http://music.163.com/api/song/lyric?' + 'id=' + str(song_id) + '&lv=-1&kv=-1&tv=-1'
            json_text = self.get_url_json(url_song)
            with open('G:/lyric/xs/hxzy/' + str(song_id) + ".txt", 'w+') as f:
                f.write(self.parse_lyric(json_text))
                print(json_text)


if __name__ == "__main__":
    sing_id_xs = '5771'            # 许嵩
    c = CrawlerLyric()
    c.get_all_song_lyric(sing_id_xs)
    #c.get_top50(sing_id_xs)
    # c.test0(sing_id_xs)

已知歌曲id的情况下( url = f"http://music.163.com/api/song/lyric?id={song_id}+&lv=-1&tv=-1")
import json  # 使用了json格式存储
import requests
def get_lyric(song_id):
    headers = {
        "user-agent" : "Mozilla/5.0",
        "Referer" : "http://music.163.com",
        "Host" : "music.163.com"
    }
    if not isinstance(song_id, str):
        song_id = str(song_id)
    url = f"http://music.163.com/api/song/lyric?id={song_id}+&lv=-1&tv=-1"
    r = requests.get(url, headers=headers)
    r.raise_for_status()
    r.encoding = r.apparent_encoding
    json_obj = json.loads(r.text)
    return json_obj["lrc"]["lyric"]

lyric = get_lyric(1842801496)
print(lyric)


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

推荐阅读更多精彩内容