python爬虫基础Ⅱ——Ajax数据爬取、带参请求:QQ音乐歌单、QQ音乐评论
文章目录
- 基础爬虫部分Ⅱ
- Ajax技术
- json
- 1. Network
- 2. XHR怎么请求?
- 3. 什么是json?
- 4. json数据如何解析?
- 带参数请求
- 1. 复习
- 2. params
- 3. 添加Headers
- 根据输入的歌手名获得相应歌单信息
基础爬虫部分Ⅱ
Ajax技术
全称为Asynchronous JavaScript and XML
,即异步 JavaScript 和 XML。它不是一门编程语言,而是利用JS在保证页面不被刷新、页面链接不改变的情况下与服务器交换数据并更新部分网页的技术。
对于传统的网页,如果想更新其内容,那么必须要刷新整个页面(就是第一部分爬取的那种网页,也叫静态网页吧),但有了Ajax,便可以在页面不被全部刷新的情况下更新内容。
有时候我们在用requests
抓取页面的时候,在浏览器中可以看到正常显示页面数据,但爬取结果没有。这是因为requests
获取的都是原始的HTML文档,而浏览器中的页面都是经过JS处理数据后生成的结果。
比如有些网页下拉的时候经常有“正在加载更多”的字样,但是网页并无刷新,其实就是Ajax加载的过程。
待会下边要提到的QQ音乐网站,也是利用了这种技术。遇到这样的页面,直接用requests
等库来抓取原始页面,是无法获得到有效数据的。
json
有点不知从何说起,那我就乱来了鸭 XD
现在呢,我想获取QQ音乐里周杰伦的歌曲清单。按照前边说的,可能会写出这样的代码:
import requests
from bs4 import BeautifulSoupres_music = requests.get('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')
bs_music = BeautifulSoup(res_music.text,'html.parser')# 解析html
list_music = bs_music.find_all('a',class_='js_song')
# 查找class属性值为“js_song”的a标签,得到一个由标签组成的列表
for music in list_music:print(music['title'])# 打印出音乐名
但是程序运行的结果,是什么都找不到……为啥子呢,就要看下面说滴这个啦
1. Network
打开对应的网页:url(暂且叫这个网页为 url 好吧) = https://y.qq.com/portal/search.html#page=1&searchid=1&remoteplace=txt.yqq.top&t=song&w=周杰伦
然后F12,然后点击Network
(在 Element 那一列,我懒得截图了 TAT)。
Network
的功能是:记录在当前页面上发生的所有请求。现在看上去好像空空如也的样子,这是因为Network
记录的是实时网络请求。现在网页都已经加载完成,所以不会有东西。
刷新一下网页,浏览器会重新访问网络,这样就会有记录。哗~密密麻麻地出来了许多。
这个,正是我们的浏览器每时每刻工作的真相:它总是在向服务器,发起各式各样的请求。当这些请求完成,它们会一起组成我们在Elements
中看到的网页源代码。
而我们刚刚写的代码,只是模拟了这52个请求中的一个(准确来说,就是第0个请求),而这个请求里并不包含歌曲清单的。
当然也有一些网页,直接把所有的关键信息都放在第0个请求里,像前边爬取书本信息的网页就是这样的,我们要的信息就在url里。而这个歌曲清单是不在url里的。
那我们拿到一个要爬的url前,要怎么判断我们要的信息在不在里边呢?
那就点开第0个请求,再点Preview:
然后看看这里边的信息,确实是没有歌曲清单的呀,这也就说明歌曲清单不在url里。这也就是我前面说的,QQ音乐也是采用了Ajax技术的。 那到底在哪里呢?
其实,Ajax有其特殊的请求类型,它叫XHR(XHR and Fetch)。
先来粗略了解一哈:
对于我圈起来的,最常用的是:
ALL
(查看全部)
XHR
(仅查看XHR,会重点讲它)
Doc
(Document,第0个请求一般在这里)
有时候也会看看:
Img
(仅查看图片)
Media
(仅查看媒体文件)
Other
(其他)
最后,JS和CSS,则是前端代码,负责发起请求和页面实现;Font是文字的字体;而理解WS和Manifest,好像需要网络编程的知识,倘若不是专门做这个的不需要了解。(我菜死了)
那就去XHR里的请求找找喽~
2. XHR怎么请求?
看看XHR里请求有十几二十个左右吧,要从里面找出带有歌单的那一个,显然最有可能藏在client_search
请求里(客户端搜索嘛)……而且它最大,有10.9KB,点击它!
点击Preview
,你能在里面发现我们想要的信息:歌名就藏在里面!(只是有点难找,需要你一层一层展开:data-song-list-0-name
,然后你就可以看到“晴天”。也显然list里有10个元素,其实就是当前页面的10首歌曲信息。
那如何把这些歌曲名拿到呢?这就需要我们去看看最左侧的Headers
,点击它。如下所示,它被分为四个板块。
General
里的Requests URL
就是我们应该去访问的链接。如果在浏览器中打开这个链接,你会看到一个复杂的结构:最外层是一个字典,然后里面又是字典,往里面又有列表和字典……还是直接用Preview
来看就好。列表和字典在此都会有非常清晰的结构,层层展开,按照这样的顺序data-song-list
,又可以看到10个字典,歌曲名就在这10个字典里,而歌名是键为name
对应的value
。
如何得到这一个复杂的结构,还能把它像正常的字典/列表一样,一层一层的取出来?重点来了。
3. 什么是json?
json
是什么呢?粗暴地来解释,在Python语言当中,json
是一种特殊的字符串,这种字符串特殊在它的写法——它是用列表/字典的语法写成的。
a = '1,2,3,4'
# 这是字符串
b = [1,2,3,4]
# 这是列表
c = '[1,2,3,4]'
# 这是字符串,但它是用 json格式 写的字符串#引入json----------------------------------------
import jsona = [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的数据类型.
这种特殊的写法决定了,json
能够有组织地存储信息。
刚刚我们在XHR
里查看到的列表/字典,严格来说其实它不是列表/字典,它是json
。
4. json数据如何解析?
方法很简单,请求到数据之后,使用json()
方法即可成功读取。接下来的操作,就和列表/字典相一致。遇上聪明的你,相信我可以直接上代码了:
import requestsres_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¬ice=0&platform=yqq.json&needNewCode=0') # XHR里的URL才是我们需要数据所在的URLjson_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为键,查找歌曲名
事实上,如果对这个程序稍加延展,它就能拿到:歌曲名、所属专辑、播放时长,以及播放链接。因为这些信息都在那个XHR
里,聪明的你认真观察分析后,肯定很轻易就能做到。撒花撒花✿✿ヽ(°▽°)ノ✿
带参数请求
现在我还想爬取周杰伦的“晴天”这首歌前几页的评论。
1. 复习
打开有评论那个网页:https://y.qq.com/n/yqq/song/0039MnYb0qxYhV.html#comment_box
按照上一节说的方法,我们知道评论在这里,这一页有25个评论:
在0-24个字典里的 key 为rootcommentcontent
的 value 就是评论。剩下的事情就简单了。我们去模拟这个请求,解析json,提取想要的内容就好。很容易写出以下的代码获取到本页评论:
import requestsurl = '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¬ice=0&platform=yqq.json&needNewCode=0&cid=205360772&reqtype=2&biztype=1&topid=97773&cmd=8&needmusiccrit=0&pagenum=0&pagesize=25&lasthotcommentid=&domain=qq.com&ct=24&cv=10101010'
res = requests.get(url)
res_json = res.json() # 使用json()方法,将response对象,转为列表/字典
comments = res_json['comment']['commentlist']
for comment in comments: # comments是一个列表,comment是它里面的元素print(comment['rootcommentcontent'],'\n')
但是我想要的前几页的评论,怎么样更简单的获取呢?
2. params
有没有觉得上边代码的url太长了,不美观。
我们再去 Headers
里边看,看到Query String Parameters
,其实这是一个字典。
我们能发现,
这个网址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¬ice=0&platform=yqq.json&needNewCode=0&cid=205360772&reqtype=2&biztype=1&topid=97773&cmd=8&needmusiccrit=0&pagenum=0&pagesize=25&lasthotcommentid=&domain=qq.com&ct=24&cv=10101010
是由https://c.y.qq.com/base/fcgi-bin/fcg_global_comment_h5.fcg?
后边跟上Query String Parameters
里的元素,以Key=Value
,用&
隔开连接的。
事实上,requests
模块里的requests.get()
提供了一个参数叫params
,可以让我们用字典的形式,把参数传进去。
url = 'xxx'
params = {'xxx':'xxx','xxx':'xxx' .....} #把参数封装成字典
res = requests.get(url,params=params) #这样代码比较简洁明了
现在多翻几页评论列表,点击Headers
,在General
里看链接,在Query String Parametres
里看参数,总结参数的规律。
经过比对,发现XHR有两个参数在不断变化:一个是pagenum
,一个lasthotcommentid
。其中pagenum
好理解,就是页码,但是lasthotcommentid
是什么?英文的意思是:上一条热评的评论id。
基于此,我们可以做一个猜想:每一页的请求,参数lasthotcommentid
的值,是上一页的最后一条评论,所对应的id。
要验证这个猜想,需要确认:首先,每个评论都有commentid
;其次,是验证这种对应关系。
比对之后,发现我们的猜想是正确的,每一页的最后一个评论的id是下一页 url 里参数lasthotcommentid
的值。
且第一个的pagenum
是0,第二页是1……,至此我们就找到每一页评论 url 的规律了,用一个循环就可以解决获取前几页的评论(循环最好不要超过5,不然会给对方服务器造成负荷):
import requestsurl = '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, #上一条评论的id 每页评论只有这俩参数在变'domain':'qq.com','ct':'24','cv':'101010 '} # 将参数封装为字典,其中pagenum和lastcommentid是特殊的变量res_comment = requests.get(url,params=params)json_comment = res_comment.json()list_comment = json_comment['comment']['commentlist']for comment in list_comment:print(comment['rootcommentcontent'])commentid = list_comment[24]['commentid']# 将最后一个评论的id赋值给comment,准备开始下一次循环
3. 添加Headers
除了带参数请求,我们最好还将自己的爬虫伪装成真实的浏览器——因为在这种情况下,服务器很可能拒绝爬虫访问。甚至有的网站,一开始就不允许爬虫访问。如,知乎、猫眼电影。
每一个请求,都会有一个Requests Headers
,我们把它称作请求头。它里面会有一些关于该请求的基本信息,比如:这个请求是从什么设备什么浏览器上发出?这个请求是从哪个页面跳转而来?
最常需要的是user-agent
,它会记录你电脑的信息和浏览器版本。如果我们想告知服务器,我们不是爬虫是一个正常的浏览器,就要去修改user-agent
。倘若不修改,那么这里的默认值就会是Python,会被浏览器认出来:
url = 'xxx'
headers = {'user-agent':'xxx'}# 标记了请求从什么设备,什么浏览器上发出
params = {'xxx':'xxx'}
res_music = requests.get(url,headers=headers,params=params)
而对于爬取某些特定信息,也要求你注明请求的来源,即origin或referer的内容。
根据输入的歌手名获得相应歌单信息
观察相关URL的参数,有了前面的带参请求,我们就可以根据用户输入的歌手名,把它写入参数去请求,再爬取歌单(包括歌名+所属专辑+播放时长+播放链接)。先自己写写试试,需要注意的是参数中有指向歌手名和页码的,下面是我写的:
# -*- coding:utf-8 -*-
import requests
from bs4 import BeautifulSoup
singer = input('输入你喜欢的歌手名字,\n将在QQ音乐中搜索出他/她的歌单:')
url = 'https://c.y.qq.com/soso/fcgi-bin/client_search_cp'
for i in range(5): #不要爬太多页哦parameters = {'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(i+1), #页码'n': '20','w': singer, #歌手名'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=parameters) # 调用get方法,下载这个字典json_music = res_music.json() # 使用json()方法,将response对象,转为列表/字典#print(json_music['data']['song']['list'][0]['name']) 先用这个测试一下自己找对了没for music in json_music['data']['song']['list']:print ('歌名: ',music['name'])print('所属专辑:' + music['album']['name'])print('播放时长:' + str(music['interval'])+'秒')print('播放链接:https://y.qq.com/n/yqq/song/' + music['mid']+'.html\n\n')
又完了,✿✿ヽ(°▽°)ノ✿加油加油~!!
————————每个人都在抱怨生活不易,可是都在默默为生活打拼————————
python爬虫基础Ⅱ——Ajax数据爬取、带参请求:QQ音乐歌单、QQ音乐评论相关推荐
- python爬虫的一次尝试——华北电力大学图书馆读者荐购系统:基于python爬虫的web数据爬取
华北电力大学图书馆读者荐购系统数据爬取 前言 本章工具 网页分析 1.荐购数据 2.书目具体信息 代码部分 1. 荐购数据爬取 2. 完整书目信息爬取 前言 本学期数据仓库与数据挖掘课程大作业是编程实 ...
- 爬虫:Ajax数据爬取
目录 1.什么是Ajax 1.1 实例的引入 1.2 基本原理 2.Ajax分析方法 1.查看请求 2.过滤请求 3.Ajax结果提取 1.分析请求 2.分析响应 3.例子 我们在用 requests ...
- 【Python爬虫】东方财富数据爬取
0.背景 由于工作需要,最近在研究如何从东方财富网页爬取股东增持数据. 网页:http://data.eastmoney.com/executive/gdzjc-jzc.html 1.分析网页请求 打 ...
- Python爬虫之微信数据爬取(十三)
原创不易,转载前请注明博主的链接地址:Blessy_Zhu https://blog.csdn.net/weixin_42555080 本次代码的环境: 运行平台: Windows Python版本: ...
- Python爬虫——Ajax数据爬取
前言 有时候我们在用requests抓取页面的时候,得到的结果可能和在浏览器中看到的不一样,在浏览器中可以看到正常显示的页面数据,但使用requests得到的结果并没有.这是因为在requests获得 ...
- 简单爬虫Ajax数据爬取——今日头条图片爬取
一.Ajax简介 什么是Ajax? Ajax 即"Asynchronous Javascript And XML"(异步 JavaScript 和 XML),是指一种创建交互式网页 ...
- Python3 爬虫学习笔记 C03 【Ajax 数据爬取】
Python3 爬虫学习笔记第三章 -- [Ajax 数据爬取] 文章目录 [3.1]Ajax 简介 [3.2]解析真实地址提取 [3.1]Ajax 简介 Ajax - Asynchronous Ja ...
- 《PYTHON3网络爬虫开发实践》——第六章 Ajax数据爬取
第六章 Ajax数据爬取 有时候我们在用requests抓取页面的时候,得到的结果可能和在浏览器中看到的不一样:这是因为requests 获取的都是原始的HTML文档,而浏览器中的页面则是经过Java ...
- 数据采集与存储案例——基于Python爬虫框架Scrapy的爬取网络数据与MySQL数据持久化
此案例需要预先安装pymsql python3.7.4 scrapy2.7.1 一.安装scrapy框架 1.使用pip命令安装scrapy pip install scrapy 在这里下载太慢可以使 ...
最新文章
- 多媒体个人计算机的英语,计算机英语之网络多媒体篇
- 有监督、无监督与半监督学习【总结】
- 最懂中文的H5前端框架amazeUI
- [专栏目录]-环境搭建安装问题笔记目录
- unity 批量导入模型工具_零基础的Unity图形学笔记3:使用多模型UV与优化模型导出...
- Vue.js 学习视频和书籍【推荐】
- boost::iostreams::example::container_device用法的测试程序
- 开源之夏 | 阿里开源近百任务上线
- PostgreSQL统计信息的几个重要视图
- OpenCV-Python实战(14)——人脸检测详解(仅需6行代码学会4种人脸检测方法)
- 51Nod 1109 01组成的N的倍数
- ROS 位置姿态Odometry仿真模拟(gmapping)
- Editor\Data\il2cpp/build/deploy/net471/il2cpp.exe did not run properly!
- Hyperledger Explorer部署
- 应用图标变小及换图标不生效的问题
- Linux常用的远程工具
- Razor 视图引擎的一些属性和方法
- 多元统计分析——数据降维——因子分析(FA)
- 解析android:ellipsize=end属性无效的情况
- cpu低端计算机配置清单,i3 4160/GTX750Ti剑灵/英雄联盟中低端组装机配置清单
热门文章
- 快狗打车CTO沈剑:如何利用计划管理提升团队效率和产能
- pygame-KidsCanCode系列jumpy-part7-游戏启动/结束画面
- windows下同一个显卡配置多个CUDA工具包以及它们之间的切换
- 实战Nagios NSCA方式监控Linux系统资源使用情况 -- Nagios配置篇 -- 被监控端
- 【学习笔记】NIM游戏与SG函数初探
- linux宝塔重新安装,Linux服务器Windows系统 安装和卸载宝塔面板
- 大时代已过,小机会可期
- php 微信上传素材,微信上传素材php代码
- 学习ESP8266_15_Flash
- chrome 导出历史访问记录