【python爬虫】6.爬虫实操(带参数请求数据)

文章目录

  • 前言
  • 项目:狂热粉丝
  • 分析过程
    • 什么是带参数请求数据
    • 如何带参数请求数据
  • 代码实现
  • 被隐藏的歌曲清单
    • 什么是Request Headers
    • 如何添加Request Headers
  • 复习

前言

先来复习一下上一关的主要知识吧,先热个身。

Network能够记录浏览器的所有请求。我们最常用的是:ALL(查看全部)/XHR(仅查看XHR)/Doc(Document,第0个请求一般在这里),有时候也会看看:Img(仅查看图片)/Media(仅查看媒体文件)/Other(其他)。最后,JS和CSS,则是前端代码,负责发起请求和页面实现;Font是文字的字体;而理解WS和Manifest,需要网络编程的知识,倘若不是专门做这个,你不需要了解。

在这里插入图片描述
在Network,有非常重要的一类请求是XHR(或Fetch),因为有它的存在,人们不必刷新/跳转网页,即可加载新的内容。随着技术发展,XHR的应用频率越来越高,我们常常需要在这里找我们想要的数据。

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

如何解析json数据?答案如下:

在这里插入图片描述
总之,在上一关,我们最后把代码写成这副模样:

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\n')# 查找播放链接

项目:狂热粉丝

我们接着上一关说,如果仅仅只是拿到20首歌曲的相关信息,实际上并不能让一个狂热的粉丝感到喜悦。他会在心里呐喊:“我,全都要!”

那就全都给他吧!在这一关,我们要完成的项目是:让上一关的代码得到进化,使它能爬取很多很多歌曲,而不只是爬取20个。

但是,在这之前,我们会以歌曲《七里香》作为案例,去爬取它的歌曲评论:

在这里插入图片描述
在Get到“爬取《七里香》评论”的技能后,我们会再回到爬取更多歌曲的项目当中。就好像你在玩游戏时,会先到新手村杀小怪涨经验再出村解锁新地图一样,爬取评论就是我们用来练手的“新手村”。

当然了,如果你开心,我们还可以把“爬取歌词”作为本关卡的练习。

在这个过程当中,我们会学到带参数请求数据的知识,以及关于Request Headers的知识。此刻你或许还不清楚我在说什么,没关系,答案很快会揭晓。

分析过程

你可能会疑惑,为什么不能直接爬取周杰伦的更多歌曲,来吧,先来打开偶像的qq音乐搜索链接:

https://y.qq.com/portal/search.html#page=1&searchid=1&remoteplace=txt.yqq.top&t=song&w=%E5%91%A8%E6%9D%B0%E4%BC%A6

如果仔细观察页面的内容,你可能会摇摇头,认为爬取更多的歌曲信息是一个不可能完成的任务,因为如今的qq音乐已经不支持更多歌曲的翻阅功能,正常访问的途径都没有了,我们的“虫”(代码)上哪爬取去?

在这里插入图片描述
退而求其次,咱们来看看评论这边的情况,目前qq音乐的评论页面结构是这样的:

在这里插入图片描述
评论区分成了两部分,分别是精彩评论和最新评论,精彩评论可以通过点击加载更多获得更多数据,最新评论则需要翻页来进行数据更新。

也就是说,爬取更多的评论数据的难点似乎在翻页和点击加载更多。

显然这种数据的加载模式还是我们上一关熟悉的“动态加载”,即点击一个按钮(加载更多或者第n页),服务器就会根据新的XHR更新页面信息。

这样一来,若我们想要获得更多的评论数据,就需要:1️⃣点击按钮获得新的XHR 2️⃣根据新的XHR获得json数据 3️⃣解析json数据,如此循环往复,直至精神崩溃。

如果python有情绪,它的脸上现在肯定写满了嫌弃和拒绝。所以,看在python的面上,只要我们能找到每个请求之间的规律,这种重复的工作就交给它了好吗?

相比较爬取我们“看不见”(更多歌曲信息)的数据,评论这个能通过点击页码或加载更多按钮看到更多数据的“柿子”看起来比较软一点,就先捏它吧~

不过,解决评论的问题,需要用到“带参数请求数据”。学会这个,所有的问题都不再是问题。

什么是带参数请求数据

我不知道你有没有认真地观察过一个完整url的组成,如果没有,我们现在来试试看:

当你在豆瓣搜索“海边的卡夫卡”,它的网址会是这样:

https://www.douban.com/search?q=%E6%B5%B7%E8%BE%B9%E7%9A%84%E5%8D%A1%E5%A4%AB%E5%8D%A1

当你在知乎搜索“宇宙大爆炸”,它的网址会是这样:

https://www.zhihu.com/search?type=content&q=%E5%AE%87%E5%AE%99%E5%A4%A7%E7%88%86%E7%82%B8

现在,我要揭晓规律:

在上面,我们能看到每个url都由两部分组成。前半部分大多形如:https://xx.xx.xxx/xxx/xxx

后半部分,多形如:xx=xx&xx=xxx&xxxxx=xx&……

两部分使用?来连接。举例刚刚的豆瓣网址,前半部分就是:

icon
https://www.douban.com/search

icon
后半部分则是:q=%E6%B5%B7%E8%BE%B9%E7%9A%84%E5%8D%A1%E5%A4%AB%E5%8D%A1

它们的中间使用了?来隔开。

这前半部分是我们所请求的地址,它告诉服务器,我想访问这里。而后半部分,就是我们的请求所附带的参数,它会告诉服务器,我们想要什么样的数据。

这参数的结构,会和字典很像,有键有值,键值用=连接;每组键值之间,使用&来连接。

就像豆瓣。我们请求的地址是https://www.douban.com/search

而我们的请求所附带的参数是“海边的卡夫卡”:q=%E6%B5%B7%E8%BE%B9%E7%9A%84%E5%8D%A1%E5%A4%AB%E5%8D%A1(那段你看不懂的代码,它是“海边的卡夫卡”使用utf-8编码的结果)。

技能点学满了吧?那现在,我们要以《七里香》为例,爬取用户的精彩评论。

首先,进入网址:

https://y.qq.com/n/yqq/song/004Z8Ihr0JIu5s.html

打开Network,选中All,点击刷新。

在这里插入图片描述
上一关我们说到,第0个请求一般都会是html。我们点开第0个请求来看看(看Preview或Response都可以),看里面有没有我们想要的评论信息。

显然是没有的。我们现在去看XHR。

在这里插入图片描述
这次的XHR还挺多,有四五十个。常规来说我们有两种方法来寻找XHR:阅读它们的name看看哪个可能是评论;或者是一个一个翻。

现在再给你介绍一个简单的小技巧:先把Network面板清空,再点击一下精彩评论的点击加载更多,看看有没有多出来的新XHR,多出来的那一个,就应该是和评论相关的啦。

在这里插入图片描述

总结这个技巧,就是:

在这里插入图片描述
我们点开这个请求的Preview,能够在[‘comment’][‘commentlist’]里找到评论列表。列表的每一个元素都是字典,字典里键rootcommentcontent对应的值,就是我们要找的评论。

在这里插入图片描述

好嘞,于是我们就在找到拥有评论数据的页面链接(请求的Headers栏:General中的Request URL):

https://c.y.qq.com/base/fcgi-bin/fcg_global_comment_h5.fcg?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=6&needmusiccrit=0&pagenum=1&pagesize=15&lasthotcommentid=song_102065756_3202544866_44059185&domain=qq.com&ct=24&cv=10101010

显然,这样一个长链接,阅读体验非常之差。Network面板提供了一个更友好的查看方式,我来带你看看它。

回到上面我们找到XHR的地方,选中Headers,保持General打开,保持Response Headers和Request Headers关闭。我们点开Query String Parameters。

在这里插入图片描述
它里面的内容有没有感觉眼熟?正是链接请求中所附带的参数,对吧!Query String Parameters,它的中文翻译是:查询字符串参数。

这个面板用类似字典的形式,呈现了各个参数的键值,阅读体验会好一些。我们可以常来此处看看。

如何带参数请求数据

在上一关当中,我们直接用requests.get()请求了url。在这一关,如果我们想拿到更多精彩评论。就要读懂url的各个参数。修改它们,重新发起请求。

读懂参数,有两个重要的方法是“观察”和“比较”。“观察”指的是阅读参数的键与值,尝试理解它的含义。“比较”指的是比较两个相近的XHR——它们有哪些不同,对应的页面显示内容有什么不同。

现在,我们来观察比较,依然在“七里香”的歌曲详情页,点击精彩评论的点击加载更多按钮,此时Network会多加载出更多的XHR,但是Name为fcg_global_comment_h5…才是我们关心的XHR。

在这里插入图片描述
分别点开它们的Query String Parameters,比较参数之间有什么不同。点击Enter(回车)键,告诉你答案。

在这里插入图片描述
事实上答案已经很明显了,只要我们多点耐心就会发现,链接的众多参数中,只有一个参数在变化。这个参数是pagenum,第一次点击加载更多的值为1,第二第三次点击它的值就变成了2和3。

当然,pagenum这个复合英文本身也说明了问题,指的可不就是页码嘛!也就是说,pagenum=1等于告诉服务器:我要歌曲信息列表第一页的数据,pagenum=2:我要歌曲信息列表第二页的数据。

这样一来,按照之前学的知识,你大约会想:我们写一个循环,每次循环都去更改pagenum的值,这样不就能实现爬取好多好多精彩评论了吗?

代码实现

你可以尝试这样做,来,请书写代码,实现这一点。备注:虽然这样能爬到我们的数据,但我并不推荐你在课堂里把所有的评论都爬取下来。一来是等待时间较长,二来虽然QQ音乐没有对爬虫做限制,但是我们也应该尽可能减少对服务器的压力。所以,循环不要超过5个。

参考代码:

import requests
# 引用requests模块
for n in range(1,6):res_comments = requests.get('https://c.y.qq.com/base/fcgi-bin/fcg_global_comment_h5.fcg?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=6&needmusiccrit=0&pagenum='+str(n)+'&pagesize=15&lasthotcommentid=song_102065756_3202544866_44059185&domain=qq.com&ct=24&cv=10101010')# 调用get方法,下载评论列表json_comments = res_comments.json()# 使用json()方法,将response对象,转为列表/字典list_comments = json_comments['comment']['commentlist']# 一层一层地取字典,获取评论列表for comment in list_comments:# list_comments是一个列表,comment是它里面的元素print(comment['rootcommentcontent'])# 输出评论print('-----------------------------------')# 将不同的评论分隔开来

有点不太对劲,发生了什么?!

如果你单独把那些评论收集起来,会发现:相同的评论出现了5次。

也就是说,我们并没有通过循环修改pagenum的值,获取到后面的评论,而是将第一页的评论循环爬取了5次。

这是怎么回事呢?要怎么才能真正爬取到后续的精彩评论呢?

好吧,这是前端的一种特殊的处理机制,这里的pagenum并不是实际意义上的页码。真正令更多精彩评论展示发挥作用的字段其实是pagesize。

如果你想获得前5页的内容?那就相当于15 * 5 = 75条评论,也就是pagesize = 75。

那么应该怎么修改呢,请想一想。

参考代码:

import requests
# 引用requests模块res_comments = requests.get('https://c.y.qq.com/base/fcgi-bin/fcg_global_comment_h5.fcg?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=6&needmusiccrit=0&pagenum=1&pagesize=75&lasthotcommentid=song_102065756_3202544866_44059185&domain=qq.com&ct=24&cv=10101010')
# 调用get方法,下载评论列表
json_comments = res_comments.json()
# 使用json()方法,将response对象,转为列表/字典
list_comments = json_comments['comment']['commentlist']
# 一层一层地取字典,获取评论列表
for comment in list_comments:
# list_comments是一个列表,comment是它里面的元素print(comment['rootcommentcontent'])# 输出评论print('-----------------------------------')# 将不同的评论分隔开来

运行一下,是不是可以了?
这样写代码,的确能够完成我们的目标。只是修改链接的参数实在太麻烦了,显然不够优雅,因为它实在太长了。

素有“人工智能之父”的唐纳德·克努特(Donald Ervin Knuth)讲过一句话让我印象深刻,他说:代码写出来是让人读的,只是顺便拿去让机器执行。

在这里插入图片描述
我们来让这个代码变好看些。事实上,requests模块里的requests.get()提供了一个参数叫params,可以让我们用字典的形式,把参数传进去。它的官方文档,是这样描述:

在这里插入图片描述
所以,其实我们可以把Query String Parameters里的内容,直接复制下来,封装为一个字典,传递给params。只是有一点要特别注意:要给他们打引号,让它们变字符串。

所以,代码最后可能长这样:

import requests
# 引用requests模块
url = 'https://c.y.qq.com/base/fcgi-bin/fcg_global_comment_h5.fcg'
# 请求歌曲评论的url参数的前面部分for i 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':'6','needmusiccrit':'0','pagenum':str(i),'pagesize':'15','lasthotcommentid':'song_102065756_3202544866_44059185','domain':'qq.com','ct':'24','cv':'10101010'   }# 将参数封装为字典res_comments = requests.get(url,params=params)# 调用get方法,下载这个字典json_comments = res_comments.json()list_comments = json_comments['comment']['commentlist']for comment in list_comments:print(comment['rootcommentcontent'])print('-----------------------------------')

你可以尝试运行它试试看:
怎么样,这样是不是也可以正常运行!

被隐藏的歌曲清单

好了,现在回到一开始遇到的难题:我想要爬取周杰伦更多的歌曲信息,但是qq音乐告诉我:想要查看更多内容,请下载一个客户端。

在这里插入图片描述
这一次,我们所向披靡的爬虫难道踢到了钢板,从此要金盆洗脚息步于江湖?

作为一名忠实的狂热粉丝,再挣扎一下吧!

前面我们提到,一个完整url是由两部分组成的,前半部分大多形如:https://xx.xx.xxx/xxx/xxx,后半部分则是xx=xx&xx=xxx&xxxxx=xx&,中间有时候会用?来连接。

来看看我们搜索的首页:

https://y.qq.com/portal/search.html#page=1&searchid=1&remoteplace=txt.yqq.top&t=song&w=周杰伦

不出所料,这个链接的前半部分是https://y.qq.com/portal/search.html,后半部分是page=1&searchid=1&remoteplace=txt.yqq.top&t=song&w=周杰伦,然而,分隔这两部分的符号不是?,而是#。

其实在这里,#和?的功能是一样的,作用都是分隔,若把链接的#替换成?,访问的效果是一样的(注意:用?分隔的url不一定可以用#代替)。

既然如此,我们是不是可以跟前面一样,对参数下手了呢?

观察一下后半部分的参数
page=1&searchid=1&remoteplace=txt.yqq.top&t=song&w=周杰伦,page(中文:页面),searchid(中文:搜索id),remoteplace(中文:远程位置),后面的t和w这俩参数虽然不知道是什么,但根据他们的值(song和周杰伦)可窥得一斑,应该是指类型和关键字。

前面我们在爬取评论的时候知道,改变pagenum就可以加载更多的数据。举一反三,试想,如果改变搜索页面(https://y.qq.com/portal/search.html#page=1&searchid=1&remoteplace=txt.yqq.top&t=song&w=周杰伦)的page这个参数我们是否可以访问到其他页面的数据呢?

在这里插入图片描述
为了验证猜想,老师将网页链接中的page=1改成了page=2,果然就访问到了下一页数据,嘿嘿嘿,来吧,可以造作起来了!

还记得更快查找XHR的骚操作吗?1️⃣先把Network面板清空,2️⃣再修改page值按回车键,3️⃣查看Network多出来的新XHR,也就是这个client_search_cp…。

剩下的事情就简单了,重复上面的步骤,找到Headers,找到最下面的client_search_cp…,点开Query String Parameters,观察参数的变化规律。

找到了吗?

实际上,p值和searchid都在变化,但通过前面的网页测试来看,searchid的值都为1仍然成功翻页,由此可知,searchid的变化并不影响大局。

关键来看p值的变化:

在这里插入图片描述
这个参数是p,第1页XHR的参数p值为1,第2、3页XHR的参数p值则为2和3,说明在这个client_search_cp…的请求中,代表页码的参数是p(page的缩写)。

依然是爬取歌曲的相关信息(歌曲名、所属专辑、播放时长、播放链接),只不过这一次,可以爬取的可不止是第一页的数据。

如此,代码应该如下(同上,不推荐循环超过5次):

# 直接运行代码就好
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':'59091538798969282','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\n')# 查找播放链接

运行结果(节选部分)

退后
所属专辑:依然范特西
播放时长:261秒
播放链接:https://y.qq.com/n/yqq/song/001L1lqm4UAdyo.html最长的电影
所属专辑:我很忙
播放时长:235秒
播放链接:https://y.qq.com/n/yqq/song/003ZrdgZ0UnjDl.html发如雪
所属专辑:十一月的萧邦
播放时长:299秒
播放链接:https://y.qq.com/n/yqq/song/0027oMO61wWi55.html夜的第七章
所属专辑:依然范特西
播放时长:228秒
播放链接:https://y.qq.com/n/yqq/song/0010ibBn4bYFTk.html我不配
所属专辑:我很忙
播放时长:288秒
播放链接:https://y.qq.com/n/yqq/song/001T3JAT15palI.html爱在西元前
所属专辑:范特西
播放时长:234秒
播放链接:https://y.qq.com/n/yqq/song/002usg9o4GTAKf.html彩虹
所属专辑:我很忙
播放时长:263秒
播放链接:https://y.qq.com/n/yqq/song/004bRWFg3fej9y.html本草纲目
所属专辑:依然范特西
播放时长:209秒
播放链接:https://y.qq.com/n/yqq/song/001bo9Wy1NfHpb.html说好不哭(with 五月天阿信)
所属专辑:说好不哭(with 五月天阿信)
播放时长:222秒
播放链接:https://y.qq.com/n/yqq/song/001qvvgF38HVc4.html反方向的钟
所属专辑:Jay
播放时长:258秒
播放链接:https://y.qq.com/n/yqq/song/0017K7gL4WYnw2.html阳光宅男
所属专辑:我很忙
播放时长:222秒
播放链接:https://y.qq.com/n/yqq/song/001bnNGN127Kbq.html龙卷风
所属专辑:Jay
播放时长:250秒
播放链接:https://y.qq.com/n/yqq/song/002l8JN71d2Dxy.htmlMojito
所属专辑:Mojito
播放时长:185秒
播放链接:https://y.qq.com/n/yqq/song/001glaI72k8BQX.html我是如此相信
所属专辑:我是如此相信
播放时长:266秒
播放链接:https://y.qq.com/n/yqq/song/001PLl3C4gPSCI.html不该 (with aMEI)
所属专辑:周杰伦的床边故事
播放时长:290秒
播放链接:https://y.qq.com/n/yqq/song/000sxzol11raSd.html屋顶
所属专辑:K情歌10
播放时长:319秒
播放链接:https://y.qq.com/n/yqq/song/001wXiwd0eRSes.html周大侠
所属专辑:2007世界巡回演唱会
播放时长:134秒
播放链接:https://y.qq.com/n/yqq/song/003nLOYI4gJ6U0.html晴天
所属专辑:周杰伦地表最强世界巡回演唱会
播放时长:249秒
播放链接:https://y.qq.com/n/yqq/song/004Fs2FP1EvZYc.html兰亭序
所属专辑:2011年春节联欢晚会歌曲
播放时长:240秒
播放链接:https://y.qq.com/n/yqq/song/004bsJxD1n2Gjk.html断了的弦
所属专辑:寻找周杰伦
播放时长:297秒
播放链接:https://y.qq.com/n/yqq/song/003ZdxP61ClQZ5.html黑色毛衣
所属专辑:十一月的萧邦
播放时长:252秒
播放链接:https://y.qq.com/n/yqq/song/003iY6cU4YG0xi.html我落泪情绪零碎
所属专辑:跨时代
播放时长:257秒
播放链接:https://y.qq.com/n/yqq/song/0022b7OX2STU86.html暗号
所属专辑:八度空间
播放时长:271秒
播放é¾接:https://y.qq.com/n/yqq/song/000NQDjk4BA0W3.html开不了口
所属专辑:范特西
播放时长:284秒
播放链接:https://y.qq.com/n/yqq/song/0020qX4u2JJRxK.html借口
所属专辑:七里香
播放时长:260秒
播放链接:https://y.qq.com/n/yqq/song/002XWgfo0IKPOH.html说了再见
所属专辑:跨时代
播放时长:282秒
播放链接:https://y.qq.com/n/yqq/song/00265Jxe3JzXOJ.html大笨钟
所属专辑:十二新作
播放时长:242秒
播放链接:https://y.qq.com/n/yqq/song/002jkBM53MLB9Q.html甜甜的
所属专辑:我很忙
播放时长:243秒
播放链接:https://y.qq.com/n/yqq/song/000xdZuV2LcQ19.html回到过去
所属专辑:八度空间
播放时长:233秒
播放链接:https://y.qq.com/n/yqq/song/003rxgIM2eOFSF.html

悄悄地告诉你,如果你将这个代码里’w’关键字参数值换成另一个歌手/歌曲名,那么它也能爬到这个歌手/同名歌曲的信息。如果你愿意,可以在本关卡结束后,练习做这件事。

当然,qq音乐的产品经理肯定是不希望我们能访问到第2页的内容,他们更希望我们能下载客户端,从客户端访问数据。

为此,服务器就可能会对我们这些“投机取巧”的爬虫做限制处理。一来可以降低服务器的访问压力,毕竟成千上万次的访问对代码来说就是一个for循环的事儿;二来可以拦截那些想要通过爬虫窃取数据的竞争者。

那这就有一个问题,服务器怎么判断访问者是一个普通的用户(通过浏览器),还是一个爬虫者(通过代码)呢?

这需要我们回到浏览器中,重新认识一个新的信息栏:请求头Request Headers。

什么是Request Headers

就是这个:

在这里插入图片描述

每一个请求,都会有一个Request Headers,我们把它称作请求头。它里面会有一些关于该请求的基本信息,比如:这个请求是从什么设备什么浏览器上发出?这个请求是从哪个页面跳转而来?

如上图,user-agent(中文:用户代理)会记录你电脑的信息和浏览器版本(如我的,就是windows10的64位操作系统,使用谷歌浏览器)。

origin(中文:源头)和referer(中文:引用来源)则记录了这个请求,最初的起源是来自哪个页面。它们的区别是referer会比origin携带的信息更多些。

如果我们想告知服务器,我们不是爬虫,而是一个正常的浏览器,就要去修改user-agent。倘若不修改,那么这里的默认值就会是Python,会被服务器认出来。

有趣的是,像百度的爬虫,它的user-agent就会是Baiduspider,谷歌的也会是Googlebot……如是种种。

而对于爬取某些特定信息,也要求你注明请求的来源,即origin或referer的内容。比如我有试过,在爬取歌曲详情页里的歌词时,就需要注明这个信息,否则会拿不到歌词。你可以在写练习的时候进行尝试。

如何添加Request Headers

Requests模块允许我们去修改Headers的值。点击它的官方文档,搜索“user-agent”,你会看到:

在这里插入图片描述
如上,只需要封装一个字典就好了。和写params非常相像。

而修改origin或referer也和此类似,一并作为字典写入headers就好。就像这样:

import requests
url = 'https://c.y.qq.com/soso/fcgi-bin/client_search_cp'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 = {
'ct':'24',
'qqmusic_ver': '1298',
'new_json':'1',
'remoteplace':'sizer.yqq.song_next',
'searchid':'59091538798969282',
't':'0',
'aggr':'1',
'cr':'1',
'catZhida':'1',
'lossless':'0',
'flag_qc':'0',
'p':'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,headers=headers,params=params)
# 发起请求,填入请求头和参数

鉴于这个代码你已经写过也运行过,所以在这里我们不再做练习。 只需要记得Request Headers(请求头)的含义和用法就好。

如果有一天,你真的需要爬取一万多条信息,将for循环执行成百上千次。

那么,你最好将自己的爬虫伪装成真实的浏览器(填写请求头)—— 因为在那种情况下,服务器很可能拒绝爬虫访问。甚至有的网站,一开始就不允许爬虫访问。如,知乎、猫眼电影。

复习

在本关卡,我们主要学习了带参数请求数据和Request Headers的用法。

对于前者,我们认识到一个url由两部分组成,?(有时候是“#”)之前是我们请求的地址,?之后是我们的请求所附带的参数。通常,我们会把参数封装成一个字典,添加进请求中去。

通过对参数进行修改,我们能爬到许多信息。

大约在第8关,我们还会学习另一种数据请求的类型post,它区别于我们今天所使用的get请求,但用法却是大同小异。

而对于后者,Request Headers,我们把它称作请求头。它里面会有一些关于该请求的基本信息,比如:这个请求是从什么设备什么浏览器上发出?这个请求是从哪个页面跳转而来?

它最大的应用是帮助我们应对“反爬虫”技术,将Python爬虫伪装成真正的浏览器,不为服务器所辨识;同时也可以标记这个请求的来源是什么,最终帮助我们拿到想要的信息。

除此之外,我们还通过项目实操,学会如何判断我们想要的信息是在Html,还是在XHR里:

在这里插入图片描述
利用这张图来分析网页,你能找到几乎所有你想要的信息。剩下的,只是请求、解析、提取、存储罢了。其中解析和提取你已经学过,存储我们将在下一关学习。在未来,我们会学习更多的请求方式,更快的请求方式。

最后用一个代码复习本关卡所学,就是:

import requests
url = 'https://c.y.qq.com/soso/fcgi-bin/client_search_cp'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 = {
'ct':'24',
'qqmusic_ver': '1298',
'new_json':'1',
'remoteplace':'sizer.yqq.song_next',
'searchid':'59091538798969282',
't':'0',
'aggr':'1',
'cr':'1',
'catZhida':'1',
'lossless':'0',
'flag_qc':'0',
'p':'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,headers=headers,params=params)
# 发起请求,填入请求头和参数

我们下一关见!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/61505.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

React Navigation 使用导航

在 Web 浏览器中,您可以使用锚标记链接到不同的页面。当用户单击链接时,URL 会被推送到浏览器历史记录堆栈中。当用户按下后退按钮时,浏览器会从历史堆栈顶部弹出该项目,因此活动页面现在是以前访问过的页面。React Native 不像 W…

AZ900备考

文章目录 云服务的概念云服务模型云服务类型消费的模型云服务的好处可靠性和可预测性的优势云中的管理 Azure 体系结构和服务核心结构组件物理基础结构组件 Azure计算和网络服务Azure 存储服务身份认证AD身份认证 Azure 管理和治理成本管理治理合规性的功能和工具管理和部署Azu…

代码随想录算法训练营第17期第34天 | 1005. K 次取反后最大化的数组和、134. 加油站、135. 分发糖果

1005. K 次取反后最大化的数组和 这里说一下卡哥和我的区别,基本思路是一样的, 只是卡哥这里只需要一次排序,而我这边排了两次; 卡哥思路: 1.按照绝对值大小从大到小排序 2.从前往后遍历,遇到负数将其转…

喷泉码浅谈

01、喷泉码简介 喷泉码(Fountain Code)是一种在无线通信、数据传输和网络编码领域中使用的错误纠正技术。它与传统的纠错码和编码方法有所不同,喷泉码被设计用于在不确定信道条件下的高效数据传输。传统的纠错码(如海明码、RS码等…

MAC苹果电脑如何压缩rar文件?

作为开发者,想必主力开发机肯定都以苹果的MacBook为主,究其原因,为非是因为其对开发者的友好性,且可同时进行iOS 以及android的app开发,但是windows在这方面就欠缺太多了,虽然很多人说可以使用,…

Linux服务器部署JavaWeb后端项目

适用于:MVVM前后台分离开发、部署、域名配置 前端:Vue 后端:Spring Boot 这篇文章只讲后端部署,前端部署戳这里 目录 Step1:服务器上搭建后端所需环境1、更新服务器软件包2、安装JDK83、安装MySQL4、登录MySQL5、修…

可视化绘图技巧100篇基础篇(九)-子弹图(一)

目录 前言 适用场景 图例 绘图工具及代码实现 Excel绘制子弹图 Python绘制子弹图

钉钉消息已读、未读咋实现的嘞?

前言 一款app,消息页面有:钱包通知、最近访客等各种通知类别,每个类别可能有新的通知消息,实现已读、未读功能,包括多少个未读,这个是怎么实现的呢?比如用户A访问了用户B的主页,难道…

Kotlin的内置函数 apply、let、run、with、also

let 1.let函数返回类型,是根据匿名函数的最后一行变化而变化 2.let函数中的匿名函数里面持有的是it 集合自身 fun main() {var num1 1var num2 1var result:Intresult num1 num2var str result?.let {//传入本身,it指代本身即result,result不为空…

Mac下Docker Desktop安装命令行工具、开启本地远程访问

Mac系统下,为了方便在terminal和idea里使用docker,需要安装docker命令行工具,和开启Docker Desktop本地远程访问。 具体方法是在设置-高级下, 1.将勾选的User调整为System,这样不用手动配置PATH即可使用docker命令 …

Nuxt 菜鸟入门学习笔记五:CSS 样式

文章目录 本地样式表在组件内导入通过 Nuxt 配置 CSS 属性导入使用字体导入通过 NPM 发布的样式表 外部样式表动态添加样式表【高级】使用 Nitro 插件修改渲染的头部 使用预处理器单文件组件 SFC 样式类和样式绑定使用 v-bind 的动态样式Scoped StylesCSS Modules预处理器支持 …

基于Python+OpenCV智能答题卡识别系统——深度学习和图像识别算法应用(含Python全部工程源码)+训练与测试数据集

目录 前言总体设计系统整体结构图系统流程图 运行环境Python 环境PyCharm安装OpenCV环境 模块实现1. 信息识别2. Excel导出模块3. 图形用户界面模块4. 手写识别模块 系统测试1. 系统识别准确率2. 系统识别应用 工程源代码下载其它资料下载 前言 本项目基于Python和OpenCV图像处…

多重背包模板题,P1776 宝物筛选

题目描述 终于,破解了千年的难题。小 FF 找到了王室的宝物室,里面堆满了无数价值连城的宝物。 这下小 FF 可发财了,嘎嘎。但是这里的宝物实在是太多了,小 FF 的采集车似乎装不下那么多宝物。看来小 FF 只能含泪舍弃其中的一部分…

【SA8295P 源码分析】87 - SA8295P HQNX + Android 编译环境搭建指导

【SA8295P 源码分析】87 - SA8295P HQNX + Android 编译环境搭建指导 一、Android 编译环境搭建:Android + sa8295p-hqx-4-2-4-0_hlos_dev_la.tar.gz1.1 更新 Ubuntu 18.04 源路径1.2 安装基础编译环境1.3 设置JDK8 的环境变量1.4 配置sh为bash(默认为dash)1.5 Android 编译…

图像扭曲之旋转

源码: void twirl(cv::Mat& src,cv::Mat& dst,double angle,double radius) {dst.create(src.rows, src.cols, CV_8UC3);dst.setTo(0);int radius2radius*radius;int cx src.cols / 2;int cy src.rows / 2;int distance,distance2 0;for (int h 0; h &…

P13 VUE 二级menu实现

主要修改以下几个点&#xff1a; CommonAside.vue中 外层便利有孩子节点&#xff0c;关键词key是对应的标签&#xff0c;class动态图表渲染 内层遍历不能再用item&#xff0c;用subitem&#xff0c;遍历该item.childeren&#xff0c;关键词是path&#xff0c; <templat…

k8s etcd 简介

Etcd是CoreOS基于Raft协议开发的分布式key-value存储&#xff0c;可用于服务发现、共享配置以及一致性保障&#xff08;如数据库选主、分布式锁等&#xff09;。 如&#xff0c;Etcd也可以作为微服务的注册中心&#xff0c;比如SpringCloud也基于ETCD实现了注册中心功能&#…

dayjs格式转换成日期

目录 方法一&#xff1a; ​编辑方法二&#xff1a; 这个项目在筛选订单时间的时候是由前端进行筛选的&#xff0c;用的是adt-design-pro进行二开的&#xff0c;其中在用日期组件的时候遇到了一个问题&#xff0c;组件返回的是&#xff1a; 但是我需要的是年-月-日&#xff…

OpenCV中Mat、Ipllmage以及Halcon中Hobject数据类型之间转换

OpenCV中Mat、CVMat、Ipllmage类型都可以代表和显示图像。IplImage是由CVMat派生,而CvMat由CvArr派生即CvArr -> CvMat -> IplImage,Mat类型则是C++版本的矩阵类型(CvArr用作函数的参数,无论传入的是CvMat或IplImage,内部都是按CvMat处理)。 Mat类型侧重于计算,数…

计算机网络 第二节

目录 一&#xff0c;计算机网络的分类 1.按照覆盖范围分 2.按照所属用途分 二&#xff0c;计算机网络逻辑组成部分 1.核心部分 &#xff08;通信子网&#xff09; 1.1电路交换 1.2 分组交换 两种方式的特点 重点 2.边缘部分 &#xff08;资源子网&#xff09; 进程通信的方…