urllib3下网易云音乐分析遇到的坑

环境:{

    系统:win10

    python:python-3.6.4-amd64.exe # 官网下的,自己可以下

    urllib:urllib3 # pip install urllib3 安装。

    idea:  pycharm-community-2017.3.4.exe # 这个官网也有,不用破解,因为是社区版(够用),不是专业版。

    时间:大家注意博客时间,因为他api改了也说不定

    pycrytodome(AES): pip install pycrytodome # pycryto&cryto直接pip不行,网上也有解决办法,但感觉这个简单

    ps: 想节约时间看干货可以直接去最后,我感觉主要是参数问题。

}

想做一个网易云音乐的音频下载爬虫,苦难重重,本人小白,不喜勿喷。主要是记录我在编程时的坑,遇到同样问题不至于浪费时间。

我只做了一个页面爬真实地址,剩下的就简单了。就决定是你了:http://music.163.com/#/song?id=29567100 眉间雪

大家都懂打开网页F12,再F5刷新:

对于b这个GET请求我想大家都知道吧,直接可以打开,通过另存为mp3实现。

主要说a这个POST请求,除了该有的请求头外,他是有参数的:

关于为什么是这个xhr请求和参数解析,大家请移步:https://www.zhihu.com/question/36081767

感谢这个知乎大神提供的方法。

为了测试我自己的代码,对于params和encSecKey我是直接传进去的:

data = {
    'params': '/MHyb9Ekp9GO4dUqbNJUDaJ4JruAX+R7ZodEeiAdlSsPNXZOpEmBY5InP574jBLKHYzExLm0q3SPfuIrWdNatehjgX1Zxoo4nhip45ycQUu2/MIK3KcbfD8B7Mh8IXhr',
    'encSecKey': '96f3df985b1912785e15b4c3ba7bb070a978693c016514d6ee866c70a54a1baa520d5b8076b1384c7098fc9d2b52816bef418854d17704679d723d53671992ad680a1b4488959e8cc28fd6762368a1840364dbf62c60e4ef6663015a35e8fdc6eabb52d1ccca642b4ad827826140b1248758f83b04dcd9661f4b203c03735237'
}

请求头的话是这个:

headers = {
    'Accept': '*/*',
    'Accept-Encoding': 'gzip, deflate',
    'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
    'Cache-Control': 'max-age=0, no-cache',
    'Connection': 'keep-alive',
    'Content-Length': '408',
    'Content-Type': 'application/x-www-form-urlencoded',
    'Host': 'music.163.com',
    'Referer': 'http://music.163.com/',
    'Pragma': 'no-cache',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:59.0) Gecko/20100101 Firefox/59.0',
}
但实际这个才是最关键的,必须有。当然其他的最好有(我强迫症)
'Content-Type': 'application/x-www-form-urlencoded'

于是开始用urllib3做请求:(urllib3的用法官网有的就不说了,https://urllib3.readthedocs.io/en/latest/user-guide.html

http = urllib3.PoolManager(cert_reqs='CERT_REQUIRED', ca_certs=certifi.where()) #这个里面两个参数是防止产生Warning的
# 方式:post, 地址:http://music.163.com/weapi/song/enhance/player/url(也可以在后面加上"?csrf_token")
# fields用于传入表单数据(data就是前面的代码段data), headers(也是前面的代码段headers)
html = http.request('POST', 'http://music.163.com/weapi/song/enhance/player/url',fields=data, headers=headers)
result = html.data # 返回的二进制数据。可以通过json.loads(data.decode('utf-8'))编程json格式数据
code = html.status # 返回的请求状态码

结果,code=200,result=b''。居然是空。

这个问题困扰了我两天。我不断的检查:是post方式啊,关键请求头有啊(我一直以为是请求头的问题,无聊到一条一条的试),表单数据是fields={}传的啊,不可能是body={}(其实我也试了),data数据是对的啊(不会因为时间产生错误)。吃枣药丸。。。。。。。

灵光一闪,我擦,祖传手艺----编译啊怎么能忘呢,于是开始一条一条的看,还真的有发现,这条官网上没说,是关于content-type请求的:

这里面提到了encode_multipart参数,当为False时才会以content-type:application/x-www-form-urlencoded 传递数据data。并且默认是True,而我就是因为没设置为False才会导致传递方式错误,而且这个content-type这个不能使用aplication/json或者multipart_boundary(默认是这种)方式。

http = urllib3.PoolManager(cert_reqs='CERT_REQUIRED', ca_certs=certifi.where())
html = http.request('POST', 'http://music.163.com/weapi/song/enhance/player/url',fields=data, headers=headers,encode_multipart=False)

添加encode_multipart=False参数后,终于返回了数据。


但是我这个地方params和encSecKey是指定的,肯定可以返回数据的。当我用上文知乎大神和另一篇博客给的计算方法计算的params和encSecKey做请求时却还是返回空数据,现在还不知道原因,也许是因为跨时间太久,加密方式发生改变导致。我还没解决出来,等弄出来会更新的。源代码我这挺乱的,等我整理好就传上来。

Good Luck To You All.





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值