该网站现在的架构发生了变化,在network中已没有 client_search_cp?ct=… 这个请求,数据已直接呈现在网页中,不过这个api现在依旧可以访问
2021.11.22
刚开始学爬虫使用的都是简单的网页,想要的数据可以直接从网页源码中获得,但是实际情况却不是这样的,如果网页的源码中数据不全,或者根本没有我们想要的数据,那该怎么办呢?
这时就可以通过开发者模式(F12)在Network中寻找深层次的数据,通过分析查看其中客户端与服务器的交互信息来找到我们想要的数据。
Network中有很多细分的模块,我们重点看XHR,因为我们想要的数据大多可以从这里找到。如下图
那么什么是XHR呢?XHR是Network中非常重要的一类请求,XHR请求是通过Axjx技术实现在更新网页时不用重新加载整个网页,这样既减轻服务器的负担,又节省流量与时间。
如何判断数据在html中还是在XHR中呢?
可以打开Network后查看第一个请求的内容中有没有数据,
如果没有就在XHR中去寻找
上面的描述是为下面做铺垫,只是比较浅显的讲述了一下,具体的用法还需要自己深入了解,这里就不做赘述了。接下来深入主题。
这时我们会发现解析出来的网页数据中只有一些html标签信息,并没有我们想要的歌曲信息
XHR下有一个Name叫client_search_cp?ct=…的请求信息,点击后这条请求后在其Preview下的json数据中可以看到页面中的一些信息
深入点开List的第一个就可以看到其中的歌曲信息,这里就有我们要找的信息
找到了这里,接下来我们可以获取数据了,但是怎么获取这里的json数据呢
其实答案就在旁边的Headers中,我们可以从其中的 Request URL(点击查看) 获取到json数据
可以将 json字符串(点击查看)复制到 json.cn去更清楚得查看结构
如果想要获取专辑名字 “我与你” 代码就可以这样写(关键是结合上一张图,看这里的第13行,其中list下有10条信息,这里只要第一条,所以用后面用[0][‘album’][‘name’])
有了前面的讲解,这里就直接上代码了
import requests
# 请求地址
url = 'https://c.y.qq.com/soso/fcgi-bin/client_search_cp?ct=24&qqmusic_ver=1298&new_json=1&remoteplace=txt.yqq.song&searchid=60573890944916186&t=0&aggr=1&cr=1&catZhida=1&lossless=0&flag_qc=0&p=1&n=10&w=%E5%BC%A0%E5%AD%A6%E5%8F%8B&g_tk_new_20200303=247151551&g_tk=247151551&loginUin=1578887414&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8¬ice=0&platform=yqq.json&needNewCode=0'
# headers
headers={'user-agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36'}
# 获取数据
res_music = requests.get(url,headers=headers)
# 将response对象转换为dict/list
json_music = res_music.json()
# 根据数据的结构,将dict数据”一层层剥开“
list_music = json_music['data']['song']['list']
music_info = []
# 提取每首歌的信息
for music in list_music:
music_name = music['name'] # 歌曲名
album_name = music['album']['name'] # 专辑名
singer = music['singer'][0]['name'] # 歌手
length = music['interval'] # 时长
music_url = 'https://y.qq.com/n/yqq/song/' + music['mid'] + '.html' # 播放链接
music_info.append([music_name,album_name,singer,length,music_url])
for i in music_info:
print(i)
如果我们想要一次得到更多甚至是全部信息该怎么做呢?
这里需要我们使用带参数请求的方式来得到更多的歌曲信息,其实在上面给出的代码中的url就是一个带参数的请求地址。我们只需要改变参数的值就可以得到自己想要的数据了。
url中 “?” 之后的都是参数,参数之间用 “&” 连接,“=”后面是参数的值。
https://c.y.qq.com/soso/fcgi-bin/client_search_cp?ct=24&qqmusic_ver=1298&new_json=1&remoteplace=txt.yqq.song&searchid=60573890944916186&t=0&aggr=1&cr=1&catZhida=1&lossless=0&flag_qc=0&p=1&n=10&w=%E5%BC%A0%E5%AD%A6%E5%8F%8B&g_tk_new_20200303=247151551&g_tk=247151551&loginUin=1578887414&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8¬ice=0&platform=yqq.json&needNewCode=0
上面的这种方式看起来并不友好,其实在Headers中可以更清晰地查看到各个参数(Headers最底下的Query String Parameters中)
这样看起来是不是清楚多了,这里我们只关注p和n这两个参数
分别表示页数(page)与每页的数量(number)
接下来我们只需要改变这两个参数就可以得到任意数量的数据
在了解了带参数请求后,最直接的方式就是修改url中的参数就可得到想要的数据了
url = ‘https://c.y.qq.com/soso/fcgi-bin/client_search_cp?ct=24&qqmusic_ver=1298&new_json=1&remoteplace=txt.yqq.song&searchid=60573890944916186&t=0&aggr=1&cr=1&catZhida=1&lossless=0&flag_qc=1&
p=1&n=30
&w=%E5%BC%A0%E5%AD%A6%E5%8F%8B&g_tk_new_20200303=247151551&g_tk=247151551&loginUin=1578887414&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8¬ice=0&platform=yqq.json&needNewCode=0’
但这只是一种笨方法,也不符合我们对于 python语言简洁性的了解
其实就是上面说到的Headers中的Query String Parameters就可以解决这个问题
将Query String Parameters中的数据全部封装到一个字典中,发送请求时一起传递给浏览器即可。get请求也是支持的,方法中的params参数就是用来传递请求参数的
就像下图这样
上面的代码也可以实现和之前一样的效果
可以发现,其中的url短了很多,只有原来url的“?”之前的部分,并且将参数用字典封装到param中也增加了代码的可扩展性和可读性。
很多地方都只是带过,如查看Network面板,Axjx,json等等都只给出了部分介绍或代码,并没有深入说明,因为这对于面向百度学习的我们应该不是太困难吧。
刚开始还是比较犹豫要不要写这篇博客的,因为准备三级考试,中间隔的时间有点长,有点生疏了,并且这部分对我来说也是新知识,还没有完全吸收,东西太多了就感觉有点难以找到一条线将它们串联起来。
但是开始写了之后,看着之前的知识再复习一下感觉就要好多了,看来还是得多记录,可以理清知识的联系,也可以在之后用到时快速复习。因为我并没有去记每行代码是怎么写的,只要记住大概原理,这样在未来用的时候就能根据现在的记录很快得想起来,但是这样也有一个缺点,就是用得少的话,每次用都要看着之前的记录写,但这刚好适合像我这样健忘的人今后的学习。哈哈