Python爬虫实战,30行代码轻松爬取网易云音乐热歌榜
在开始讲解思路之前,我们首先了解下网络状态码,为什么要看这个呢?以后你会回来感谢我的,嘻嘻!
一般网络状态有以下几种:
200(成功)
服务器成功处理了请求。一般来说,这意味着服务器提供所请求的页面,如果您看到此状态,您的robots.txt文件,这意味着Googlebot的检索成功。
301(永久移动)
请求的网页已永久移动到新的位置,当服务器返回此响应(作为一个GET或HEAD请求的响应),它会自动转发请求到新的位置。你应该使用这个代码让Googlebot的知道一个网页或网站已永久移动到新位置。
302(临时移动)
服务器正在响应请求,从不同位置的网页,但请求者应继续使用原来的位置,为将来的请求。此代码是在这一个GET或HEAD请求的301相似,它会自动转发到不同的位置请求,但你不应该用它来告诉Googlebot的一个网页或网站已移动,因为Googlebot会继续抓取和索引原来的位置。
400(错误请求)
服务器不理解请求的语法。
403(禁止)
服务器拒绝请求。如果你看到在Googlebot尝试抓取您的网站的有效网页(你可以看到在网络上抓取页面在谷歌webmasters诊断下)收到此状态码时,它有可能是您的服务器或主机阻止Googlebot存取。
404(未找到)
服务器找不到请求的页面。例如,服务器返回此代码,如果请求是在服务器上的页面不存在。如果没有您网站上的robots.txt文件,并在webmasters“诊断”标签的robots.txt页上看到此状态,这是正确的状态。然而,如果你有一个robots.txt文件,你会看到这种状态,那么您的robots.txt文件可能被命名为不正确或在错误的位置。它应该是在顶级域,名为robots.txt的。如果你看到的网址,Googlebot尝试抓取(诊断“标签的HTTP错误”页上)此状态, 则表示Googlebot可能从另一页(可能是旧链接或输入有误)的无效链接。
500(内部服务器错误)
服务器遇到了一个错误,并不能满足要求。
503(服务不可用)
服务器目前无法使用(因为它是重载维修或向下),一般来说,这是一个临时的状态。
重点来了,跟上思路
进入正题,我们今天爬取的是网易云音乐热歌榜的歌曲,首先我们要知道这个网址,如下图所示:
网址是这个:https://music.163.com/#/discover/toplist?id=3778678
有了网址就要对这个网址进行尝试访问,一般在进行爬虫时,为了防止反爬机制,我们需要将我们伪装成浏览器身份去进行访问网页,那么怎么进行伪装呢?就是修改我们的访问身份:
- 进入网页后按F12;
- 然后选择NetWork;
- 按F5进行页面刷新;
- 点击music.163.com;
- 选择最底下的进行复制;
看图中标记位置:
在进行数据爬取时,我们需要对网页进行分析,对网页内容需要进行解析,这时候我们需要几个必备的包:
- requests :请求网页,接受网页数据
- etree :解析网页
怎么导入了,这个很简单的哈:
import requests
from lxml import etree
这里拓展一下,要是包没有下载,我们可以使用pip install 这个命令去分别下载这两个库
pip install requests
pip install lxml
准备工作做好了,我们来进行代码访问我们的需要爬取的网址
import requests
from lxml import etree
import os
url='https://music.163.com/discover/toplist?id=3778678'
head={
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36'
down_url='https://music.163.com/song/media/outer/url?id='
respone=requests.get(url,headers=head)print(respone)
运行代码输出结果如图
上图所示结果就是访问正常了,下面我们开始来解析网页
解析网页我们一般用到的是:
html=etree.HTML(respone.text)
我们进行检查时,发现歌曲的主要信息在这里,那么格式我们可以这样写:
id_list=html.xpath('//a[contains(@href,"song?")]')
这个a标签中包含href中song?及以后的数据
print(id_list)
然后我们能获得一下信息,看图:
是不是感觉有点奇奇怪怪的,好像和我们想象中的有点不太一样,这只是我们获取到的地址,我们还需要进行进一步的提取,怎么提取,往下看
我们需要获取ID:
for id in id_list:
href=id.xpath('./@href')[0]
print(href)
我们对获取到的地址进行遍历,取到其href中的值,看下结果:
我们想要的是id后面的那串数字,那么这时候我们对其进行分割,取到我们想要的数据:
music_id=href.split('=')[1]
print(music_id)
分割后的结果如下:
有了这些数字,接下来需要干嘛,当然是获取歌曲的名字
if "$" not in music_id:
music_name=id.xpath('./text()')[0]
print(music_name)
这里解释下,为什么要使用这个if判断条件,直接看图
看到了没有,这是因为在进行id获取时,有的id是没有的,字符串里包含$,如果我们不进行处理,那么就会出现索引错误,因为里面没有这些包含$的id,所以就会报错,名字获取到了那么我们就可以对歌曲进行下载并存储。
其实每个歌曲都有自己的下载链接,那么我们采用这个链接并且配合我们获取到的id就可以进行下载啦:
down_url='https://music.163.com/song/media/outer/url?id='
拼接链接,把我们之前得到的Id数字加上去:
music_url=down_url + music_id
music=requests.get(url=music_url,headers=head)
print(music_url)
看到了吗,每个歌曲对应一个下载地址,然后我们随机复制一个下载地址,看看能不能下载,
可以下载,对不对?然后我们接下来就可以进行存储了:
if not os.path.exists(r'C:\Users\***\Desktop\music'):
os.mkdir(r'C:\Users\***\Desktop\music')
else:
with open(r'C:\Users\***\Desktop\music/%s.mp3' % music_name, "wb") as f:
print("正在下载歌曲 《%s》 ..." % music_name)
f.write(music.content)
是不是有点看不懂,不要急,我来说下这里:
- 先查找文件夹,如果不存在则进行创建;
- 创建之后打开文件夹,将获取到的文件以刚才获取到的名字进行命名,然后后缀名改为.mp3格式;
- 以二进制形式进行写入数据文件。
r'C:\Users\***\Desktop\music/%s.mp3'
这里是什么意思呢:
- r:防止位置中的有些字符被转义;
- C:\Users\***\Desktop\music这是一个用户位置信息,如果你想直接复制粘贴肯定不行,得改成你自己的用户名哈。
把思路整合,运行下我们的代码,是怎样的结果呢:
桌面是不是有了一个名字为music的文件夹
打开这个文件夹,是不是将歌曲爬取并进行了存储:
这里又有疑问了,这个歌单不是有200首歌曲吗?你这只有191首呀,原因我前面已经讲了哈,为什么加一个if判断条件。
随便点开一个mp3文件,看下文件大小,看看是不是完整版的。
到这里为止,我们就已经将歌曲爬取完毕并存储到了桌面music文件夹里面了,简不简单。
跟着一步一步的走,思路是最重要的,小白也能学会。
最后附上完整的代码:
import requests
from lxml import etree
import os #创建文件夹
url='https://music.163.com/discover/toplist?id=3778678'
head={
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36'
down_url='https://music.163.com/song/media/outer/url?id='
respone=requests.get(url,headers=head)
print(respone)
html=etree.HTML(respone.text)id_list=html.xpath('//a[contains(@href,"song?")]')
print(id_list)
for id in id_list:
href=id.xpath('./@href')[0]
print(href)
music_id=href.split('=')[1]
print(music_id)
if "$" not in music_id:
music_name=id.xpath('./text()')[0]
print(music_name)
music_url=down_url + music_id
music=requests.get(url=music_url,headers=head)
print(music_url)