python爬虫实例网易云-爬虫实战(二) 用Python爬取网易云歌单

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

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

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

python爬虫实例网易云-爬虫实战(二) 用Python爬取网易云歌单_第1张图片

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 的语法不太熟悉的朋友,可以看看博主之前的文章)

python爬虫实例网易云-爬虫实战(二) 用Python爬取网易云歌单_第2张图片

python爬虫实例网易云-爬虫实战(二) 用Python爬取网易云歌单_第3张图片

核心代码如下:

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 爬取网易云歌单

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

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

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

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

python爬虫实例网易云-爬虫实战(二) 用Python爬取网易云歌单_第4张图片

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

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

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

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

需要修改的地方是获取网页源代码的函数,另外也需要在初始化数据的函数中实例化 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')

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

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

你可能感兴趣的:(python爬虫实例网易云-爬虫实战(二) 用Python爬取网易云歌单)