Python爬虫笔记——解析json数据(以周杰伦歌单为例)及Headers

一、Network

Network能够记录浏览器的所有请求。我们最常用的是:ALL(查看全部)/XHR(仅查看XHR)/Doc(Document,第0个请求一般在这里),有时候也会看看:Img(仅查看图片)/Media(仅查看媒体文件)/Other(其他)。最后,JS和CSS,则是前端代码,负责发起请求和页面实现;Font是文字的字体;而理解WS和Manifest,需要网络编程的知识,倘若不是专门做这个,则不需要了解。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
我们平时使用浏览器上网的时候,经常有这样的情况:浏览器上方,它所访问的网址没变,但是网页里却新加了内容。
典型代表:如购物网站,下滑自动加载出更多商品。在线翻译网站,输入中文实时变英文。再比如,我们正在爬取的QQ音乐案例,如果你对“周杰伦”的搜索结果进行翻页,浏览器上方显示的网址,也不会发生变化。
在Network,有非常重要的一类请求是XHR(或Fetch),因为有它的存在,人们不必刷新/跳转网页,即可加载新的内容。随着技术发展,XHR的应用频率越来越高,我们常常需要在这里找我们想要的数据。
在这里插入图片描述
Headers:标头(请求信息)、Preview:预览、Response:原始信息、Timing:时间。

XHR的功能是传输数据,其中有非常重要的一种数据是用json格式写成的,和html一样,这种数据能够有组织地存储大量内容。json的数据类型是“文本”,在Python语言当中,我们把它称为字符串。我们能够非常轻易地将json格式的数据转化为列表/字典,也能将列表/字典转为json格式的数据。

如何解析json数据?答案如下:
在这里插入图片描述
而如果你想在Python语言中,实现列表/字典转json,json转列表/字典,则需要借助json模块。
也可阅读它的官方文档来了解,地址在这里:https://docs.python.org/3/library/json.html

一个简单的应用示例,是这样:

import json
# 引入json模块
a = [1,2,3,4]
# 创建一个列表a。
b = json.dumps(a)
# 使用dumps()函数,将列表a转换为json格式的字符串,赋值给b。
print(b)
# 打印b。
print(type(b))
# 打印b的数据类型。
c = json.loads(b)
# 使用loads()函数,将json格式的字符串b转为列表,赋值给c。
print(c)
# 打印c。
print(type(c)) 
# 打印c的数据类型。

打印结果:

[1, 2, 3, 4]
<class 'str'>
[1, 2, 3, 4]
<class 'list'>

二、爬取QQ音乐周杰伦的前20个歌曲名、所属专辑、播放时长,以及播放链接的实例

import requests
# 引用requests库
res_music = requests.get('https://c.y.qq.com/soso/fcgi-bin/client_search_cp?ct=24&qqmusic_ver=1298&new_json=1&remoteplace=txt.yqq.song&searchid=60997426243444153&t=0&aggr=1&cr=1&catZhida=1&lossless=0&flag_qc=0&p=1&n=20&w=%E5%91%A8%E6%9D%B0%E4%BC%A6&g_tk=5381&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8&notice=0&platform=yqq.json&needNewCode=0')
# 调用get方法,下载这个字典
json_music = res_music.json()
# 使用json()方法,将response对象,转为列表/字典
list_music = json_music['data']['song']['list']
# 一层一层地取字典,获取歌单列表
for music in list_music:
# list_music是一个列表,music是它里面的元素
    print(music['name'])
    # 以name为键,查找歌曲名
    print('所属专辑:'+music['album']['name'])
    # 查找专辑名
    print('播放时长:'+str(music['interval'])+'秒')
    # 查找播放时长
    print('播放链接:https://y.qq.com/n/yqq/song/'+music['mid']+'.html\n')
    # 查找播放链接

打印结果:

Mojito
所属专辑:Mojito
播放时长:185秒
播放链接:https://y.qq.com/n/yqq/song/001glaI72k8BQX.html

晴天
所属专辑:叶惠美
播放时长:269秒
播放链接:https://y.qq.com/n/yqq/song/0039MnYb0qxYhV.html

一路向北
所属专辑:J III MP3 Player
播放时长:295秒
播放链接:https://y.qq.com/n/yqq/song/001xd0HI0X9GNq.html

七里香
所属专辑:七里香
播放时长:299秒
播放链接:https://y.qq.com/n/yqq/song/004Z8Ihr0JIu5s.html

稻香
所属专辑:魔杰座
播放时长:223秒
播放链接:https://y.qq.com/n/yqq/song/003aAYrm3GE0Ac.html

告白气球
所属专辑:周杰伦的床边故事
播放时长:215秒
播放链接:https://y.qq.com/n/yqq/song/003OUlho2HcRHC.html

听妈妈的话
所属专辑:依然范特西
播放时长:265秒
播放链接:https://y.qq.com/n/yqq/song/002hXDfk0LX9KO.html

等你下课
所属专辑:等你下课
播放时长:270秒
播放链接:https://y.qq.com/n/yqq/song/001J5QJL1pRQYB.html

夜曲
所属专辑:十一月的萧邦
播放时长:226秒
播放链接:https://y.qq.com/n/yqq/song/001zMQr71F1Qo8.html

半岛铁盒
所属专辑:八度空间
播放时长:319秒
播放链接:https://y.qq.com/n/yqq/song/002OKIox28ad9a.html

不能说的秘密
所属专辑:不能说的秘密 电影原声带
播放时长:296秒
播放链接:https://y.qq.com/n/yqq/song/002MXZNu1GToOk.html

搁浅
所属专辑:七里香
播放时长:240秒
播放链接:https://y.qq.com/n/yqq/song/001Bbywq2gicae.html

青花瓷
所属专辑:我很忙
播放时长:239秒
播放链接:https://y.qq.com/n/yqq/song/002qU5aY3Qu24y.html

以父之名
所属专辑:叶惠美
播放时长:342秒
播放链接:https://y.qq.com/n/yqq/song/001n4C3p1yv0FU.html

给我一首歌的时间
所属专辑:魔杰座
播放时长:253秒
播放链接:https://y.qq.com/n/yqq/song/004BhQke4adHcf.html

爱的飞行日记
所属专辑:跨时代
播放时长:255秒
播放链接:https://y.qq.com/n/yqq/song/003CxS6w14OQyM.html

简单爱
所属专辑:范特西
播放时长:270秒
播放链接:https://y.qq.com/n/yqq/song/0009BCJK1nRaad.html

蒲公英的约定
所属专辑:我很忙
播放时长:247秒
播放链接:https://y.qq.com/n/yqq/song/004Yi5BD3ksoAN.html

烟花易冷
所属专辑:跨时代
播放时长:263秒
播放链接:https://y.qq.com/n/yqq/song/004emQMs09Z1lz.html

枫
所属专辑:十一月的萧邦
播放时长:275秒
播放链接:https://y.qq.com/n/yqq/song/003KtYhg4frNXC.html

以上代码只能爬取20个代码使它能爬取很多很多歌曲,而不只是爬取20个。所以要学会怎么翻页
使用浏览器打开QQ音乐官网,搜索周杰伦。然后打开检查面板里的Network,刷新这个页面。找到隐藏有歌曲列表的那个XHR,它的名字应该叫client_search……之类,点开它,选中Headers,你能看到Request Url,很长的一个地址。现在,保持General打开,保持Response Headers和Request Headers关闭。我们点开Query String Parametres。它里面的内容,正是请求所附带的参数,Query String Parametres,它的中文翻译是:查询字符串参数。这个面板用类似字典的形式,呈现了各个参数的键值,阅读体验会好一些。

三、如何带参数请求数据

读懂参数,有两个重要的方法是“观察”和“比较”。“观察”指的是阅读参数的键与值,尝试理解它的含义。“比较”指的是比较两个相近的XHR——它们有哪些不同,对应的页面显示内容有什么不同。
现在,我们来观察比较,不同页码的歌曲列表,它们url的不同。依然在搜索“周杰伦”的结果页,点击第2页、第3页进行翻页,此时Network会多加载出2个XHR,它们的Name都是client_search…。
在这里插入图片描述
分别点开它们的Query String Parametres,比较参数之间有什么不同。点击Enter(回车)键,告诉你答案。
在此,只有一个参数变化。这个参数是p。第1页p的值为1,第二、第三页的值则为2和3。说明p代表的应该就是页码。
如果你再去对比它们的url,也能发现同样的事实:url整个儿都是
我们去写一个循环,每次循环去更改p的值,这样不就能实现爬取好多好多歌曲了吗?
代码如下

import requests
# 引用requests模块
page = int(input('请输入歌单的页数:'))
for x in range(page):
    res_music = requests.get('https://c.y.qq.com/soso/fcgi-bin/client_search_cp?ct=24&qqmusic_ver=1298&new_json=1&remoteplace=txt.yqq.song&searchid=60997426243444153&t=0&aggr=1&cr=1&catZhida=1&lossless=0&flag_qc=0&p='+str(x+1)+'&n=20&w=%E5%91%A8%E6%9D%B0%E4%BC%A6&g_tk=5381&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8&notice=0&platform=yqq.json&needNewCode=0')
    # 调用get方法,下载这个字典
    json_music = res_music.json()
    # 使用json()方法,将response对象,转为列表/字典
    list_music = json_music['data']['song']['list']
    # 一层一层地取字典,获取歌单列表
    for music in list_music:
    # list_music是一个列表,music是它里面的元素
        print(music['name'])
        # 以name为键,查找歌曲名
        print('所属专辑:'+music['album']['name'])
        # 查找专辑名
        print('播放时长:'+str(music['interval'])+'秒')
        # 查找播放时长
        print('播放链接:https://y.qq.com/n/yqq/song/'+music['mid']+'.html\n')

四、params

事实上,requests模块里的requests.get()提供了一个参数叫params,可以让我们用字典的形式,把参数传进去。
在这里插入图片描述
所以,其实我们可以把Query String Parametres里的内容,直接复制下来,封装为一个字典,传递给params。只是有一点要特别注意:要给他们打引号,让它们变字符串。
代码如下:

import requests
# 引用requests模块
url = 'https://c.y.qq.com/soso/fcgi-bin/client_search_cp'
for x in range(5):
    
    params = {
    'ct':'24',
    'qqmusic_ver': '1298',
    'new_json':'1',
    'remoteplace':'sizer.yqq.song_next',
    'searchid':'64405487069162918',
    't':'0',
    'aggr':'1',
    'cr':'1',
    'catZhida':'1',
    'lossless':'0',
    'flag_qc':'0',
    'p':str(x+1),
    'n':'20',
    'w':'周杰伦',
    'g_tk':'5381',
    'loginUin':'0',
    'hostUin':'0',
    'format':'json',
    'inCharset':'utf8',
    'outCharset':'utf-8',
    'notice':'0',
    'platform':'yqq.json',
    'needNewCode':'0'    
    }
    # 将参数封装为字典
    res_music = requests.get(url,params=params)
    # 调用get方法,下载这个字典
    json_music = res_music.json()
    # 使用json()方法,将response对象,转为列表/字典
    list_music = json_music['data']['song']['list']
    # 一层一层地取字典,获取歌单列表
    for music in list_music:
    # list_music是一个列表,music是它里面的元素
        print(music['name'])
        # 以name为键,查找歌曲名
        print('所属专辑:'+music['album']['name'])
        # 查找专辑名
        print('播放时长:'+str(music['interval'])+'秒')
        # 查找播放时长
        print('播放链接:https://y.qq.com/n/yqq/song/'+music['mid']+'.html\n')
        # 查找播放链接

打开Network,选中All,点击刷新。第0个请求一般都会是html。我们点开第0个请求来看看(看Preview或Response都可以),里面有没有我们想要的评论信息。如果没有找到就去看XHR,常规来说我们有两种方法来寻找XHR:阅读它们的name看看哪个可能是评论;或者是一个一个翻。
介绍一个简单的小技巧:先把Network面板清空,再点击一下评论翻页,看看有没有多出来的新XHR,多出来的那一个,就应该是和评论相关的啦。
在这里插入图片描述
总结技巧:
在这里插入图片描述
我们点开这个请求的Preview,能够在[‘comment’][‘commentlist’]里找到评论列表。列表的每一个元素都是字典,字典里键rootcommentcontent对应的值,就是我们要找的评论。
剩下的事情就简单了。我们去模拟这个请求,解析json,提取想要的内容就好。
点击Headers,在General里看链接,在Query String Parametres里看参数,多翻几页评论列表,总结参数的规律。
XHR有两个参数在不断变化:一个是pagenum,一个lasthotcommentid。其中pagenum好理解,就是页码,但是lastcommentid是什么?
我们来阅读这个英文lasthotcommentid,它的含义是:上一条热评的评论id。基于此,我们可以做一个猜想:每一页的请求,参数lasthotcommentid的值,是上一页的最后一条评论,所对应的id。

import requests
# 引用requests模块
url = 'https://c.y.qq.com/base/fcgi-bin/fcg_global_comment_h5.fcg'
commentid = ''
# 设置一个初始commentid
for x in range(5):
    
    params = {
    'g_tk':'5381',
    'loginUin':'0',
    'hostUin':'0',
    'format':'json',
    'inCharset':'utf8',
    'outCharset':'GB2312',
    'notice':'0',
    'platform':'yqq.json',
    'needNewCode':'0',
    'cid':'205360772',
    'reqtype':'2',
    'biztype':'1',
    'topid':'102065756',
    'cmd':'8',
    'needcommentcrit':'0',
    'pagenum':str(x),
    'pagesize':'25',
    'lasthotcommentid':commentid,
    'domain':'qq.com',
    'ct':'24',
    'cv':'101010  '
    }
    # 将参数封装为字典,其中pagenum和lastcommentid是特殊的变量
    res_comment = requests.get(url,params=params)
    # 调用get方法,下载评论列表
    json_comment = res_comment.json()
    # 使用json()方法,将response对象,转为列表/字典
    list_comment = json_comment['comment']['commentlist']
    # 一层一层地取字典,获取评论列表
    for comment in list_comment:
    # list_comment是一个列表,comment是它里面的元素
        print(comment['rootcommentcontent'])
        # 输出评论
    commentid = list_comment[24]['commentid']
    # 将最后一个评论的id赋值给comment,准备开始下一次循环

这样写好像也可以,可以忽略掉lasthotcommentid

import requests
# 引用requests模块
url = 'https://c.y.qq.com/base/fcgi-bin/fcg_global_comment_h5.fcg'
#commentid = ''
# 设置一个初始commentid
for x in range(2):
    
    params = {
    'g_tk':'5381',
    'loginUin':'0',
    'hostUin':'0',
    'format':'json',
    'inCharset':'utf8',
    'outCharset':'GB2312',
    'notice':'0',
    'platform':'yqq.json',
    'needNewCode':'0',
    'cid':'205360772',
    'reqtype':'2',
    'biztype':'1',
    'topid':'102065756',
    'cmd':'8',
    'needcommentcrit':'0',
    'pagenum':str(x),
    'pagesize':'25',
    'lasthotcommentid':'',
    'domain':'qq.com',
    'ct':'24',
    'cv':'101010  '
    }
    # 将参数封装为字典,其中pagenum和lastcommentid是特殊的变量
    res_comment = requests.get(url,params=params)
    # 调用get方法,下载评论列表
    json_comment = res_comment.json()
    # 使用json()方法,将response对象,转为列表/字典
    list_comment = json_comment['comment']['commentlist']
    # 一层一层地取字典,获取评论列表
    for comment in list_comment:
    # list_comment是一个列表,comment是它里面的元素
        print(comment['rootcommentcontent']+'\n')
        # 输出评论
    #commentid = list_comment[24]['commentid']
    # 将最后一个评论的id赋值给comment,准备开始下一次循环

五、Request Headers

如果有一天,你真的需要爬取这一万多条评论,将for循环执行成百上千次。
那么,你最好将自己的爬虫伪装成真实的浏览器——因为在这种情况下,服务器很可能拒绝爬虫访问。甚至有的网站,一开始就不允许爬虫访问。如,知乎、猫眼电影。
服务器通过什么识别我们是真实浏览器,还是Python爬虫的呢?
在这里插入图片描述
每一个请求,都会有一个Requests Headers,我们把它称作请求头。它里面会有一些关于该请求的基本信息,比如:这个请求是从什么设备什么浏览器上发出?这个请求是从哪个页面跳转而来?
如上图,user-agent会记录你电脑的信息和浏览器版本(如我的,就是windows10的64为操作系统,使用谷歌浏览器)。origin和referer则记录了这个请求,最初的起源是来自哪个页面。它们的区别是referer会比origin携带的信息更多些。
如果我们想告知服务器,我们不是爬虫是一个正常的浏览器,就要去修改user-agent。倘若不修改,那么这里的默认值就会是Python,会被浏览器认出来。
而对于爬取某些特定信息,也要求你注明请求的来源,即origin或referer的内容。比如我有试过,在爬取歌曲详情页里的歌词时,就需要注明这个信息,否则会拿不到歌词。你可以在写练习的时候进行尝试。
如何添加Requests Headers?
Requests模块允许我们去修改Headers的值。点击它的官方文档,搜索“user-agent”,你会看到:
在这里插入图片描述
如上,只需要封装一个字典就好了。和写params非常相像。
而修改origin或referer也和此类似,一并作为字典写入headers就好。就像这样:

import requests
url = 'https://c.y.qq.com/base/fcgi-bin/fcg_global_comment_h5.fcg'
# 这是那个,请求歌曲评论的url
headers = {
    'origin':'https://y.qq.com',
    # 请求来源,本案例中其实是不需要加这个参数的,只是为了演示
    'referer':'https://y.qq.com/n/yqq/song/004Z8Ihr0JIu5s.html',
    # 请求来源,携带的信息比“origin”更丰富,本案例中其实是不需要加这个参数的,只是为了演示
    'user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36',
    # 标记了请求从什么设备,什么浏览器上发出
    }
params = {
'g_tk':'5381',
'loginUin':'0',
'hostUin':'0',
'format':'json',
'inCharset':'utf8',
'outCharset':'GB2312',
'notice':'0',
'platform':'yqq.json',
'needNewCode':'0',
'cid':'205360772',
'reqtype':'2',
'biztype':'1',
'topid':'102065756',
'cmd':'8',
'needcommentcrit':'0',
'pagenum':0,
'pagesize':'25',
'lasthotcommentid':'',
'domain':'qq.com',
'ct':'24',
'cv':'101010  '
    }

res_music = requests.get(url,headers=headers,params=params)

爬取前五页歌词:

import requests

for i in range(1,6):
        res=requests.get('https://c.y.qq.com/soso/fcgi-bin/client_search_cp?ct=24&qqmusic_ver=1298&remoteplace=txt.yqq.lyric&searchid=91763561204056573&aggr=0&catZhida=1&lossless=0&sem=1&t=7&p={}&n=5&w=%E5%91%A8%E6%9D%B0%E4%BC%A6&g_tk=1676601595&loginUin=835926124&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8&notice=0&platform=yqq.json&needNewCode=0'.format(i))
        lyric=res.json()
        contents=lyric['data']['lyric']['list']
        for content in contents:
                print(content['content'].replace('\\n','\n'))#\\n表示真的\n字符而不是换行符,将歌词中的\n替换成换行符。
                print('---------------------------------')


  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值