利用python爬虫(案例6+part14)--如何爬取科研数据
學(xué)習(xí)筆記
文章目錄
- Ajax動(dòng)態(tài)加載網(wǎng)站數(shù)據(jù)抓取
- 動(dòng)態(tài)加載的類型
- 那么該如何抓取數(shù)據(jù)?
- 如何得到JSON文件的地址?
- 觀察JSON文件URL地址的查詢參數(shù)
- JSON格式數(shù)據(jù)轉(zhuǎn)換成python字典
- 如何獲取科研數(shù)據(jù)
Ajax動(dòng)態(tài)加載網(wǎng)站數(shù)據(jù)抓取
前幾天小伙伴在寫報(bào)告時(shí),和我討論了一下爬取某生態(tài)網(wǎng)站的統(tǒng)計(jì)數(shù)據(jù)問(wèn)題,我看了一下,這個(gè)網(wǎng)站是動(dòng)態(tài)加載的,想了一想,很多數(shù)據(jù)網(wǎng)站的數(shù)據(jù)都是動(dòng)態(tài)加載的,那么脆寫一個(gè)案例吧,方便大家進(jìn)行數(shù)據(jù)收集和整理。
在爬取數(shù)據(jù)之前,我先講幾個(gè)關(guān)于動(dòng)態(tài)加載網(wǎng)站的知識(shí)點(diǎn),方便大家理解代碼。
動(dòng)態(tài)加載的類型
- 部分頁(yè)面刷新的動(dòng)態(tài)加載
我們首先看一個(gè)動(dòng)態(tài)加載的網(wǎng)站(這個(gè)網(wǎng)站也是我們之后要爬取的網(wǎng)站):
當(dāng)我們進(jìn)行翻頁(yè)操作時(shí),URL地址并沒(méi)有變化,網(wǎng)站只進(jìn)行了部分頁(yè)面的刷新,只有表格內(nèi)的數(shù)據(jù)有變化,頁(yè)面的其他部分并無(wú)改變:
- 滾動(dòng)頁(yè)面自動(dòng)觸發(fā)頁(yè)面加載
我們?cè)倏匆粋€(gè)大家都很熟悉的動(dòng)態(tài)加載的網(wǎng)站,某東。當(dāng)我們?cè)谀硸|上搜索【華章數(shù)學(xué)時(shí)】會(huì)出現(xiàn)如下頁(yè)面:
我們審查元素,查看當(dāng)前頁(yè)面中的最后一個(gè)商品的HTML結(jié)構(gòu):
通過(guò)觀察,我們發(fā)現(xiàn)每一個(gè)商品被包裹在一個(gè)li標(biāo)記中,那么當(dāng)前頁(yè)面的最后一個(gè)商品,應(yīng)該是被包裹在最后一個(gè)li標(biāo)簽中。現(xiàn)在我們滑動(dòng)鼠標(biāo)滑輪,邊滑動(dòng)頁(yè)面邊觀察HTML頁(yè)面結(jié)構(gòu):
哎呀!我們發(fā)現(xiàn),當(dāng)滑倒底部時(shí),頁(yè)面自動(dòng)加載出了一大堆新的被li標(biāo)簽包裹的商品,此時(shí)網(wǎng)頁(yè)的URL地址依然沒(méi)有改變。
那么該如何抓取數(shù)據(jù)?
我們看到在動(dòng)態(tài)加載的頁(yè)面下,URL是如此無(wú)力,我們無(wú)法沿用靜態(tài)匹配的方法去爬取動(dòng)態(tài)加載頁(yè)面里的數(shù)據(jù),那么我們?cè)撊绾闻廊⌒畔⒛?#xff1f;
需要注意的是!只要是動(dòng)態(tài)加載的網(wǎng)站,當(dāng)我們與網(wǎng)站發(fā)生交互,那么網(wǎng)站就會(huì)返回給我們JSON格式的信息,這些信息中包含了我們要爬取的數(shù)據(jù)。此時(shí),我們只要找到這些JSON文件的地址,就成功了一大步。
如何得到JSON文件的地址?
我們以安#省生態(tài)環(huán)境廳的數(shù)據(jù)(http://sthjt.ah.gov.cn/site/tpl/5391?cityCode=340100)為例,我們發(fā)現(xiàn)在這個(gè)網(wǎng)頁(yè)中進(jìn)行翻頁(yè)操作,只有部分頁(yè)面信息被刷新,網(wǎng)頁(yè)URL地址不變,因此該網(wǎng)站應(yīng)該是動(dòng)態(tài)加載數(shù)據(jù)的。
打開安#省生態(tài)環(huán)境廳的網(wǎng)頁(yè)后,右鍵打開審查元素–>點(diǎn)擊Network–>點(diǎn)擊All–>進(jìn)行翻頁(yè)操作,獲取網(wǎng)站和我們進(jìn)行交互的數(shù)據(jù)包–>點(diǎn)開preview,判斷該數(shù)據(jù)包中是否有我們要的數(shù)據(jù)–>點(diǎn)開Headers,查看數(shù)據(jù)包的頭部信息:
我們關(guān)注一下Headers中基本請(qǐng)求信息(General)里的Request URL , 這個(gè)URL地址,就是我們需要的JSON文件的URL地址,我們打開這個(gè)地址驗(yàn)證一下:
很好!就是你啦。但是…這些JSON數(shù)據(jù)的格式看起來(lái)很混亂,還有很多\轉(zhuǎn)義符是怎么回事?雖然這個(gè)問(wèn)題不影響我們之后的數(shù)據(jù)爬取,但是我先標(biāo)記一下這個(gè)問(wèn)題,以后再解決
我們?cè)倩氐秸?qǐng)求頭Headers,查看一下查詢參數(shù):
這些查詢參數(shù),就是JSON文件URL地址的查詢參數(shù),不信的話,我們將這些查詢參數(shù)與JSON文件的URL地址對(duì)比一下:
#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#查詢參數(shù) IsAjax:1 dataType:json _:0.6245771911926585 isJson:true cityCode:340100 type:1 num:2 isPage:true pageIndex:3 pageSize:10 labelName:airQuality嗯!沒(méi)錯(cuò)了!
那么我們要這些查詢參數(shù)有啥用呢?就像我們?cè)谥芭廊§o態(tài)網(wǎng)頁(yè)的數(shù)據(jù)時(shí),需要觀察多個(gè)URL地址的查詢參數(shù)的規(guī)律一樣。如果我們要爬取動(dòng)態(tài)頁(yè)面里的數(shù)據(jù),這些數(shù)據(jù)可能不止在一兩個(gè)JSON文件中,而是可能在大量的JSON文件中。這時(shí),就需要通過(guò)觀察查詢參數(shù)的規(guī)律,來(lái)批量得到我們需要的JSON文件的URL地址,從而獲取JSON文件里的數(shù)據(jù)。
觀察JSON文件URL地址的查詢參數(shù)
我們進(jìn)行多次翻頁(yè)操作,觀察查詢參數(shù)規(guī)律。
第一頁(yè):
IsAjax:1 dataType:json _:0.9632859283976705 isJson:true cityCode:340100 type:1 num:2 isPage:true pageIndex:1 pageSize:10 labelName:airQuality第二頁(yè):
IsAjax:1 dataType:json _:0.699042424499402 isJson:true cityCode:340100 type:1 num:2 isPage:true pageIndex:2 pageSize:10 labelName:airQuality第三頁(yè):
IsAjax:1 dataType:json _:0.6245771911926585 isJson:true cityCode:340100 type:1 num:2 isPage:true pageIndex:3 pageSize:10 labelName:airQuality我們發(fā)現(xiàn)除了_和pageIndex在翻頁(yè)時(shí)有所改變,其他查詢參數(shù)不變。
這個(gè)_查詢參數(shù)的規(guī)律我有點(diǎn)捉摸不透啊,我們看看,在URL地址中把這個(gè)查詢參數(shù)去掉,能不能訪問(wèn)JSON文件。
去掉_查詢參數(shù)后的第3頁(yè)的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訪問(wèn)結(jié)果:
可以!刪除_查詢參數(shù)后不妨礙我們得到該JSON文件;同時(shí),我們對(duì)比網(wǎng)頁(yè)中第3頁(yè)的數(shù)據(jù),一毛一樣。
現(xiàn)在我們觀察pageIndex查詢參數(shù),可以看到第一頁(yè)pageIndex的參數(shù)值為1,第二頁(yè)為2,第三頁(yè)為3, 則我們推斷第kkk頁(yè)pageIndex查詢參數(shù)的值為kkk. 現(xiàn)在我把pageIndex的參數(shù)值改為4,并訪問(wèn)此URL地址:
對(duì)比網(wǎng)頁(yè)中第4頁(yè)的數(shù)據(jù),一模一樣。
JSON格式數(shù)據(jù)轉(zhuǎn)換成python字典
現(xiàn)在我們理清了JSON文件的URL地址,就可以爬取網(wǎng)頁(yè),獲取網(wǎng)頁(yè)內(nèi)容了。但是!需要注意的是,我們?nèi)绾潍@取JSON文件里的數(shù)據(jù)呢?我們看到JSON的數(shù)據(jù)格式,有點(diǎn)像python里的字典和列表。其中要爬取的數(shù)據(jù),被data鍵所對(duì)應(yīng)的值(一個(gè)列表)包裹;每一條記錄在列表中,被一個(gè)字典包裹:
{data: [ { aqi: "54", area: "合肥市", cityCode: 340100, co: "0.363", level: "II級(jí)", 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級(jí)", 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 }但仔細(xì)觀察我們又發(fā)現(xiàn), 這些數(shù)據(jù)格式和字典又有細(xì)微差別,不能直接用字典的索引方式去獲取數(shù)據(jù). 所以,我們就想將JSON格式的數(shù)據(jù)轉(zhuǎn)換為python字典類型,方便獲取數(shù)據(jù)。
但是要怎么進(jìn)行轉(zhuǎn)換呢?
requests模塊是我們的好幫手,使用requests.get().json()方法可以直接返回python的數(shù)據(jù)類型。
語(yǔ)法:
html_str = requests.get(url, headers=headers).json()按理來(lái)說(shuō),應(yīng)該是返回一個(gè)字典的,但是!不知道為啥,它給我返回了一個(gè)包含著字典的字符串???我不想要字符串,我想要字典!現(xiàn)在我在網(wǎng)上查到了2種把字符串轉(zhuǎn)換為字典類型的方法,演示一下:
In [43]: str_01 = '{"a":1}'In [44]: type(json.loads(str_01)) Out[44]: dictIn [45]: type(eval(str_01)) Out[45]: dict如何獲取科研數(shù)據(jù)
好了,現(xiàn)在回到我們?cè)撊绾潍@取科研數(shù)據(jù)這個(gè)問(wèn)題。這里,我就以我和小伙伴想要爬取的網(wǎng)站為例,就是我們剛才一直在講解的安徽省生態(tài)環(huán)境廳的網(wǎng)站:
在這個(gè)案例中,我就獲取網(wǎng)頁(yè)中aqi(質(zhì)量指數(shù))、cityCode(城市代碼)、pm25(PM2.5)這幾個(gè)變量值.
PS:因?yàn)槲姨珣辛?#xff0c;不想打那么多代碼,大家可以舉一反三,將其他變量值獲取下來(lái)。
好,開始敲代碼:
# -*- 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)遍歷每條記錄的數(shù)據(jù)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í)行時(shí)間:%.2f' % (end-start))控制臺(tái)輸出:
<class 'str'> <class 'str'> <class 'str'> <class 'str'> 執(zhí)行時(shí)間:1.15爬取下來(lái)的部分?jǐn)?shù)據(jù)(共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很好!數(shù)據(jù)都爬取下來(lái)了。
但是注意! 這個(gè)數(shù)據(jù)網(wǎng)站的頁(yè)面雖然標(biāo)明了有47條數(shù)據(jù),并共有5頁(yè),但實(shí)際上只有37條數(shù)據(jù),第5頁(yè)我是咋地都點(diǎn)不開:
設(shè)置JSON的URL地址中查詢參數(shù)pageIndex為5,得到的響應(yīng)是系統(tǒng)繁忙:
。。。嗯
這個(gè)案例寫完啦,歡迎補(bǔ)充,糾錯(cuò),指導(dǎo)。
備注:雖然看上去,我們花了那么多心思,而爬取的數(shù)據(jù)并不多,但重要的是理解+舉一反三。
總結(jié)
以上是生活随笔為你收集整理的利用python爬虫(案例6+part14)--如何爬取科研数据的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: TP-Link TL-WDR6500 V
- 下一篇: 等级分明,Ross Young 称 6.