在此记录一下自己的爬虫练习之路
我猜来看我这篇文章的基本都是小白或者是有一点基础想要进一步提高自己实力的'爬虫'们
让我们一起共同进步吧!
我会尽量将每一步都讲出来,尽量让大家看得明白,现在开始吧
网址:某狗音乐
分析过程
- 首先打开酷狗音乐网页,然后按F12打开开发者工具,再在搜索框输入任意歌名,
之后按下回车进行搜索 - 进入搜索后网页会持续加载,右边开发者工具不断会有内容出现,当网页加载完成后在下面列表里一个个的点开看,这个过程会很枯燥,加油.在看了一段时间后会找到左边红框的接口,预览里就是网页显示的搜索结果
- 复制cURL,
爬虫工具库-spidertools.cn
去这个网页中转换为python代码去pycharm中看看能不能请求到结果,因为复制cURL的操作无法截图,直接看图吧将复制的cURL粘贴到左边方框,然后全选右边的代码进行复制 - 成功请求,说明接口与请求参数都是有效的
- 删除框中的代码,验证接口是否验证cookie
验证说明不需要cookie也可以请求,nice!因为我不会逆向cookie生成过程,省事了~ - 转回开发者工具,多次请求验证除了框选的参数其他全是固定的,时间戳和搜索参数好解决,剩下加密参数的加密方法现在开始一步步调试出来
- 按shift+ctrl+f打开全局搜索,先搜索mid,会看到多个选项,不知道选哪个的话就每一个都点进去看看,看看代码是否包含mid以及赋值,实在不行就每一个点进去然后点击代码旁边最外面的边框打上断点,然后去搜索框搜不同的内容,按下回车会发现代码停在了断点的位置(俺也打了好几个断点才找到真正的位置)
- 一步步调试,打印看看f是否发生变化
- 然后再看看附近其他变量,发现变量 l 中已有加密参数,说明在此之前参数mid和uuid就已经被加密,所以需要在右边的调用堆栈中往前推,这里面还有dfid,暂时不管
- 再往前走,发现到了调用的位置,打印查看变量o,发现正是此处往后传入的代码,再往上翻翻,我们就找到了mid真正的加密方法了!
- 断点打到加密方法处,点击类似于播放的按钮让进程走完,然后搜索框重新输入并搜索,就断到了我们刚才打断点的地方;把鼠标放在调用加密函数的位置上,会弹出一个方框,点击框中的蓝色链接就会跳转到加密方法的真正位置;but,我们的断点现在还在下图的位置,所以我们需要点击绿色方框的单步调试按钮进入代码
- 一步步调试,最后发现红框处就是加密的来源,存在于cookie中
- 但是我们并不清楚cookie是怎么生成的,所以,再次释放进程,然后我们回到网络选项卡中,按下图的步骤,清除浏览器cookie,重新搜索,进入断点
- 由于没有cookie,var n = e.Cookie.read("kg_mid");这一行代码为空,会进入到红框所选的位置中,恭喜你,此处就是cookie,mid,uuid真正生成的位置!!!(误打误撞找到了cookie,奈斯~)
而真正加密就是绿框所选的位置.
老规矩,我们先进入e.Guid()查看代码,发现代码就在上头 - 蓝色框中的js代码比较简单,我们可以直接用python改写(复杂的一般扣js,咱不太会)
def guid(): num = 1 + random.random() res = hex(int(65536 * num))[3:] return res GUID = guid() + guid() + "-" + guid() + "-" + guid() + "-" + guid() + "-" + guid() + guid() + guid()
-
然后我们再次查看e.Md5(),其实就是一个md5加密,有个简答的方法来判断md5加密是否有被魔改,就是直接用当前js的md5加密固定内容查看结果,再到别的加密平台加密同样的内容查看结果是否一致,俺是直接用python的hashlib库的md5方法.
import hashlib def gen_md5(word): word = ''.join([x for x in word]) encode_word = word.encode('utf-8') return hashlib.md5(encode_word).hexdigest()
-
一致,那就好说了,mid以及uuid加密方法已经到手,接下来是加密参数signature
def gen_md5(word): word = ''.join([x for x in word]) encode_word = word.encode('utf-8') return hashlib.md5(encode_word).hexdigest() def guid(): num = 1 + random.random() res = hex(int(65536 * num))[3:] return res GUID = guid() + guid() + "-" + guid() + "-" + guid() + "-" + guid() + "-" + guid() + guid() + guid() mid = gen_md5(GUID)
-
再次全局搜索,打上断点,重新搜索歌曲,断点已经成功断住,此处就是signature的加密来源
-
经过多次请求,打印内容,发现s其实是个列表,而列表内容是请求接口所需的参数,拼接而成的字符串,我们不用那么麻烦,直接复制他的字符串就行,不过里面有几个地方需要修改
-
s解决了,我们再看看方法d,打上断点,重新请求,单步调试进入方法,变量t为刚刚传入的明文
-
这里说一下方法d,我当时直觉告诉我是md5加密,然后我就这么做了,而且成功了,确实是那样;至于方法d的js代码,调试的时候并不是直接的md5,而是将字符串转为列表然后拼接成的密文,着实没有头绪,如果有人知道是什么原理还请讲解一下~
那么现在,方法d我们就直接md5加密即可,完整请求代码如下headers = { "authority": "complexsearch.kugou.com", "accept": "*/*", "accept-language": "zh-CN,zh;q=0.9", "cache-control": "no-cache", "pragma": "no-cache", "referer": "https://www.kugou.com/", "sec-ch-ua": "\"Not.A/Brand\";v=\"8\", \"Chromium\";v=\"114\", \"Google Chrome\";v=\"114\"", "sec-ch-ua-mobile": "?0", "sec-ch-ua-platform": "\"Windows\"", "sec-fetch-dest": "script", "sec-fetch-mode": "no-cors", "sec-fetch-site": "same-site", "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36" } def gen_md5(word): word = ''.join([x for x in word]) encode_word = word.encode('utf-8') return hashlib.md5(encode_word).hexdigest() url = "https://complexsearch.kugou.com/v2/search/song" params = { "callback": "callback123", "srcappid": "2919", "clientver": "1000", "clienttime": "", # 时间戳 "mid": "", "uuid": "", "dfid": "", "keyword": "", # 歌名 "page": "1", "pagesize": "30", "bitrate": "0", "isfuzzy": "0", "inputtype": "0", "platform": "WebFilter", "userid": "0", "iscorrection": "1", "privilege_filter": "0", "filter": "10", "token": "", "appid": "1014", "signature": "" # 加密 } def guid(): num = 1 + random.random() res = hex(int(65536 * num))[3:] return res GUID = guid() + guid() + "-" + guid() + "-" + guid() + "-" + guid() + "-" + guid() + guid() + guid() def gen_params(word): timestamp = int(time.time() * 1000) dfid = '-' # dfid经过本人多次测试发现为-即可 keyword = word mid = gen_md5(GUID) t = f'NVPh5oo715z5DIWAeQlhMDsWXXQV4hwtappid=1014bitrate=0callback=callback123clienttime={timestamp}clientver=1000dfid={dfid}filter=10inputtype=0iscorrection=1isfuzzy=0keyword={keyword}mid={mid}page=1pagesize=30platform=WebFilterprivilege_filter=0srcappid=2919token=userid=0uuid={mid}NVPh5oo715z5DIWAeQlhMDsWXXQV4hwt' signature = gen_md5(t) params['clienttime'] = timestamp params['dfid'] = dfid params['keyword'] = keyword params['mid'] = mid params['uuid'] = mid params['signature'] = signature return params response = requests.get(url, headers=headers, params=gen_params(word)).text
最后
我的第一篇博客,终于写完了,嘎嘎
如果什么地方有疑问可以在评论区留言,我看到会回复的
如果什么地方有问题,还请各位大佬帮忙指出
感谢