Ajax 是一种使用 JavaScript 发起异步请求的技术,其通过 XML 与服务后台交换数据,并在不加载整个网页的情况下改变其部分内容
因为 Ajax 灵活、易用,且更具维护性能,在许多现代网站开发中都会被使用
这里介绍怎么使用爬虫来爬取 Ajax 传递的数据
分析网页结构
我们准备爬取一个文娱数据统计的网站:http://www.endata.com.cn/
目标网页是数据榜单中的票房数据,基于年度票房的数据统计,如下图是2020年电影票房数据的统计
图中红箭头指向的是用于选择年份的下拉列表
使用开发者模式,定位下拉列表,可以查看该标签的相关属性
再到网页源码文件中查找这个标签的 id
在这里面我们看到一个调用 Ajax 请求接口的方法,以及其参数内容
这显然是一个封装好的方法,我们可以到外部引入的脚本中去查看这个方法的具体实现
显然是来自这个 Common.js,我们打开这个文件,在里面进行关键字查找
如此,我们得到了 Ajax 请求的目标 url 和 POST 的表单格式,其传递数据的形式为 Json
分析网页请求
除了分析网页结构,我们还可以通过分析网页请求信息来提取关键信息
使用开发者模式,打开 Network 标签,改变年份,观察每次年份变更后重新载入数据时浏览器发起的请求信息
显然,最先是加载该年份总的电影票房数据信息,后面是单独加载某个电影的数据
查看第一个请求包的详细内容
是我们想要的信息
模拟请求
我们前面前面获取到的信息有:
- Ajax 请求的 url 为:http://www.endata.com.cn/API/GetData.ashx
- 请求方法为 POST,表单内容为 year 和 MethodName
- 传递数据的形式为 Json
我们根据这些信息进行模拟请求,测试其是否可成功获取数据
测试成功,模拟的 POST 请求可以获取 Json 形式的数据返回
在 Json 格式化数据中,我们想要获取的信息在 Data 字段中的 Table 字段,以数组的形式存储
构建爬虫
由此,我们编写爬虫代码
# 电影票房
import requests
import pandas as pd
def get_boxoffices_by_year(url, headers):
res_data = []
for year in range(2008, 2021):
data = {'year': year, 'MethodName': 'BoxOffice_GetYearInfoData'}
res = requests.post(url, data=data, headers=headers)
res_data += res.json()['Data']['Table']
df = pd.DataFrame(res_data)
df.to_excel('boxoffices_by_year.xlsx')
if __name__ == '__main__':
url = 'http://www.endata.com.cn/API/GetData.ashx'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3100.0 Safari/537.36'
}
get_boxoffices_by_year(url, headers)
爬取结果:
追加(2021-01-23)
现在网站对后台返回的数据进行了加密处理,能获取到的都是密文
前端在处理数据时候也是做了判断,如果不是一个Json字符串,就会调用webInstace.shell()方法进行解密处理
大概猜测他用的是DES加密算法,DES是对称加密算法,加密密钥和解密密钥是同一个,在前端进行解密,要么是后台另外传了密钥过来,要么就是使用了约定的密钥生成方法,这里就不往下探究了(这里应该是对加密算法的js代码使用了混淆,看得头痛)。
既然网站对数据进行了加密,我们直接使用ajax就不能拿到有效的数据了,或许可以等前端渲染之后再拿数据明文,这里也不继续探究了,这篇文章就当看一乐吧。