python爬虫科研_利用python爬虫(案例6+part15)–如何爬取科研数

学习笔记

文章目录Ajax动态加载网站数据抓取动态加载的类型那么该如何抓取数据?如何得到JSON文件的地址?观察JSON文件URL地址的查询参数JSON格式数据转换成python字典如何获取科研数据

Ajax动态加载网站数据抓取

前几天小伙伴在写报告时,和我讨论了一下爬取某生态网站的统计数据问题,我看了一下,这个网站是动态加载的,想了一想,很多数据网站的数据都是动态加载的,那么脆写一个案例吧,方便大家进行数据收集和整理。

在爬取数据之前,我先讲几个关于动态加载网站的知识点,方便大家理解代码。

动态加载的类型

部分页面刷新的动态加载

我们首先看一个动态加载的网站(这个网站也是我们之后要爬取的网站):

当我们进行翻页操作时,URL地址并没有变化,网站只进行了部分页面的刷新,只有表格内的数据有变化,页面的其他部分并无改变:

滚动页面自动触发页面加载

我们再看一个大家都很熟悉的动态加载的网站,某东。当我们在某东上搜索【华章数学时】会出现如下页面:

我们审查元素,查看当前页面中的最后一个商品的HTML结构:

通过观察,我们发现每一个商品被包裹在一个li标记中,那么当前页面的最后一个商品,应该是被包裹在最后一个li标签中。现在我们滑动鼠标滑轮,边滑动页面边观察HTML页面结构:

哎呀!我们发现,当滑倒底部时,页面自动加载出了一大堆新的被li标签包裹的商品,此时网页的URL地址依然没有改变。

那么该如何抓取数据?

我们看到在动态加载的页面下,URL是如此无力,我们无法沿用静态匹配的方法去爬取动态加载页面里的数据,那么我们该如何爬取信息呢?

需要注意的是!只要是动态加载的网站,当我们与网站发生交互,那么网站就会返回给我们JSON格式的信息,这些信息中包含了我们要爬取的数据。此时,我们只要找到这些JSON文件的地址,就成功了一大步。

如何得到JSON文件的地址?

我们以安#省生态环境厅的数据(http://sthjt.ah.gov.cn/site/tpl/5391?cityCode=340100)为例,我们发现在这个网页中进行翻页操作,只有部分页面信息被刷新,网页URL地址不变,因此该网站应该是动态加载数据的。

打开安#省生态环境厅的网页后,右键打开审查元素–>点击Network–>点击All–>进行翻页操作,获取网站和我们进行交互的数据包–>点开preview,判断该数据包中是否有我们要的数据–>点开Headers,查看数据包的请求头:

我们关注一下Headers中基本请求信息(General)里的Request URL , 这个URL地址,就是我们需要的JSON文件的URL地址,我们打开这个地址验证一下:

很好!就是你啦。但是…这些JSON数据的格式看起来很混乱,还有很多\转义符是怎么回事?虽然这个问题不影响我们之后的数据爬取,但是我先标记一下这个问题,以后再解决

我们再回到请求头Headers,查看一下查询参数:

这些查询参数,就是JSON文件URL地址的查询参数,不信的话,我们将这些查询参数与JSON文件的URL地址对比一下:

#JSON文件的URL地址

http://sthjt.ah.gov.cn/site/label/8888?IsAjax=1&dataType=json&_=0.6245771911926585&isJson=true&cityCode=340100&type=1&num=2&isPage=true&pageIndex=3&pageSize=10&labelName=airQuality

#查询参数

IsAjax:1

dataType:json

_:0.6245771911926585

isJson:true

cityCode:340100

type:1

num:2

isPage:true

pageIndex:3

pageSize:10

labelName:airQuality

嗯!没错了!

那么我们要这些查询参数有啥用呢?就像我们在之前爬取静态网页的数据时,需要观察多个URL地址的查询参数的规律一样。如果我们要爬取动态页面里的数据,这些数据可能不止在一两个JSON文件中,而是可能在大量的JSON文件中。这时,就需要通过观察查询参数的规律,来批量得到我们需要的JSON文件的URL地址,从而获取JSON文件里的数据。

观察JSON文件URL地址的查询参数

我们进行多次翻页操作,观察查询参数规律。

第一页:

IsAjax:1

dataType:json

_:0.9632859283976705

isJson:true

cityCode:340100

type:1

num:2

isPage:true

pageIndex:1

pageSize:10

labelName:airQuality

第二页:

IsAjax:1

dataType:json

_:0.699042424499402

isJson:true

cityCode:340100

type:1

num:2

isPage:true

pageIndex:2

pageSize:10

labelName:airQuality

第三页:

IsAjax:1

dataType:json

_:0.6245771911926585

isJson:true

cityCode:340100

type:1

num:2

isPage:true

pageIndex:3

pageSize:10

labelName:airQuality

我们发现除了_和pageIndex在翻页时有所改变,其他查询参数不变。

这个_查询参数的规律我有点捉摸不透啊,我们看看,在URL地址中把这个查询参数去掉,能不能访问JSON文件。

去掉_查询参数后的第3页的JSON文件的URL地址:

http://sthjt.ah.gov.cn/site/label/8888?IsAjax=1&dataType=json&isJson=true&cityCode=340100&type=1&num=2&isPage=true&pageIndex=3&pageSize=10&labelName=airQuality

访问结果:

可以!删除_查询参数后不妨碍我们得到该JSON文件;同时,我们对比网页中第3页的数据,一毛一样。

现在我们观察pageIndex查询参数,可以看到第一页pageIndex的参数值为1,第二页为2,第三页为3, 则我们推断第kkk页pageIndex查询参数的值为kkk. 现在我把pageIndex的参数值改为4,并访问此URL地址:

对比网页中第4页的数据,一模一样。

JSON格式数据转换成python字典

现在我们理清了JSON文件的URL地址,就可以爬取网页,获取网页内容了。但是!需要注意的是,我们如何获取JSON文件里的数据呢?我们看到JSON的数据格式,有点像python里的字典和列表。其中要爬取的数据,被data键所对应的值(一个列表)包裹;每一条记录在列表中,被一个字典包裹:

{data: [

{

aqi: "54",

area: "合肥市",

cityCode: 340100,

co: "0.363",

level: "II级",

measure: "",

no2: "30",

o3: "115",

pm10: "57",

pm25: "16",

primaryPollutant: "颗粒物(PM10)",

quality: "良",

so2: "7",

timePoint: "2020-04-15 18:00:00",

unheathful: ""

},

{

aqi: "49",

area: "合肥市",

cityCode: 340100,

co: "0.334",

level: "I级",

measure: "",

no2: "22",

o3: "123",

pm10: "49",

pm25: "15",

primaryPollutant: "—",

quality: "优",

so2: "7",

timePoint: "2020-04-15 17:00:00",

unheathful: ""

}],

pageCount: 5,

pageIndex: 4,

pageSize: 10,

startNumber: 40,

total: 47

}

但仔细观察我们又发现, 这些数据格式和字典又有细微差别,不能直接用字典的索引方式去获取数据. 所以,我们就想将JSON格式的数据转换为python字典类型,方便获取数据。

但是要怎么进行转换呢?

requests模块是我们的好帮手,使用requests.get().json()方法可以直接返回python的数据类型的字符串。

语法:

html_str = requests.get(url, headers=headers).json()

我不想要字符串,我想要字典!现在我在网上查到了2种把字符串转换为字典类型的方法,演示一下:

In [43]: str_01 = '{"a":1}'

In [44]: type(json.loads(str_01))

Out[44]: dict

In [45]: type(eval(str_01))

Out[45]: dict

如何获取科研数据

好了,现在回到我们该如何获取科研数据这个问题。这里,我就以我和小伙伴想要爬取的网站为例,就是我们刚才一直在讲解的安徽省生态环境厅的网站:

在这个案例中,我就获取网页中aqi(质量指数)、cityCode(城市代码)、pm25(PM2.5)这几个变量值.

PS:因为我太懒了,不想打那么多代码,大家可以举一反三,将其他变量值获取下来。

好,开始敲代码:

# -*- coding: utf-8 -*-

import requests

import time

import csv

import json

class DeeSpider:

def __init__(self):

self.url = 'http://sthjt.ah.gov.cn/site/label/8888?IsAjax=1&dataType=json&isJson=true&cityCode=340100&type=1&num=2&isPage=true&pageIndex={}&pageSize=10&labelName=airQuality'

self.headers = {'Accept':'application/json, text/javascript, */*; q=0.01',

'Accept-Language':'zh-CN,zh;q=0.9',

'Connection':'keep-alive',

'Host':'sthjt.ah.gov.cn',

'User-Agent':'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36',

'X-Requested-With':'XMLHttpRequest'}

def get_data(self, url):

html = requests.get(url, headers=self.headers).json()

#得到的是字符串

print(type(html))

html_dict = json.loads(html)["data"] #html_dict = html["data"]

#for循环遍历每条记录的数据

data_list = []

for data in html_dict:

aqi = data['aqi'] cityCode = data['cityCode'] pm25 = data['pm25'] #print(cityCode)

data_list.append([aqi, cityCode, pm25])

self.write_data(data_list)

def write_data(self, data_list):

with open('./test/my_DeeData.csv', 'a', newline = '') as f:

writer = csv.writer(f)

#writer.writerow(['aqi', 'cityCode', 'pm25'])

writer.writerows(data_list)

def main(self):

for item in range(1, 5):

url = self.url.format(item)

self.get_data(url)

if __name__ == '__main__':

start = time.time()

spider = DeeSpider()

spider.main()

end = time.time()

print('执行时间:%.2f' % (end-start))

控制台输出:

执行时间:1.15

爬取下来的部分数据(共37条):

85,340100,63

93,340100,69

94,340100,70

92,340100,68

88,340100,65

85,340100,60

85,340100,49

82,340100,43

84,340100,44

87,340100,41

87,340100,35

83,340100,31

很好!数据都爬取下来了。

但是注意! 这个数据网站的页面虽然标明了有47条数据,并共有5页,但实际上只有37条数据,第5页我是咋地都点不开:

设置JSON的URL地址中查询参数pageIndex为5,得到的响应是系统繁忙:

。。。嗯

这个案例写完啦,欢迎补充,纠错,指导。

备注:虽然看上去,我们花了那么多心思,而爬取的数据并不多,但重要的是理解+举一反三。

作者:山羊菌

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值