美文网首页
网易云音乐-飙升榜歌曲信息爬取

网易云音乐-飙升榜歌曲信息爬取

作者: 莫得灵魂的小白 | 来源:发表于2020-04-06 21:49 被阅读0次

    此方法仅用于学习,请勿他用,造成爬取对象服务器压力

    【目标】爬取网易云音乐榜单歌曲,返回 ['歌曲名','歌曲id','歌曲链接','榜单排名','歌曲信息(歌词,作词,编曲,歌手)','歌曲时长']

    image.png

    给出完整脚本及一些关键点的分析(个人拙见,若理解有误,请予以指正,谢谢)

    1. 引入需要用到的库,并设置请求头Header及文件存储路径

    import json 
    import re 
    import time
    import datetime
    tday=datetime.datetime.now().strftime('%Y-%m-%d')
    
    headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36'}
    
    save_path='E:/python/scarpy/screapy_wyy/wyy_toplist_'+tday+'.csv'
    

    2.定义函数:主要用于获取榜单歌曲名,歌曲链接及歌曲id(歌曲id用于后边构建歌曲链接获取歌曲信息)

    (1)右键-检查,小鼠标定位到要提取的内容下,可以看到链接及歌曲名所在的标签,可以先尝试通过request.get()获取链接的respon.text(响应文本),看看所需要的信息是否能被打印出来,如果可以,则说明信息存储在html中,可以通过BeautifulSoup进行解析

    image.png

    (2)通过遍历a标签,返回的内容不唯一,需要找到最小的父类标签,在这个问题上纠结了很久,最后在框架的源代码(非网页源代码)中搜索歌曲名,发现了父类标签 <u1> class=f-hide

    image.png
    def get_toplist():
        url='http://music.163.com/discover/toplist'
        res=requests.get(url,headers=headers)
        toplist_soup=BeautifulSoup(res.text,'html.parser')
        music_list=toplist_soup.find('ul',class_="f-hide").find_all('a')
        song_msg=[]
        count=1
        for item in music_list:
            songname=item.text
            link='http://music.163.com'+item['href']
            p1=re.compile(r'id=(.*)',re.S)#提取规则,re.S是为了让.表示除了换行符的任一字符
            songid=re.findall(p1,item['href'])[0]#findall返回一个列表,但是此次结果中只有一个字符串,所以直接取[0]
            num=count
            song_msg.append([songname,songid,link,num])
            count+=1
        return song_msg 
    

    3.定义函数:通过歌单id构造歌曲访问链接,通过requst.get进行读取解析(参考了网易云api文档构建的链接,因为原始的请求方式是post,需要从 【from data】中拼接参数,但参数通过函数进行了加密,有兴趣可以看下这位大佬的分析:https://blog.csdn.net/weixin_43999566/article/details/87697962,而我只能选择曲线救国)

    (1) post请求 + 令人绝望的参数☟

    image.png

    (2) 内容存储在json中

    image.png

    所以最终的实现方式是根据api文档+获取到的歌单id,重构访问的链接

    def get_toplist_songmsg():
        songlist=get_toplist()
        songlist_msg=[]
        listname=['歌曲名','歌曲id','歌曲链接','榜单排名','歌曲信息','歌曲时长']
        write_csv(listname)
    
        for songs in songlist:
            songid=songs[1]
            url='https://api.imjad.cn/cloudmusic/?type=lyric&id='+songid
            res=requests.get(url,headers=headers)
            res.encoding='utf-8'
            rst_dict=json.loads(res.text)#json格式字符串转成字典 
            print(rst_dict)
            try:
                lyrics=rst_dict['lrc']['lyric']
                #通过正则去掉[时间]及获取歌曲时长
                regex=re.compile(r'\[.*\]')#获取时间部分的信息
                final_lyric=re.sub(regex,'',lyrics)#把符合正则部分的内容替换成空
                final_lyric = re.sub(r'\n+', '|', final_lyric)#将歌曲歌词换行符换成“|”
                if len(re.findall(regex,lyrics))==0:
                    song_time='none'
                else:
                    song_time=re.findall(regex,lyrics)[-1]#获取歌曲信息最后一部分的时长作为歌曲整体时长
                songs.extend([final_lyric,song_time])
                songlist_msg.append(songs)
                print(songs)
                write_csv(songs)
                print('第%s首歌曲写入成功'%(str(songs[3])))
            except (TypeError,KeyError):
                print('获取不到')
            time.sleep(1.5)
        return songlist_msg
    

    4.保存爬取的结果

    注意点,由于编码问题,写入歌曲信息时会报UnicodeEncodeError,python3中使用的解决办法是对打开的文件设定编码格式为'gb18030'

    #写入文件 
    def write_csv(list_msg):
        import csv
        
        with open(save_path,'a',newline='',encoding ='gb18030') as csv_file:
            writer=csv.writer(csv_file)
            writer.writerow(list_msg)
    
    

    5.发送邮件 (参考菜鸟教程:https://www.runoob.com/python/python-email.html)

    注意点:附件名称为中文名时,需要使用add_header,否则会被编译成以.bin结尾的文件名:

    image.png
    def send_mail():
        import smtplib
        from email.mime.text import MIMEText
        from email.mime.multipart import MIMEMultipart
        from email.header import Header 
        
        #配置信息服务器+端口
        host='smtp.qq.com'
        port=25
        #获取发件人,授权码,收件人等信息
        account=input('请输入你的邮箱:')
        password=input('请输入邮箱授权码:')
        receiver=[]
        while True:
            addr=input('请输入收件箱:')
            receiver.append(addr)
            key=input('是否继续输入邮箱,按任意键继续,按"n"退出:')
            if key=='n':
                break 
    
        # 创建带附件的实例
        message=MIMEMultipart()
        message['From']=Header('莫得灵魂的小白','utf-8')
        message['To']=Header(','.join(receiver))
        text='自动获取【%s】榜单'%(str(tday))
        subject = text
        message['Subject'] = Header(subject, 'utf-8')
    
        #邮件正文内容
        message.attach(MIMEText('打开附件嗷', 'plain', 'utf-8'))
    
        # 构造附件:传送指定目录下的文件
        att1 = MIMEText(open(save_path, 'rb').read(), 'base64', 'utf-8')
        att1["Content-Type"] = 'application/octet-stream'
        # 这里的filename可以任意写,写什么名字,邮件中显示什么名字
        file_name=text+'.csv'
        att1.add_header('Content-Disposition', 'attachment', filename=file_name)
        #att1["Content-Disposition"] = 'attachment,filename=%s' % file_name.encode("utf-8")
        message.attach(att1)
    
        #发送邮件
        smtp_mail=smtplib.SMTP()
        try:
            smtp_mail.connect(host,port)
            smtp_mail.login(account,password)
            smtp_mail.sendmail(account,receiver,message.as_string())
            smtp_mail.quit()
            print('发送成功')
        except smtplib.SMTPException:
            print ("Error: 无法发送邮件")
    

    6. 调用函数执行

    #执行
    
    get_toplist_songmsg()
    send_mail()
    

    执行结果

    image.png image.png

    相关文章

      网友评论

          本文标题:网易云音乐-飙升榜歌曲信息爬取

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