最近,博主喜欢上了听歌,但是又苦于找不到好音乐,于是就打算到网易云的歌单中逛逛

本着 “用技术改变生活” 的想法,于是便想着写一个爬虫爬取网易云的歌单,并按播放量自动进行排序

这篇文章,我们就来讲讲怎样爬取网易云歌单,并将歌单按播放量进行排序,下面先上效果图

1、用 requests 爬取网易云歌单

打开 网易云音乐 歌单首页,不难发现这是一个静态网页,而且格式很有规律,爬取起来应该十分简单

按照以前的套路,很快就可以写完代码,无非就是分为下面几个部分:

(1)获取网页源代码

这里我们使用 requests 发送和接收请求,核心代码如下:

import requests
def get_page(url):
# 构造请求头部
headers = {
'USER-AGENT':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'
}
# 发送请求,获得响应
response = requests.get(url=url,headers=headers)
# 获取响应内容
html = response.text
return html

(2)解析网页源代码

解析数据部分我们使用 xpath(对于 xpath 的语法不太熟悉的朋友,可以看看博主之前的文章)

文章传送门:

核心代码如下:

from lxml import etree
# 解析网页源代码,获取数据
def parse4data(self,html):
html_elem = etree.HTML(html)
# 播放量
play_num = html_elem.xpath('//ul[@id="m-pl-container"]/li/div/div/span[@class="nb"]/text()')
# 歌单名称
song_title = html_elem.xpath('//ul[@id="m-pl-container"]/li/p[1]/a/@title')
# 歌单链接
song_href = html_elem.xpath('//ul[@id="m-pl-container"]/li/p[1]/a/@href')
song_link = ['https://music.163.com/#'+item for item in song_href]
# 用户名称
user_title = html_elem.xpath('//ul[@id="m-pl-container"]/li/p[2]/a/@title')
# 用户链接
user_href = html_elem.xpath('//ul[@id="m-pl-container"]/li/p[2]/a/@href')
user_link = ['https://music.163.com/#'+item for item in user_href]
# 将数据打包成列表,其中列表中的每一个元素是一个字典,每一个字典对应一份歌单信息
data = list(map(lambda a,b,c,d,e:{'播放量':a,'歌单名称':b,'歌单链接':c,'用户名称':d,'用户链接':e},play_num,song_title,song_link,user_title,user_link))
# 返回数据
return data # 解析网页源代码,获取下一页链接
def parse4link(self,html):
html_elem = etree.HTML(html)
# 下一页链接
href = html_elem.xpath('//div[@id="m-pl-pager"]/div[@class="u-page"]/a[@class="zbtn znxt"]/@href')
# 如果为空,则返回 None;如果不为空,则返回链接地址
if not href:
return None
else:
return 'https://music.163.com/#' + href[0]

(3)完整代码

import requests
from lxml import etree
import json
import time
import random class Netease_spider:
# 初始化数据
def __init__(self):
self.originURL = 'https://music.163.com/#/discover/playlist'
self.data = list() # 获取网页源代码
def get_page(self,url):
headers = {
'USER-AGENT':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'
}
response = requests.get(url=url,headers=headers)
html = response.text
return html # 解析网页源代码,获取数据
def parse4data(self,html):
html_elem = etree.HTML(html)
play_num = html_elem.xpath('//ul[@id="m-pl-container"]/li/div/div/span[@class="nb"]/text()')
song_title = html_elem.xpath('//ul[@id="m-pl-container"]/li/p[1]/a/@title')
song_href = html_elem.xpath('//ul[@id="m-pl-container"]/li/p[1]/a/@href')
song_link = ['https://music.163.com/#'+item for item in song_href]
user_title = html_elem.xpath('//ul[@id="m-pl-container"]/li/p[2]/a/@title')
user_href = html_elem.xpath('//ul[@id="m-pl-container"]/li/p[2]/a/@href')
user_link = ['https://music.163.com/#'+item for item in user_href]
data = list(map(lambda a,b,c,d,e:{'播放量':a,'歌单名称':b,'歌单链接':c,'用户名称':d,'用户链接':e},play_num,song_title,song_link,user_title,user_link))
return data # 解析网页源代码,获取下一页链接
def parse4link(self,html):
html_elem = etree.HTML(html)
href = html_elem.xpath('//div[@id="m-pl-pager"]/div[@class="u-page"]/a[@class="zbtn znxt"]/@href')
if not href:
return None
else:
return 'https://music.163.com/#' + href[0] # 开始爬取网页
def crawl(self):
# 爬取数据
print('爬取数据')
html = self.get_page(self.originURL)
data = self.parse4data(html)
self.data.extend(data)
link = self.parse4link(html)
while(link):
html = self.get_page(link)
data = self.parse4data(html)
self.data.extend(data)
link = self.parse4link(html)
time.sleep(random.random())
# 处理数据,按播放量进行排序
print('处理数据')
data_after_sort = sorted(self.data,key=lambda item:int(item['播放量'].replace('万','0000')),reverse=True)
# 写入文件
print('写入文件')
with open('netease.json','w',encoding='utf-8') as f:
for item in data_after_sort:
json.dump(item,f,ensure_ascii=False) if __name__ == '__main__':
spider = Netease_spider()
spider.crawl()
print('Finished')

2、用 selenium 爬取网易云歌单

然而,事情真的有这么简单吗?

当我们运行上面的代码的时候,会发现解析网页源代码部分,返回的竟然是空列表!

这是为什么呢?敲重点,敲重点,敲重点,这绝对是一个坑啊!

我们重新打开浏览器,认真观察网页的源代码

原来,我们所提取的元素被包含在 <iframe> 标签内部,这样我们是无法直接进行定位的

因为 iframe 会在原有页面中加载另外一个页面,当我们需要获取内嵌页面的元素时,需要先切换到 iframe 中

明白了原理之后,重新修改一下上面的代码

思路是利用 selenium 获取原有网页,然后使用 switch_to.frame() 方法切换到 iframe 中,最后返回内嵌网页

对 selenium 的使用以及环境配置不清楚的朋友,可以参考博主之前的文章

需要修改的地方是获取网页源代码的函数,另外也需要在初始化数据的函数中实例化 webdriver,完整代码如下:

from selenium import webdriver
from lxml import etree
import json
import time
import random class Netease_spider:
# 初始化数据(需要修改)
def __init__(self):
# 无头启动 selenium
opt = webdriver.chrome.options.Options()
opt.set_headless()
self.browser = webdriver.Chrome(chrome_options=opt)
self.originURL = 'https://music.163.com/#/discover/playlist'
self.data = list() # 获取网页源代码(需要修改)
def get_page(self,url):
self.browser.get(url)
self.browser.switch_to.frame('g_iframe')
html = self.browser.page_source
return html # 解析网页源代码,获取数据
def parse4data(self,html):
html_elem = etree.HTML(html)
play_num = html_elem.xpath('//ul[@id="m-pl-container"]/li/div/div/span[@class="nb"]/text()')
song_title = html_elem.xpath('//ul[@id="m-pl-container"]/li/p[1]/a/@title')
song_href = html_elem.xpath('//ul[@id="m-pl-container"]/li/p[1]/a/@href')
song_link = ['https://music.163.com/#'+item for item in song_href]
user_title = html_elem.xpath('//ul[@id="m-pl-container"]/li/p[2]/a/@title')
user_href = html_elem.xpath('//ul[@id="m-pl-container"]/li/p[2]/a/@href')
user_link = ['https://music.163.com/#'+item for item in user_href]
data = list(map(lambda a,b,c,d,e:{'播放量':a,'歌单名称':b,'歌单链接':c,'用户名称':d,'用户链接':e},play_num,song_title,song_link,user_title,user_link))
return data # 解析网页源代码,获取下一页链接
def parse4link(self,html):
html_elem = etree.HTML(html)
href = html_elem.xpath('//div[@id="m-pl-pager"]/div[@class="u-page"]/a[@class="zbtn znxt"]/@href')
if not href:
return None
else:
return 'https://music.163.com/#' + href[0] # 开始爬取网页
def crawl(self):
# 爬取数据
print('爬取数据')
html = self.get_page(self.originURL)
data = self.parse4data(html)
self.data.extend(data)
link = self.parse4link(html)
while(link):
html = self.get_page(link)
data = self.parse4data(html)
self.data.extend(data)
link = self.parse4link(html)
time.sleep(random.random())
# 处理数据,按播放量进行排序
print('处理数据')
data_after_sort = sorted(self.data,key=lambda item:int(item['播放量'].replace('万','0000')),reverse=True)
# 写入文件
print('写入文件')
with open('netease.json','w',encoding='utf-8') as f:
for item in data_after_sort:
json.dump(item,f,ensure_ascii=False) if __name__ == '__main__':
spider = Netease_spider()
spider.crawl()
print('Finished')

这样,得到目前网易云音乐中播放量排名前十的歌单如下(哈哈,又可以愉快的听歌啦):

  1. 2018年度最热新歌TOP100
  2. 听说你也在找好听的华语歌
  3. 精选 | 网络热歌分享
  4. 隔壁老樊的孤单
  5. 温柔暴击 | 沉溺于男友音的甜蜜乡
  6. 谁说翻唱不好听
  7. 若是心怀旧梦 就别再无疾而终
  8. KTV必点:有没有一首歌,唱着唱着就泪奔
  9. 化妆拍照BGM.
  10. 会讲故事的男声 歌词唱的太像自己

注意:本项目代码仅作学习交流使用!!!

爬虫实战(二) 用Python爬取网易云歌单的更多相关文章

  1. Python爬取网易云歌单

    目录 1. 关键点 2. 效果图 3. 源代码 1. 关键点 使用单线程爬取,未登录,爬取网易云歌单主要有三个关键点: url为https://music.163.com/discover/playl ...

  2. 用Python爬取网易云音乐热评

    用Python爬取网易云音乐热评 本文旨在记录Python爬虫实例:网易云热评下载 由于是从零开始,本文内容借鉴于各种网络资源,如有侵权请告知作者. 要看懂本文,需要具备一点点网络相关知识.不过没有关 ...

  3. Python爬取网易云音乐歌手歌曲和歌单

    仅供学习参考 Python爬取网易云音乐网易云音乐歌手歌曲和歌单,并下载到本地 很多人学习python,不知道从何学起.很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手.很多已经做 ...

  4. Python爬取网易云热歌榜所有音乐及其热评

    获取特定歌曲热评: 首先,我们打开网易云网页版,击排行榜,然后点击左侧云音乐热歌榜,如图: 关于如何抓取指定的歌曲的热评,参考这篇文章,很详细,对小白很友好: 手把手教你用Python爬取网易云40万 ...

  5. Python 爬取网易云歌手的50首热门作品

    使用 requests 爬取网易云音乐 Python 代码: import json import os import time from bs4 import BeautifulSoup impor ...

  6. python爬取网易云音乐歌单音乐

    在网易云音乐中第一页歌单的url:http://music.163.com/#/discover/playlist/ 依次第二页:http://music.163.com/#/discover/pla ...

  7. python爬取网易云音乐歌曲评论信息

    网易云音乐是广大网友喜闻乐见的音乐平台,区别于别的音乐平台的最大特点,除了“它比我还懂我的音乐喜好”.“小清新的界面设计”就是它独有的评论区了——————各种故事汇,各种金句频出.我们可以透过歌曲的评 ...

  8. 爬虫实战(三) 用Python爬取拉勾网

    目录 0.前言 1.初始化 2.爬取数据 3.保存数据 4.数据可视化 5.大功告成 0.前言 最近,博主面临着选方向的困难(唉,选择困难症患者 >﹏<),所以希望了解一下目前不同岗位的就 ...

  9. 爬虫实战(一) 用Python爬取百度百科

    最近博主遇到这样一个需求:当用户输入一个词语时,返回这个词语的解释 我的第一个想法是做一个数据库,把常用的词语和词语的解释放到数据库里面,当用户查询时直接读取数据库结果 但是自己又没有心思做这样一个数 ...

随机推荐

  1. T4 最小差异值 dvalue

    T4 最小差异值 dvalue [问题描述] P 省刚经历一场不小的地震,所有城市之间的道路都损坏掉了,所以省长想请你将城市之间的道路重修一遍. 因为很多城市之间的地基都被地震破坏导致不能修公路了,所 ...

  2. SVN工具使用技巧

    SVN打tag SVN打tag是一个很常用的功能,要谈打tag,还得从SVN官方推荐的目录结构说起.SVN官方推荐在一个版本库的根目录下先建立trunk.branches.tags这三个文件夹,其中t ...

  3. navicat导入.sql文件出错2006-MySQLserver has gone away

    方式一(验证无误): 找到mysql安装目录下的my.ini配置文件,加入以下代码: max_allowed_packet=500M wait_timeout=288000 interactive_t ...

  4. Wannafly挑战赛29A御坂美琴

    传送门 这套题很有意思2333 蠢了--首先先判总共加起来等不等于\(n\),不是的话就不行 然后dfs记录\(n\)不断分下去能分成哪些数,用map记录一下,判断是否所有数都能被分出来就是了 //m ...

  5. 使用printf和String.format格式化输出

    格式化输出 在哪些情况下使用格式化输出: 异常打印到日志中使用格式化输出有利于排查错误原因: printf格式化 示例: public class PrintfTest { public static ...

  6. Web前端汇总

    http://www.cnblogs.com/bigboyLin/p/5272902.html HTML/CSS部分   1.什么是盒子模型? 在网页中,一个元素占有空间的大小由几个部分构成,其中包括 ...

  7. 树莓派 关闭屏保 / RaspberryPi turn off ScreenSaver / RaspberryPi disable screen off

    安装xscreensaver并配置 见:https://www.raspberrypi.org/forums/viewtopic.php?t=57552

  8. 设计模式("大话设计模式"读书笔记 C#实现)

    前言:毫无疑问 ,学习一些设计模式,对我们的编程水平的提高帮助很大.写这个博客的时候自己刚开始学习设计模式,难免有错,欢迎评论指正. 我学设计模式的第一本书是“大话设计模式”. 1.为什么要学设计模式 ...

  9. Spring.Net学习笔记(6)-方法注入

    一.开发环境 系统:win10 编译器:VS2013 二.涉及程序集 Spring.Core.dll 1.3.1 Common.Logging.dll 三.开发过程 1.项目结构 2.编写Mobile ...

  10. Spring.Net学习笔记(二)-数据访问器

    Spring对ADO.NET也提供了支持,依赖与程序集Spring.Data.dll IDbProvider IDbProvider定义了数据访问提供器的基础,配置如下 <?xml versio ...