文章目录

  • 基础爬虫部分Ⅱ
    • 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&notice=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&notice=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&notice=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音乐评论相关推荐

  1. python爬虫的一次尝试——华北电力大学图书馆读者荐购系统:基于python爬虫的web数据爬取

    华北电力大学图书馆读者荐购系统数据爬取 前言 本章工具 网页分析 1.荐购数据 2.书目具体信息 代码部分 1. 荐购数据爬取 2. 完整书目信息爬取 前言 本学期数据仓库与数据挖掘课程大作业是编程实 ...

  2. 爬虫:Ajax数据爬取

    目录 1.什么是Ajax 1.1 实例的引入 1.2 基本原理 2.Ajax分析方法 1.查看请求 2.过滤请求 3.Ajax结果提取 1.分析请求 2.分析响应 3.例子 我们在用 requests ...

  3. 【Python爬虫】东方财富数据爬取

    0.背景 由于工作需要,最近在研究如何从东方财富网页爬取股东增持数据. 网页:http://data.eastmoney.com/executive/gdzjc-jzc.html 1.分析网页请求 打 ...

  4. Python爬虫之微信数据爬取(十三)

    原创不易,转载前请注明博主的链接地址:Blessy_Zhu https://blog.csdn.net/weixin_42555080 本次代码的环境: 运行平台: Windows Python版本: ...

  5. Python爬虫——Ajax数据爬取

    前言 有时候我们在用requests抓取页面的时候,得到的结果可能和在浏览器中看到的不一样,在浏览器中可以看到正常显示的页面数据,但使用requests得到的结果并没有.这是因为在requests获得 ...

  6. 简单爬虫Ajax数据爬取——今日头条图片爬取

    一.Ajax简介 什么是Ajax? Ajax 即"Asynchronous Javascript And XML"(异步 JavaScript 和 XML),是指一种创建交互式网页 ...

  7. Python3 爬虫学习笔记 C03 【Ajax 数据爬取】

    Python3 爬虫学习笔记第三章 -- [Ajax 数据爬取] 文章目录 [3.1]Ajax 简介 [3.2]解析真实地址提取 [3.1]Ajax 简介 Ajax - Asynchronous Ja ...

  8. 《PYTHON3网络爬虫开发实践》——第六章 Ajax数据爬取

    第六章 Ajax数据爬取 有时候我们在用requests抓取页面的时候,得到的结果可能和在浏览器中看到的不一样:这是因为requests 获取的都是原始的HTML文档,而浏览器中的页面则是经过Java ...

  9. 数据采集与存储案例——基于Python爬虫框架Scrapy的爬取网络数据与MySQL数据持久化

    此案例需要预先安装pymsql python3.7.4 scrapy2.7.1 一.安装scrapy框架 1.使用pip命令安装scrapy pip install scrapy 在这里下载太慢可以使 ...

最新文章

  1. 多媒体个人计算机的英语,计算机英语之网络多媒体篇
  2. 有监督、无监督与半监督学习【总结】
  3. 最懂中文的H5前端框架amazeUI
  4. [专栏目录]-环境搭建安装问题笔记目录
  5. unity 批量导入模型工具_零基础的Unity图形学笔记3:使用多模型UV与优化模型导出...
  6. Vue.js 学习视频和书籍【推荐】
  7. boost::iostreams::example::container_device用法的测试程序
  8. 开源之夏 | 阿里开源近百任务上线
  9. PostgreSQL统计信息的几个重要视图
  10. OpenCV-Python实战(14)——人脸检测详解(仅需6行代码学会4种人脸检测方法)
  11. 51Nod 1109 01组成的N的倍数
  12. ROS 位置姿态Odometry仿真模拟(gmapping)
  13. Editor\Data\il2cpp/build/deploy/net471/il2cpp.exe did not run properly!
  14. Hyperledger Explorer部署
  15. 应用图标变小及换图标不生效的问题
  16. Linux常用的远程工具
  17. Razor 视图引擎的一些属性和方法
  18. 多元统计分析——数据降维——因子分析(FA)
  19. 解析android:ellipsize=end属性无效的情况
  20. cpu低端计算机配置清单,i3 4160/GTX750Ti剑灵/英雄联盟中低端组装机配置清单

热门文章

  1. 快狗打车CTO沈剑:如何利用计划管理提升团队效率和产能
  2. pygame-KidsCanCode系列jumpy-part7-游戏启动/结束画面
  3. windows下同一个显卡配置多个CUDA工具包以及它们之间的切换
  4. 实战Nagios NSCA方式监控Linux系统资源使用情况 -- Nagios配置篇 -- 被监控端
  5. 【学习笔记】NIM游戏与SG函数初探
  6. linux宝塔重新安装,Linux服务器Windows系统 安装和卸载宝塔面板
  7. 大时代已过,小机会可期
  8. php 微信上传素材,微信上传素材php代码
  9. 学习ESP8266_15_Flash
  10. chrome 导出历史访问记录