Ajax数据抓取
序言
通过前几章的学习我们已经了解了爬虫的工作原理和一些基本库的使用。有时候在使用requests库或urllib库抓取页面时,得到的结果可能和在浏览器中看到的不一样。这是因为有些浏览器中的页面是经过JavaScript处理数据后生成的结果。
这些数据的来源有很多种,可能是通过Ajax加载的,也可能是包含在HTML文档中的,还有是经过JavaScript和特殊的算法计算后生成的。
对于第一种情况,是一种异步加载方式,原始的页面最初不会包含某些数据,原始页面加载完成后,在通过JS向服务器发送一个或多个请求获取数据,数据才会呈现在网页上,这其实就是发送了一个Ajax请求。
Ajax的基本原理
(1)发送请求
我们知道,JavaScript可以实现页面的各种交互功能。Ajax也不例外,它的底层也是JavaScript实现的。要使用Ajax技术,需要创建一个XMLHttpRequest对象。
在网页中为某些事件的响应绑定异步操作:通过上面创建的xmlhttp对象传输请求、携带数据。在发出请求前要先定义请求对象的method、要提交给服务器中的那个文件进行处理、要携带哪些数据,以及判断是否异步。
其中,与普通的request请求提交数据一样,这里也分为两种方法:GET和POST,在实际使用时可根据需求选择:
1.传输方法:GET通过地址栏传输,POST通过报文传输。
2.传输长度:GET参数有长度限制(受限于URL长度),而POST无限制。
3.传输效率:GET方法,浏览器会将HTTPheader和data一并发出,服务器响应200(返回数据);而对于POST,浏览器先发送header,服务器响应100(continue),浏览器再发送data,服务器再响应200。因此GET比POST更快。
4.安全:GET传输的data会展示在地址栏中,不安全。(不能用来传输密码等私密信息)。
(2)解析请求
服务器在收到请求后,就会把附带的参数数据作为输入传给处理请求的文件,然后该文件根据传入的数据做出反应,最终返回结果,并通过response对象发出去。客户端根据xmlhttp对象来获取response的内容,返回的response内容可能是HTML也可能是JSON,接下来只需要在方法中用JavaScript作进一步的处理即可。
(3)渲染页面
JAvaScript有改变网页内容的能力,所以在通过Ajax请求获取到返回数据后,通过解析就可以调用JavaScript获取指定网页DOM对象进行更新、修改等数据处理了。
Ajax有其特殊的请求类型,它叫做xhr。
使用Python模拟Ajax请求数据
分析请求
下面分析一下请求,使用浏览器打开网址:https://data.variflight.com/analytics/CodeQuery。
(1)按F12键进入开发者工具,选择【Network】选项卡,在条件搜索框中输入“PEK”并单击【搜索】按钮,可以看到【Network】选项卡下出现了很多条目。
(2)然后单击【Type】进行筛选,找到名称为“airportCode”的请求并单击。
(3)单击之后,可以看到【header】下面有很多关于请求的详细信息,通过观察发现,请求链接RequestURL为“https://data.variflight.com/analytics/Codeapi/airportCode”,请求方法Request Method为“POST”,继续拖动滚动条到最下方From Data处,可以看到这里有两个参数:key和page,key就是输入PEK要查询的三字码,page是页数。
分析响应结果
选择【Preview】选项卡,将会出现JSON格式的内容,可以看到有3个信息,一是code,代表响应状态码是失败还是成功;二是data,data就是我们想要的内容,里面包含了北京机场的相关信息;三是message,提示信息。
代码实现
POST方法
import requests
import json
url="https://data.variflight.com/analytics/Codeapi/airportCode"
data={
'key':'PEK',
'page': 0
}
res=requests.request("post",url,data=data)
text=res.text
con=json.loads(text)
print(con["data"])
GET方法
import requests
import json
url="https://data.variflight.com/analytics/Codeapi/airportCode"
data="key=PEK&page=0"
res=requests.request("get",url+'?'+data)
text=res.text
con=json.loads(text)
print(con["data"])
注意对于这个请求使用GET方法会返回错误,因为这个Ajax请求是以POST方法请求的。