[实战]爬取网抑云音乐评论
前言
月明星稀,凄神寒骨,独守窗台,
孤灯的残影烙印在远处,
遮住了我的双目,也挡住了去的路,
望着天顶的失落,原来最后的等待,叫未来可期,
正如我许多次半夜里突然转醒,久不能眠,
于是我吃饱没事干,心血来潮,拉下窗帘,
打开网抑云,写个爬虫,去感受最真实的人间~ T_T
相关知识
网页一般有两种渲染方式:
- 服务器渲染
- 客户端渲染
服务器渲染:在服务器那边直接把数据和html整合在一起,统一返回给浏览器
- 在页面源代码中能看到数据
客户端渲染:第一次请求只要一个HTML框架,第二次请求拿到数据,进行数据展示。
- 在页面源代码中,看不到数据
思路
大部分爬虫的思路基本都是一致的:
- 确认内容是否在源代码内
- 若在,则直接通过re,xpath,beautifulsoup等方式提取内容
- 若不在,则定位内容对应的URL,在其中提取内容
在页面源代码看不到数据的情况下,可以使用浏览器F12的开发者工具,利用其中给的网络模块查看整个网页请求数据的过程,并分析出数据所在的URL请求,最后写爬虫访问整个URL即可。
爬虫所用工具
Microsoft Edge 94.0.992.31
Pycharm 2019.3
Python 3.8
Python使用的相关库:
- 内置库
- beautifulsoup4 4.10.0
- lxml 4.6.3
- pycryptodome 3.10.4
- requests 2.25.1
开始实战
本次爬虫以该歌单[戏腔]戏子多秋 可怜一处情深旧 - 歌单 - 网易云音乐 (163.com)为例,进行一步一步的分析。
图1 初始界面
查看热评。
图2 热评
在网页源代码中搜索其中一条热评,发现搜索不到。
图3 搜索热评
因此,启用方案B,打开F12开发者工具,在其中的网络模块找点线索。
图4 开发者工具
刷新网页,并在筛选器中,勾选XHR,发现有多条URL请求。
图5 刷新网页
从第一条请求开始,一条一条往下分析,查看有无相关的评论内容,如第一条URL请求就没有相关评论内容。
图6 未找到评论内容
在get?csrf_token=
这条URL中,发现了评论内容
图7 发现评论内容
这时候可能就会有小伙伴好奇,csrf_token=是啥,咋每条URL都有,这个不用管它,它只有在登录之后才会有值。
这个时候我们已经定位到了评论对应的URL,此时只需要像换个URL发起请求,就能得到我们想要的评论内容。
此时URL为https://music.163.com/weapi/comment/resource/comments/get?csrf_token=
,请求的方式为POST。
图8 定位URL和确定请求方式
往下翻,会发现POST请求时所带的表单数据,参数分别为params和encSecKey。这时就有小伙伴砂岩了,哎呀我的妈,这是啥玩意,全是一堆人类无法理解的玩意。
图9 找到请求参数
不过不要慌,现在我们已经确定了,评论内容就是在该URL返回的结果里,结果是往服务器里发送一个叫params的参数和一个叫encSecKey的参数的POST数据得到的,而这两个玩意的真实内容,是被加密了的。
网易服务器收到请求后,就会将这两个参数解密,得到真实的内容,再像网页返回评论数据。
因此,我们要做的就是想办法找到未加密前的数据,以及找到加密过程,最后在我们的程序里模拟出加密过程,向服务器发送请求,得到结果。
- 找到未加密的参数
- 想办法把参数进行加密(必须参考网易的逻辑),params, encSecKey
- 请求到网易,拿到评论信息
JS逆向
JS逆向主要就是通过调试,分析出JS代码的作用,从而推导出加密过程,最后找出参数的真实含义。
目前加密的方式总结有下面几点:
- 对称加密(加密解密密钥相同):DES、DES3、AES
- 非对称加密(分公钥私钥):RSA
- 信息摘要算法/签名算法:MD5、HMAC、SHA
- 前端实际使用中MD5、AES、RSA,自定义加密函数使用频率是最高的
- 几种加密方式配合次序:采用非对称加密算法管理对称算法的密钥,然后用对称加密算法加密数据,用签名算法生成非对称加密的摘要
- DES、DES3、AES、RSA、MD5、SHA、HMAC传入的消息或者密钥都是bytes数据类型,不是bytes数据类型的需要先转换;密钥一般是8的倍数
- Python实现RSA中,在rsa库中带有生成签名和校对签名的方法
总之,加密工作主要是在前端进行,因此我们可以在浏览器中分析出加密过程。
点击菜单栏里的“发起程序”,有的浏览器叫“启动器”,就会看到发送请求的时候,一共经历的JS脚本过程,也就是请求调用的堆栈,从下往上排列,最开始执行的在下面。
图10 请求调用堆栈
我们从最上面的开始调试,点击之后,页面会跳转到其中的一行代码,也就是说程序执行完这行代码后,请求就被发出。
图11 开始调试
在这一行设置断点,然后重新刷新页面,然后查看当前变量的数据,和当前请求的URL。
图12 设置断点
发现URL不是我们目标的URL,于是点击“恢复执行脚本”,放过本次的拦截,直至URL为目标URL为止。
图13 放过拦截
图14 到达目标
在这里发现了被加密的数据,在进入该函数之后,从箭头位置往下走,参数被加密了,所以我们要去看在进入该函数之前,参数是否被加密。
图15 发现加密数据
于是从调用堆栈这里,一步一步点击往下找。
图16 往下寻找
观察参数,直至发现加密前的参数,从而找出的相应的加密过程。
图17 加密前
图18 加密后
因此,判断在这段函数期间,参数被加密了。
图19 找到加密过程
范围已经被确定,因此可以从该函数的第一行开始设置断点,并点击“单步跳过下一个函数调用”,去观察参数究竟在哪一行代码中被加密了。
图20 断点调试
经过调试,发现加密过程是在这一行代码中,加密函数为window.asrsea
。
图21 发现加密函数
此时,我们将该函数名拿去搜索,会发现只有两个地方出现该函数,一个是刚才的地方,另一个如图所示,这一行window.asrsea = d
代码的意思就是,将一个叫d的函数赋给了window.asrsea,也就是说d函数和window.asrsea函数是同一个函数。
图22 搜索加密函数
接下来的加密过程就与下面出现的函数有关。
图23 相关的加密函数
JS解密
到目前为止,我们已经进一步缩小了加密过程的范围,并确定了加密与上四个函数有关,我们采用逆推的思路,因此,我们先从d
函数来开始分析:
d
函数其实就是window.asrsea
函数,其中window.asrsea
所需的参数如下:
window.asrsea = d
//。。。
var bKf6Z = window.asrsea(JSON.stringify(i8a), bva3x(["流泪", "强"]), bva3x(Tu8m.md), bva3x(["爱心", "女孩", "惊恐", "大笑"]));
分别是:
- i8a
- bva3x([“流泪”, “强”])
- bva3x(Tu8m.md)
- bva3x([“爱心”, “女孩”, “惊恐”, “大笑”])
i8a其实就是加密前的参数data,也就是:
{cursor: -1offset: 0orderType: 1pageNo: 1pageSize: 20rid: "A_PL_0_2217610700"threadId: "A_PL_0_2217610700"
}
bva3x是一个新出现的函数,看着参数的值也很奇怪,但是不用管它,直接丢进控制台里面运行得到结果,可以多运行几遍,确认结果是否是随机的。如果运行显示函数未定义,需要将调用堆栈切换到加密后的那个堆栈中。
图24 新函数的运行结果
因此,现在能够确定d
函数其中的三个参数是固定的,会变的只有data数据,我们继续分析:
var h = {}
创建一个 空对象,暂时没什么用,
i = a(16)
调用a函数,并将返回值赋给i
那么a
函数是干嘛的呢?我们继续分析:
function a(a) { // 参数传为16var d, e, b = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", c = "";for (d = 0; a > d; d += 1) // 循环16次e = Math.random() * b.length, // 随机数 e = Math.floor(e), // 取整c += b.charAt(e); // 取在字符串b中的XXX位置return c // 产生16位随机的字母或数字}
a
函数的过程也没什么好说的,就是产生一个16位的随机数,此时我们将a
函数丢进控制台里面运行或者设置断点查看变量值,就能得到结果,虽然是个随机数,但是我们可以将这个结果固定住,不管这个值怎么变化,我们固定住的这个结果永远都是正确的。
图25 i的值
回到d
函数,我们接着往下分析:
function d(d, e, f, g) { // d:数据,e:010001,f:很长的定值,e:定值var h = {} // 空对象, i = a(16); // i就是一个16位的随机值,我们可以把i设置成定值return h.encText = b(d, g),h.encText = b(h.encText, i),h.encSecKey = c(i, e, f),h
}
看着上面的返回值长得那么奇怪,其实就是:
function d(d, e, f, g) { // d:数据,e:010001,f:很长的定值,e:定值var h = {} // 空对象, i = a(16); // i就是一个16位的随机值,我们可以把i设置成定值h.encText = b(d, g), h.encText = b(h.encText, i), h.encSecKey = c(i, e, f), return h
}
我们先从h.encSecKey = c(i, e, f)
这里开始分析,因为这部分比较简单,
i
我们已经固定了,现在是个定值,e
也是定值,f
也是定值,同时,c
函数内没有产生随机数的函数,所以说c
函数的返回值也是个定值,c
函数是怎么运行的我们就不用管它了。将c
函数丢进控制台里面运行或者设置断点,即可查看变量值
接下来分析h.encText = b(d, g)
,其中d
就是我们的data数据,g
是个定值,因此返回的结果与d
有关,因为我们请求的数据是不一样的例如获取不同歌单的评论
b
函数是个加密数据的函数,其中涉及到了AES加密:
高级加密标准(AES,Advanced Encryption Standard)为最常见的对称加密算法(微信小程序加密传输就是用这个加密算法的)。
对称加密算法也就是加密和解密用相同的密钥。
对称加密算法:
加密和解密用到的密钥是相同的,这种加密方式加密速度非常快,适合经常发送数据的场合。缺点是密钥的传输比较麻烦。
非对称加密算法:
加密和解密用的密钥是不同的,这种加密方式是用数学上的难解问题构造的,通常加密解密的速度比较慢,适合偶尔发送数据的场合。优点是密钥传输方便。常见的非对称加密算法为RSA、ECC和EIGamal。
实际中,一般是通过RSA加密AES的密钥,传输到接收方,接收方解密得到AES密钥,然后发送方和接收方用AES密钥来通信。
我们只有分析出该函数的执行才能,才能使用python对爬虫所请求的参数进行加密
其中出现最多的CryptoJS.enc.Utf8.parse()
的作用是从UTF8编码解析出原始字符串
从这一行代码能看出,f = CryptoJS.AES.encrypt(e, c, { iv: d, mode: CryptoJS.mode.CBC })
,这是执行AES加密的函数,e
也就是a
是加密的数据,c
也就是b
是加密的密钥,iv
也就是d
是加密所需的偏移量,加密的模式为CBC
function b(a, b) { // a是要加密的内容var c = CryptoJS.enc.Utf8.parse(b) // b是密钥, d = CryptoJS.enc.Utf8.parse("0102030405060708"), e = CryptoJS.enc.Utf8.parse(a) // e是数据, f = CryptoJS.AES.encrypt(e, c, { // c是加密的密钥iv: d, // 偏移量mode: CryptoJS.mode.CBC // 加密模式:CBC});return f.toString()}
d
函数最后是返回了两个值,分别是encText
和encSecKey
,其实分别对应了data参数里的params
和encSecKey
图26 data参数
至此,我们基本就分析得出了参数加密的整个过程,现在梳理一下:
- 通过网络模块,定位到URL,发现参数加密
- 通过调试JS代码,定位到加密过程,锁定加密函数
- 逐步分析代码作用,得到加密原理
PS.可能不同时候进行分析,看到的变量名不一样,但是过程和原理是一样的
Python实现
还原加密过程
我们使用python来还原参数的加密过程:
先将所固定的值列出来:
# 服务于d函数的
e = '010001'
f = '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7'
g = '0CoJUm6Qyw8W8jud'
i = 'nYXLafpydDFlqRNh' # 手动固定,人家的是随机的
首先,还原d
函数中的encSecKey
变量,该变量实际也是个定值
# 由于i,e,f固定,那么c函数结果固定
def get_encSecKey(): return "8f2960e5fa10ec2f643aa6a9f76f6b40f85dc4e0f7cfadc70370991ffa3234b08987d5f684619660448a8f0880dbc34436011b1f5b1091d1de4b448acc8ae259d71f84573229ade8ed9894ea55ebbfb6cd1a92e827c93ae14f5af34bdd994c004286dfa3fee40c12cf1d9da5cc3a33313a9f6b19cb10f1eb28d45d9cb8933590"
其次,还原d
函数中的encText
变量,该变量实际就是进行两次加密得到的
# 把参数进行加密
# 其中g, i是定值
def get_params(data): # data为json字符串first = enc_params(data, g)second = enc_params(first, i)return second
接下来,我们还原b
函数的加密过程,由于AES加密的规则,加密的明文的长度必须为16的倍数,且不满足则需补充至16位,补充的内容为char(所差的长度)
如:1234567890
则补充6位的char(6)
,
即1234567890char(6)char(6)char(6)char(6)char(6)char(6)
加密过程如下,注意字节和字符串的转换:
# 加密需要用到两个库
from Crypto.Cipher import AES
from base64 import b64encode# 转化成16的倍数,为下方加密算法服务
def to_16(data):pad = 16 - len(data) % 16data += chr(pad) * padreturn data# 加密过程
def enc_params(data, key): iv = '0102030405060708'data = to_16(data)# 创建加密器aes = AES.new(key=key.encode('utf-8'), iv=iv.encode('utf-8'),mode=AES.MODE_CBC) # 加密,加密的内容的长度必须是16的倍数,AES加密的逻辑bs = aes.encrypt(data.encode('utf-8')) # bs的结果不能直接转换成字节,需要先转换成base64return str(b64encode(bs), 'utf-8') # 转换成字符串返回
PyCryptodome是python一个强大的加密算法库,可以实现常见的单向加密、对称加密、非对称加密和流加密算法。直接pip安装即可:
pip install pycryptodome
爬虫实现
搞了半天,终于到了真正爬虫的环节!淦
经过了上述的解密过程,接下来的爬虫其实就很容易了,只需提交参数,找到评论内容输出即可
data
中的参数有很多,其中
pageNo:当前评论的页数
pageSize:一页评论的数量
rid和threadId:歌单的ID或一首歌的ID
歌单的ID格式一般为
A_PL_0_XXXXXXXXXX
一首歌的ID格式一般为
R_SO_4_XXXXXXXXXX
不仅是歌单的评论,一首歌的评论也能爬取哦
data = {"csrf_token": "","cursor": "-1","offset": "0","orderType": "1","pageNo": "1","pageSize": "20","rid": "A_PL_0_2022186054","threadId": "A_PL_0_2022186054"
}
接下来就以某一歌单为例,爬取评论
import requests
import json
# 发送请求得到评论
resp = requests.post(url,data={'params':get_params(json.dumps(data)),'encSecKey':get_encSecKey()
})
resp_data = json.loads(resp.text)['data']
# 获取热评
hotComments = resp_data['hotComments']if hotComments == None:print('数据为空')exit()lengh = len(hotComments)# 保存用户名和评论
user_name = []
comments = []# 获取用户名
for i in range(lengh):user_name.append(hotComments[i]['user']['nickname'])
# 获取评论内容
for i in range(lengh):comments.append(hotComments[i]['content'])# print(user_name)
# print(comments)
# 输出评论
for i in range(lengh):print(user_name[i], '说:', comments[i])print('-'*20)
脚本的爬取的评论和在浏览器看到的评论,是一致的:
图27 爬取评论
图28 评论
爬取网抑云的评论,成功实现!史前巨感动
扩展
网抑云的评论爬取到了,也可以爬爬歌单名和简介这些
from bs4 import BeautifulSoup
# 获取歌单名和介绍
url_music = 'https://music.163.com/playlist?id=2022186054'
resp = requests.get(url_music)
html = resp.text
soup = BeautifulSoup(html,'lxml')
# 获取歌单标题
title = soup.title.string
# 获取歌单介绍
introduce = soup.find(name='p',attrs={'id':'album-desc-more'})
print(title)
print(introduce.text)
结果如下:
图29 歌单简介
可扩展的方面还有很多,例如:
- 爬取歌词
- 爬取歌单里的歌名
- 爬取首页的歌单或单曲的链接,使用多线程技术对不同的歌单评论进行爬取
- 。。。
由于写文章 + 贴图史前巨尼玛麻烦,这里就不继续展示了,有兴趣的小伙伴可以自己动手试试哦,网易的网站分析过程基本都是这样。
当然,去爬爬B站啥的也可以
总结
本次的爬虫之旅到此结束,爬虫本身不难,由于网站的反爬虫机制,难就难在要分析各种参数的加密过程,不管怎么说,本次爬虫的收获还是挺大的(光是在这吹水就吹了很久)
完整代码
分析过程 + 爬虫完整代码,如下:
# 1. 找到未加密的参数
# 2. 想办法把参数进行加密(必须参考网易的逻辑) ,params => encText, encSecKey => encSecKey
# 3. 请求到网易,拿到评论信息# pip install pycryptodome
from Crypto.Cipher import AES
from base64 import b64encode
from bs4 import BeautifulSoup
import requests
import jsonurl = "https://music.163.com/weapi/comment/resource/comments/get"
# 请求方式是POST
data = {"csrf_token": "","cursor": "-1","offset": "0","orderType": "1","pageNo": "1","pageSize": "20","rid": "A_PL_0_2217610700","threadId": "A_PL_0_2217610700"
}# 单曲歌 R_SO_4_1313118277
# 歌单 "A_PL_0_2022186054"# 服务于d函数的
e = '010001'
f = '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7'
g = '0CoJUm6Qyw8W8jud'
i = 'nYXLafpydDFlqRNh' # 手动固定,人家的是随机的def get_encSecKey(): # 由于i,e,f固定,那么c函数结果固定return "8f2960e5fa10ec2f643aa6a9f76f6b40f85dc4e0f7cfadc70370991ffa3234b08987d5f684619660448a8f0880dbc34436011b1f5b1091d1de4b448acc8ae259d71f84573229ade8ed9894ea55ebbfb6cd1a92e827c93ae14f5af34bdd994c004286dfa3fee40c12cf1d9da5cc3a33313a9f6b19cb10f1eb28d45d9cb8933590"# 转化成16的倍数,为下方加密算法服务
def to_16(data):pad = 16 - len(data) % 16data += chr(pad) * padreturn datadef enc_params(data, key): # 加密过程iv = '0102030405060708'data = to_16(data)aes = AES.new(key=key.encode('utf-8'), iv=iv.encode('utf-8'),mode=AES.MODE_CBC) # 创建加密器bs = aes.encrypt(data.encode('utf-8')) # 加密,加密的内容的长度必须是16的倍数,AES加密的逻辑# bs的结果不能直接转换成字节,需要先转换成base64return str(b64encode(bs), 'utf-8') # 转换成字符串返回# 把参数进行加密
def get_params(data): # data为json字符串first = enc_params(data, g)second = enc_params(first, i)return second# 处理加密过程
'''
function a(a) { # 参数传为16var d, e, b = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", c = "";for (d = 0; a > d; d += 1) # 循环16次e = Math.random() * b.length, # 随机数 e = Math.floor(e), # 取整c += b.charAt(e); # 取在字符串b中的XXX位置return c # 产生16位随机的字母或数字}function b(a, b) { # a是要加密的内容var c = CryptoJS.enc.Utf8.parse(b) # b是密钥, d = CryptoJS.enc.Utf8.parse("0102030405060708"), e = CryptoJS.enc.Utf8.parse(a) # e是数据, f = CryptoJS.AES.encrypt(e, c, { # c是加密的密钥iv: d, # 偏移量mode: CryptoJS.mode.CBC # 加密模式:CBC});return f.toString()}function c(a, b, c) {var d, e;return setMaxDigits(131),d = new RSAKeyPair(b,"",c),e = encryptedString(d, a)}function d(d, e, f, g) { d:数据,e:010001,f:很长的定值,e:定值var h = {} # 空对象, i = a(16); # i就是一个16位的随机值,我们可以把i设置成定值return h.encText = b(d, g),h.encText = b(h.encText, i),h.encSecKey = c(i, e, f),h}上面那部分相当于h.encText = b(d, g), # g是密钥h.encText = b(h.encText, i), # 得到的就是params i也是密钥h.encSecKey = c(i, e, f), # 得到的就是encSecKey,e和f是定死的,如果此时把i固定,c函数返回的值也是固定的return hwindow.asrsea = d.....var bKf6Z = window.asrsea(JSON.stringify(i8a), bva3x(["流泪", "强"]), bva3x(Tu8m.md), bva3x(["爱心", "女孩", "惊恐", "大笑"]));bva3x(["流泪", "强"])运算结果为:010001bva3x(Tu8m.md)运算结果为:00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7bva3x(["爱心", "女孩", "惊恐", "大笑"])运算结果为:0CoJUm6Qyw8W8jud'''# 发送请求得到评论
resp = requests.post(url,data={'params':get_params(json.dumps(data)),'encSecKey':get_encSecKey()
})
resp_data = json.loads(resp.text)['data']
# 获取热评
hotComments = resp_data['hotComments']if hotComments == None:print('数据为空')exit()lengh = len(hotComments)# 保存用户名和评论
user_name = []
comments = []# 获取用户名
for i in range(lengh):user_name.append(hotComments[i]['user']['nickname'])
# 获取评论内容
for i in range(lengh):comments.append(hotComments[i]['content'])for i in range(lengh):print(user_name[i], '说:', comments[i])print('-'*20)# 获取歌单名和介绍
url_music = 'https://music.163.com/playlist?id=2022186054'
url_music = 'https://music.163.com/playlist?id=2217610700'
resp = requests.get(url_music)
html = resp.text
soup = BeautifulSoup(html,'lxml')
# 获取歌单标题
title = soup.title.string
# 获取歌单介绍
introduce = soup.find(name='p',attrs={'id':'album-desc-more'})
print(title)
print(introduce.text)
参考文献
https://blog.csdn.net/weixin_41173374/article/details/103474801
https://blog.csdn.net/qq_28205153/article/details/55798628
https://blog.csdn.net/weixin_30347335/article/details/99123821
。。。。。。
[实战]爬取网抑云音乐评论相关推荐
- python爬取网抑云音乐评论
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 一.python爬取网抑云音乐评论 前言 提示:这里可以添加本文要记录的大概内容: python爬取网抑云音乐评论 提 ...
- 【爬虫系列】用Python爬取网抑云(music)评论
目录 前言 分析 代码过程 成果展示 完整代码 前言 本案例难度一般,需要逆向两个加密参数,对于初学者还是比较麻烦的,希望通过我的分析过程,能帮助大家快速理解! 分析 首先找到评论数据接口,看看有没有 ...
- [爬虫]网抑云音乐评论
[爬虫]网抑云音乐评论 前言 自打开网抑云之后,我久久无法忘记,是它才能带给我内心世界的波涛汹涌.我左手拿起它,右手放下它,一日复一日,我终于完成了<The Spider Of Music-16 ...
- 【爬虫+多线程+MySQL】网抑云音乐评论爬取
提示:本文仅作学习交流使用,下面案例可供参考. 文章目录 前言 一.爬取所有华语男歌手姓名及ID 1.网页分析 2.代码实现 3.部分运行结果 附:url详解 二.爬取所有华语男歌手专辑ID 1.网页 ...
- 深夜爬虫, 我很抱歉 , 附爬取“网抑云”最详细的爬虫教程!
最近真的是被 网抑云 这个梗刷爆了,到处都是, 生而为人,我很抱歉,哈哈哈, 碰巧最近学习了一波微信公众号的爬取方式,想试一试, 特地在此献丑了.我是沙漏, 不定期更新爬虫教学, 其余时间学java和 ...
- python爬取网抑云歌曲下载
爬取对象 下载新歌榜中歌曲,在.py文件创建一个music文件 全部代码如下: # encoding=utf8 import requests from bs4 import BeautifulSou ...
- 给自己的博客园添加网抑云音乐播放器
1. 申请权限 首先给自己的博客园设置,申请js权限,这个教程可以去搜. 2. 打开网页版网抑云音乐 点击一首你喜欢的歌进入 , 然后点击生成外链播放器 然后复制代码: 进入到自己的博客园设置页面 我 ...
- java怎么爬网易云_Python爬虫爬取网易云的音乐
Python爬虫爬取网易云的音乐(学习笔记) 在开始之前,做一点小小的说明哈: 我只是一个python爬虫爱好者,如果本文有侵权,请联系我删除! 本文需要有简单的python爬虫基础,主要用到两个爬虫 ...
- Python之手把手教你用JS逆向爬取网易云40万+评论并用stylecloud炫酷词云进行情感分析
本文借鉴了@平胸小仙女的知乎回复 https://www.zhihu.com/question/36081767 写在前面: 文章有点长,操作有点复杂,需要代码的直接去文末即可.想要学习的需要有点耐心 ...
- 爬取网易云的音乐信息
简单的爬取音乐的名称及链接 简单爬虫 以爬取网易云音乐中的云音乐飙升榜为例 最后提醒大家,合法爬取!!! 简单爬虫 以爬取网易云音乐中的云音乐飙升榜为例 from urllib.request imp ...
最新文章
- 20180716:开博宣言
- 跟沈剑学习如何带领技术团队作战
- docker php示例,Docker PHP 例子
- 对一个可进行带括号 加减乘除运算类的分析
- long 雪花算法_一次复杂的雪花算法使用总结
- 最简单的基于FFmpeg的移动端例子:Android 推流器
- 昨晚学妹参加了B站秋招笔试,还想考考我?
- linux命令大全---入门篇(菜鸟必会)
- 数据仓库系列9- 大数据分析
- 在python是什么意思_Python a=b是什么意思?
- 后缀表达式看完这一篇文章就理解了!
- 为什么开发与测试老掐架呢
- OpenAI打破文本和图像次元壁,提出基于对比学习的多模态预训练模型CLIP
- 特殊符号,emoji表情,四字节去除问题
- 玉米社:百度竞价推广计划、推广单元是什么?
- Scrapy 2.6 Items 数据项定义、加载、传输使用指南
- MPP大规模并行处理架构详解(满满干货,需细嚼慢咽)
- sklearn库主要模块功能简介
- 光场技术的过去,现在和未来
- 西南财经大学本科毕业论文答辩PPT模板
热门文章
- html制作页面书签的步骤,网页制作基础教程(二)html标签
- LinuxC:锁、条件变量、信号量实现线程间的同步 生产者与消费者 pthread_mutex_init pthread_cond_init sem_init
- SmartBI入门(二)配置SmartBI
- Java五子棋(人机版),昨天买的棋子今天就用不上了
- TorchScript (将动态图转为静态图)(模型部署)(jit)(torch.jit.trace)(torch.jit.script)
- C# 蓝牙编程(InTheHand.Net.Personal.dll-32feet),教程地址
- 最近在测FREEBSD平台下ISP邮件系统前的准备知识摘录
- 35年老程序员个人谈:C语言时代行将落幕
- “先进”的飞书为何搞不定钉钉?
- JVM中的Xms和Xmx