前言

月明星稀,凄神寒骨,独守窗台,

孤灯的残影烙印在远处,

遮住了我的双目,也挡住了去的路,

望着天顶的失落,原来最后的等待,叫未来可期,

正如我许多次半夜里突然转醒,久不能眠,

于是我吃饱没事干,心血来潮,拉下窗帘,

打开网抑云,写个爬虫,去感受最真实的人间~ T_T

相关知识

网页一般有两种渲染方式:

  1. 服务器渲染
  2. 客户端渲染

服务器渲染:在服务器那边直接把数据和html整合在一起,统一返回给浏览器

  • 在页面源代码中能看到数据

客户端渲染:第一次请求只要一个HTML框架,第二次请求拿到数据,进行数据展示。

  • 在页面源代码中,看不到数据

思路

大部分爬虫的思路基本都是一致的:

  1. 确认内容是否在源代码内
  2. 若在,则直接通过re,xpath,beautifulsoup等方式提取内容
  3. 若不在,则定位内容对应的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数据得到的,而这两个玩意的真实内容,是被加密了的。

网易服务器收到请求后,就会将这两个参数解密,得到真实的内容,再像网页返回评论数据。

因此,我们要做的就是想办法找到未加密前的数据,以及找到加密过程,最后在我们的程序里模拟出加密过程,向服务器发送请求,得到结果。

  1. 找到未加密的参数
  2. 想办法把参数进行加密(必须参考网易的逻辑),params, encSecKey
  3. 请求到网易,拿到评论信息

JS逆向

JS逆向主要就是通过调试,分析出JS代码的作用,从而推导出加密过程,最后找出参数的真实含义。

目前加密的方式总结有下面几点:

  1. 对称加密(加密解密密钥相同):DES、DES3、AES
  2. 非对称加密(分公钥私钥):RSA
  3. 信息摘要算法/签名算法:MD5、HMAC、SHA
  4. 前端实际使用中MD5、AES、RSA,自定义加密函数使用频率是最高的
  5. 几种加密方式配合次序:采用非对称加密算法管理对称算法的密钥,然后用对称加密算法加密数据,用签名算法生成非对称加密的摘要
  6. DES、DES3、AES、RSA、MD5、SHA、HMAC传入的消息或者密钥都是bytes数据类型,不是bytes数据类型的需要先转换;密钥一般是8的倍数
  7. 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函数最后是返回了两个值,分别是encTextencSecKey,其实分别对应了data参数里的paramsencSecKey

图26 data参数

至此,我们基本就分析得出了参数加密的整个过程,现在梳理一下:

  1. 通过网络模块,定位到URL,发现参数加密
  2. 通过调试JS代码,定位到加密过程,锁定加密函数
  3. 逐步分析代码作用,得到加密原理

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
。。。。。。

[实战]爬取网抑云音乐评论相关推荐

  1. python爬取网抑云音乐评论

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 一.python爬取网抑云音乐评论 前言 提示:这里可以添加本文要记录的大概内容: python爬取网抑云音乐评论 提 ...

  2. 【爬虫系列】用Python爬取网抑云(music)评论

    目录 前言 分析 代码过程 成果展示 完整代码 前言 本案例难度一般,需要逆向两个加密参数,对于初学者还是比较麻烦的,希望通过我的分析过程,能帮助大家快速理解! 分析 首先找到评论数据接口,看看有没有 ...

  3. [爬虫]网抑云音乐评论

    [爬虫]网抑云音乐评论 前言 自打开网抑云之后,我久久无法忘记,是它才能带给我内心世界的波涛汹涌.我左手拿起它,右手放下它,一日复一日,我终于完成了<The Spider Of Music-16 ...

  4. 【爬虫+多线程+MySQL】网抑云音乐评论爬取

    提示:本文仅作学习交流使用,下面案例可供参考. 文章目录 前言 一.爬取所有华语男歌手姓名及ID 1.网页分析 2.代码实现 3.部分运行结果 附:url详解 二.爬取所有华语男歌手专辑ID 1.网页 ...

  5. 深夜爬虫, 我很抱歉 , 附爬取“网抑云”最详细的爬虫教程!

    最近真的是被 网抑云 这个梗刷爆了,到处都是, 生而为人,我很抱歉,哈哈哈, 碰巧最近学习了一波微信公众号的爬取方式,想试一试, 特地在此献丑了.我是沙漏, 不定期更新爬虫教学, 其余时间学java和 ...

  6. python爬取网抑云歌曲下载

    爬取对象 下载新歌榜中歌曲,在.py文件创建一个music文件 全部代码如下: # encoding=utf8 import requests from bs4 import BeautifulSou ...

  7. 给自己的博客园添加网抑云音乐播放器

    1. 申请权限 首先给自己的博客园设置,申请js权限,这个教程可以去搜. 2. 打开网页版网抑云音乐 点击一首你喜欢的歌进入 , 然后点击生成外链播放器 然后复制代码: 进入到自己的博客园设置页面 我 ...

  8. java怎么爬网易云_Python爬虫爬取网易云的音乐

    Python爬虫爬取网易云的音乐(学习笔记) 在开始之前,做一点小小的说明哈: 我只是一个python爬虫爱好者,如果本文有侵权,请联系我删除! 本文需要有简单的python爬虫基础,主要用到两个爬虫 ...

  9. Python之手把手教你用JS逆向爬取网易云40万+评论并用stylecloud炫酷词云进行情感分析

    本文借鉴了@平胸小仙女的知乎回复 https://www.zhihu.com/question/36081767 写在前面: 文章有点长,操作有点复杂,需要代码的直接去文末即可.想要学习的需要有点耐心 ...

  10. 爬取网易云的音乐信息

    简单的爬取音乐的名称及链接 简单爬虫 以爬取网易云音乐中的云音乐飙升榜为例 最后提醒大家,合法爬取!!! 简单爬虫 以爬取网易云音乐中的云音乐飙升榜为例 from urllib.request imp ...

最新文章

  1. 20180716:开博宣言
  2. 跟沈剑学习如何带领技术团队作战
  3. docker php示例,Docker PHP 例子
  4. 对一个可进行带括号 加减乘除运算类的分析
  5. long 雪花算法_一次复杂的雪花算法使用总结
  6. 最简单的基于FFmpeg的移动端例子:Android 推流器
  7. 昨晚学妹参加了B站秋招笔试,还想考考我?
  8. linux命令大全---入门篇(菜鸟必会)
  9. 数据仓库系列9- 大数据分析
  10. 在python是什么意思_Python a=b是什么意思?
  11. 后缀表达式看完这一篇文章就理解了!
  12. 为什么开发与测试老掐架呢
  13. OpenAI打破文本和图像次元壁,提出基于对比学习的多模态预训练模型CLIP
  14. 特殊符号,emoji表情,四字节去除问题
  15. 玉米社:百度竞价推广计划、推广单元是什么?
  16. Scrapy 2.6 Items 数据项定义、加载、传输使用指南
  17. MPP大规模并行处理架构详解(满满干货,需细嚼慢咽)
  18. sklearn库主要模块功能简介
  19. 光场技术的过去,现在和未来
  20. 西南财经大学本科毕业论文答辩PPT模板

热门文章

  1. html制作页面书签的步骤,网页制作基础教程(二)html标签
  2. LinuxC:锁、条件变量、信号量实现线程间的同步 生产者与消费者 pthread_mutex_init pthread_cond_init sem_init
  3. SmartBI入门(二)配置SmartBI
  4. Java五子棋(人机版),昨天买的棋子今天就用不上了
  5. TorchScript (将动态图转为静态图)(模型部署)(jit)(torch.jit.trace)(torch.jit.script)
  6. C# 蓝牙编程(InTheHand.Net.Personal.dll-32feet),教程地址
  7. 最近在测FREEBSD平台下ISP邮件系统前的准备知识摘录
  8. 35年老程序员个人谈:C语言时代行将落幕
  9. “先进”的飞书为何搞不定钉钉?
  10. JVM中的Xms和Xmx