利用python爬虫(案例6+part14)--如何爬取科研数据
學習筆記
文章目錄
- Ajax動態(tài)加載網站數據抓取
- 動態(tài)加載的類型
- 那么該如何抓取數據?
- 如何得到JSON文件的地址?
- 觀察JSON文件URL地址的查詢參數
- JSON格式數據轉換成python字典
- 如何獲取科研數據
Ajax動態(tài)加載網站數據抓取
前幾天小伙伴在寫報告時,和我討論了一下爬取某生態(tài)網站的統(tǒng)計數據問題,我看了一下,這個網站是動態(tài)加載的,想了一想,很多數據網站的數據都是動態(tài)加載的,那么脆寫一個案例吧,方便大家進行數據收集和整理。
在爬取數據之前,我先講幾個關于動態(tài)加載網站的知識點,方便大家理解代碼。
動態(tài)加載的類型
- 部分頁面刷新的動態(tài)加載
我們首先看一個動態(tài)加載的網站(這個網站也是我們之后要爬取的網站):
當我們進行翻頁操作時,URL地址并沒有變化,網站只進行了部分頁面的刷新,只有表格內的數據有變化,頁面的其他部分并無改變:
- 滾動頁面自動觸發(fā)頁面加載
我們再看一個大家都很熟悉的動態(tài)加載的網站,某東。當我們在某東上搜索【華章數學時】會出現如下頁面:
我們審查元素,查看當前頁面中的最后一個商品的HTML結構:
通過觀察,我們發(fā)現每一個商品被包裹在一個li標記中,那么當前頁面的最后一個商品,應該是被包裹在最后一個li標簽中。現在我們滑動鼠標滑輪,邊滑動頁面邊觀察HTML頁面結構:
哎呀!我們發(fā)現,當滑倒底部時,頁面自動加載出了一大堆新的被li標簽包裹的商品,此時網頁的URL地址依然沒有改變。
那么該如何抓取數據?
我們看到在動態(tài)加載的頁面下,URL是如此無力,我們無法沿用靜態(tài)匹配的方法去爬取動態(tài)加載頁面里的數據,那么我們該如何爬取信息呢?
需要注意的是!只要是動態(tài)加載的網站,當我們與網站發(fā)生交互,那么網站就會返回給我們JSON格式的信息,這些信息中包含了我們要爬取的數據。此時,我們只要找到這些JSON文件的地址,就成功了一大步。
如何得到JSON文件的地址?
我們以安#省生態(tài)環(huán)境廳的數據(http://sthjt.ah.gov.cn/site/tpl/5391?cityCode=340100)為例,我們發(fā)現在這個網頁中進行翻頁操作,只有部分頁面信息被刷新,網頁URL地址不變,因此該網站應該是動態(tài)加載數據的。
打開安#省生態(tài)環(huán)境廳的網頁后,右鍵打開審查元素–>點擊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嗯!沒錯了!
那么我們要這些查詢參數有啥用呢?就像我們在之前爬取靜態(tài)網頁的數據時,需要觀察多個URL地址的查詢參數的規(guī)律一樣。如果我們要爬取動態(tài)頁面里的數據,這些數據可能不止在一兩個JSON文件中,而是可能在大量的JSON文件中。這時,就需要通過觀察查詢參數的規(guī)律,來批量得到我們需要的JSON文件的URL地址,從而獲取JSON文件里的數據。
觀察JSON文件URL地址的查詢參數
我們進行多次翻頁操作,觀察查詢參數規(guī)律。
第一頁:
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我們發(fā)現除了_和pageIndex在翻頁時有所改變,其他查詢參數不變。
這個_查詢參數的規(guī)律我有點捉摸不透啊,我們看看,在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: "優(yōu)", so2: "7", timePoint: "2020-04-15 17:00:00", unheathful: "" }], pageCount: 5, pageIndex: 4, pageSize: 10, startNumber: 40, total: 47 }但仔細觀察我們又發(fā)現, 這些數據格式和字典又有細微差別,不能直接用字典的索引方式去獲取數據. 所以,我們就想將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]: dictIn [45]: type(eval(str_01)) Out[45]: dict如何獲取科研數據
好了,現在回到我們該如何獲取科研數據這個問題。這里,我就以我和小伙伴想要爬取的網站為例,就是我們剛才一直在講解的安徽省生態(tài)環(huán)境廳的網站:
在這個案例中,我就獲取網頁中aqi(質量指數)、cityCode(城市代碼)、pm25(PM2.5)這幾個變量值.
PS:因為我太懶了,不想打那么多代碼,大家可以舉一反三,將其他變量值獲取下來。
好,開始敲代碼:
# -*- coding: utf-8 -*-import requests import time import csv import jsonclass 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循環(huán)遍歷每條記錄的數據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('執(zhí)行時間:%.2f' % (end-start))控制臺輸出:
<class 'str'> <class 'str'> <class 'str'> <class 'str'> 執(zhí)行時間: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,得到的響應是系統(tǒng)繁忙:
。。。嗯
這個案例寫完啦,歡迎補充,糾錯,指導。
備注:雖然看上去,我們花了那么多心思,而爬取的數據并不多,但重要的是理解+舉一反三。
總結
以上是生活随笔為你收集整理的利用python爬虫(案例6+part14)--如何爬取科研数据的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: TP-Link TL-WDR6500 V
- 下一篇: websocket python爬虫_p