用python爬取歷史天氣數(shù)據(jù)的方法示例
某天氣網(wǎng)站(www.數(shù)字.com)存有2011年至今的天氣數(shù)據(jù),有天看到一本爬蟲教材提到了爬取這些數(shù)據(jù)的方法,學(xué)習(xí)之,并加以改進(jìn)。
準(zhǔn)備爬的歷史天氣
爬之前先分析url。左上有年份、月份的下拉選擇框,按F12,進(jìn)去看看能否找到真正的url:
很容易就找到了,左邊是儲(chǔ)存月度數(shù)據(jù)的js文件,右邊是文件源代碼,貌似json格式。
雙擊左邊js文件,地址欄內(nèi)出現(xiàn)了url:http://tianqi.數(shù)字.com/t/wea_history/js/54511_20161.js
url中的“54511”是城市代碼,“20161”是年份和月份代碼。下一步就是找到城市代碼列表,按城市+年份+月份構(gòu)造url列表,就能開始遍歷爬取了。
城市代碼也很誠實(shí),很快就找到了:
下一步得把城市名稱和代碼提取出來,構(gòu)造一個(gè)“城市名稱:城市代碼”的字典,或者由元組(城市名稱,城市代碼)組成的列表,供爬取時(shí)遍歷??紤]到正則提取時(shí),構(gòu)造元組更便捷,就不做成字典了。
def getCity(): html = reqs.get('https://tianqi.2345.com/js/citySelectData.js').content text = html.decode('gbk') city = re.findall('([1-5]\d{4})\-[A-Z]\s(.*?)\-\d{5}',text) #只提取了地級(jí)市及以上城市的名稱和代碼,5以上的是縣級(jí)市 city = list(set(city)) #去掉重復(fù)城市數(shù)據(jù) print('城市列表獲取成功') return city
接下來是構(gòu)造url列表,感謝教材主編的提醒,這里避免了一個(gè)大坑。原來2017年之前的url結(jié)構(gòu)和后面的不一樣,在這里照搬了主編的構(gòu)造方法:
def getUrls(cityCode): urls = [] for year in range(2011,2020): if year <= 2016: for month in range(1, 13): urls.append('https://tianqi.數(shù)字.com/t/wea_history/js/%s_%s%s.js' % (cityCode,year, month)) else: for month in range(1,13): if month<10: urls.append('https://tianqi.數(shù)字.com/t/wea_history/js/%s0%s/%s_%s0%s.js' %(year,month,cityCode,year,month)) else: urls.append('https://tianqi.數(shù)字.com/t/wea_history/js/%s%s/%s_%s%s.js' %(year,month,cityCode,year,month)) return urls
接下來定義一個(gè)爬取頁面的函數(shù)getHtml(),這個(gè)是常規(guī)操作,用requests模塊就行了:
def getHtml(url): header = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:14.0) Gecko/20100101 Firefox/14.0.1', 'Referer': '******'} request = reqs.get(url,headers = header) text = request.content.decode('gbk') #經(jīng)試解析,這里得用gbk模式 time.sleep(random.randint(1,3)) #隨機(jī)暫停,減輕服務(wù)器壓力 return text
然后就是重點(diǎn)部分了,數(shù)據(jù)解析與提取。
試了試json解析,發(fā)現(xiàn)效果不好,因?yàn)轫撁嫖谋纠锩婧s質(zhì)。
還是用正則表達(dá)式吧,能夠提取有效數(shù)據(jù),盡可能少浪費(fèi)機(jī)器時(shí)間。
2016年開始的數(shù)據(jù)和之前年份不一樣,多了PM2.5污染物情況,因此構(gòu)造正則表達(dá)式時(shí),還不能用偷懶模式。
str1 = "{ymd:'(.*?)',bWendu:'(.*?)℃',yWendu:'(.*?)℃',tianqi:'(.*?)',fengxiang:'(.*?)',fengli:'(.*?)',aqi:'(.*?)',aqiInfo:'(.*?)',aqiLevel:'(.*?)'.*?}" str2 = "{ymd:'(.*?)',bWendu:'(.*?)℃',yWendu:'(.*?)℃',tianqi:'(.*?)',fengxiang:'(.*?)',fengli:'(.*?)'.*?}" #這個(gè)就是偷懶模式,取出來的內(nèi)容直接存入元組中
如果嚴(yán)格以2016年為界,用一下偷懶模式還行,但本人在這里遇坑了,原來個(gè)別城市的污染物信息是時(shí)有時(shí)無的,搞不清在某年某月的某天就出現(xiàn)了,因此還得構(gòu)造一個(gè)通用版的,把數(shù)據(jù)都提出來,再把無用的字符去掉。
def getDf(url): html = getHtml(url) pa = re.compile(r'{(ymd.+?)}') #用'{ymd'打頭,把不是每日天氣的其它數(shù)據(jù)忽略掉 text = re.findall(pa,html) list0 = [] for item in text: s = item.split(',') #分割成每日數(shù)據(jù) d = [i.split(':') for i in s] #提取冒號(hào)前后的數(shù)據(jù)名稱和數(shù)據(jù)值 t = {k:v.strip("'").strip('℃') for k,v in d} #用數(shù)據(jù)名稱和數(shù)據(jù)值構(gòu)造字典 list0.append(t) df = pd.DataFrame(list0) #加入pandas列表中,便于保存 return df
數(shù)據(jù)的保存,這里選擇了sqlite3輕便型數(shù)據(jù)庫,可以保存成db文件:
def work(city,url): con =sql.connect('d:\\天氣.db') try: df = getDf(url) df.insert(0,'城市名稱',city) #新增一列城市名稱 df.to_sql('total', con, if_exists='append', index=False) print(url,'下載完成') except Exception as e: print("出現(xiàn)錯(cuò)誤:\n",e) finally: con.commit() con.close()
在這里還有一個(gè)小坑,第一次連接數(shù)據(jù)庫文件時(shí),如果文件不存在,會(huì)自動(dòng)添加,后續(xù)在寫入數(shù)據(jù)時(shí),如果數(shù)據(jù)中新增了字段,寫入時(shí)會(huì)報(bào)錯(cuò)??梢韵劝褦?shù)據(jù)庫文件字段都設(shè)置好,但這樣太累,所以本人又搞了個(gè)偷懶的方式,即先傳入一個(gè)2019年某月的單個(gè)url搞一下,自動(dòng)添加好字段,后面再寫入時(shí)就沒問題了。本人覺得這個(gè)應(yīng)該還有更佳的解決辦法,目前還在挖掘中。
數(shù)據(jù)保存后的狀態(tài)如下:
本來考慮過用多線程爬蟲,想想又覺得既然人家沒有設(shè)置反爬措施,咱們也不能太不厚道了,就單線程吧。
最終爬了334個(gè)城市,100多萬條數(shù)據(jù)。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
pytorch中torch.stack()函數(shù)用法解讀
這篇文章主要介紹了pytorch中torch.stack()函數(shù)用法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-04-04Python使用lambda表達(dá)式對(duì)字典排序操作示例
這篇文章主要介紹了Python使用lambda表達(dá)式對(duì)字典排序操作,結(jié)合實(shí)例形式分析了lambda表達(dá)式實(shí)現(xiàn)字典按鍵排序、按值排序、多條件排序相關(guān)操作技巧,需要的朋友可以參考下2019-07-07使用Python為Excel文件添加預(yù)設(shè)和自定義文檔屬性
向Excel文件添加文檔屬性是專業(yè)地組織和管理電子表格數(shù)據(jù)的關(guān)鍵步驟,這些屬性,如標(biāo)題、作者、主題和關(guān)鍵詞,增強(qiáng)了文件的元數(shù)據(jù),使得在大型數(shù)據(jù)庫或文件系統(tǒng)中跟蹤變得更加容易,本文將介紹如何使用Python高效地為Excel文件添加文檔屬性,需要的朋友可以參考下2024-05-05Python的Flask框架中SQLAlchemy使用時(shí)的亂碼問題解決
這篇文章主要介紹了Python的Flask框架中SQLAlchemy使用時(shí)的亂碼問題解決,SQLAlchemy與Python結(jié)合對(duì)數(shù)據(jù)庫的操作非常方便,需要的朋友可以參考下2015-11-11