1. 程式人生 > >基於歷史資料查詢的爬蟲操作

基於歷史資料查詢的爬蟲操作

網站:http://www.szmb.gov.cn/article/QiXiangJianCe/

目的:抓取過去一年內深圳各個區的逐小時降雨資料

歷史查詢需要通過網頁中的日曆控制元件選擇,而且日曆控制元件只有在點選日期之後才會生效,也就是說,要查詢2016年7月3日12:00的資料,需要先點選日曆,然後通過小時和分鐘的加減獲得12:00,再選擇年、月和日。這樣的操作能通過selenium實現,困難在於,該網站設定該日曆控制元件的輸入值type=“hidden”,且設定日期的屬性unselectable=“on”,display=“none”。也就是說,無法通過selenium實現模擬人的點選操作。因此嘗試以下方法:

1.設定該input的type為text型,而不是hidden型別。再通過selenium的send_keys方法輸入新的日期值,並submit。結果:失敗。原因:設定input的value並沒有用,因為input的value值是通過其他方式賦值的,不會對查詢操作有任何影響。

2.模擬點選操作。如上所述,失敗。

以上兩種方法折磨了我一晚上+一上午。

3.人工點選,並監聽瀏覽器的get和post行為。果然,發現在控制檯出現如下操作:


資料通過text/html傳送,果不其然,js程式碼對資料的操作必須要有某種資料流實現與伺服器之間的資料傳遞。點選日曆的2016年5月5日15:00時,則試圖返回的網頁為:

http://www.szmb.gov.cn/data_center/?controller=shenzhenweather&action=hismonitor&json=1&date=2016-05-05%2015:00
分析其結構組成發現其功能為查詢深圳的監測站歷史天氣資料,返回格式為json,日期為2016-05-05%2015:00,%20顯然代表空格。通過修改json=?後的值發現,當其為1時,返回的為json格式,當json=0時,返回的為標準的xml格式,這富裕資料查詢十分方便。發現新大陸!
# coding=utf-8
# Created on 3 Jul, 2016
# Author: Liuph
# Version:1.0
import urllib
import urllib2
import re
import time
import os
import string

#下載html
def getHtml(url):
    user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
    headers = {'User-Agent': user_agent}
    req = urllib2.Request(url, headers=headers)
    html = urllib2.urlopen(req).read()
    return html


#解析html
def getElement(html):
    #日期時間
    reg_date= r'(?<=\<date\>)(.+?)(?=\</date\>)'
    #行政區
    reg_area = r'area="(.+?)"'
    #站點名稱
    reg_obt = r'obt="(.+?)"'
    #小時降雨
    reg_rain = r'(?<=\<rh\>)(.+?)(?=\</rh\>)'
    #24小時降雨
    reg_rain24 = r'(?<=\<r24h\>)(.+?)(?=\</r24h\>)'

    re_date = re.compile(reg_date)
    re_area = re.compile(reg_area)
    re_obt = re.compile(reg_obt)
    re_rain = re.compile(reg_rain)
    re_rain24 = re.compile(reg_rain24)

    elems_date = re.findall(re_date, html)
    elems_area = re.findall(re_area, html)
    elems_obt = re.findall(re_obt, html)
    elems_rain = re.findall(re_rain, html)
    elems_rain24 = re.findall(re_rain24, html)
    if (len(elems_date) > 0):
        output_file = open("his/" + str(elems_date[0])[0:13] + ".txt", 'w')
        output_file.write(elems_date[0] + "\n")
        for i in range(len(elems_obt)):
            output_file.write(elems_area[i] + "," + elems_obt[i] + "," + elems_rain[i] + "," + elems_rain24[i] + "\n")
        output_file.close()


Months = ['2015-07','2015-08','2015-09','2015-10','2015-11','2015-12','2016-01','2016-02','2016-03','2016-04','2016-05','2016-06','2016-07']
MaxDays = [31,31,30,31,30,31,31,28,31,30,31,30,3]
Hours = ['00','01','02','03','04','05','06','07','08','09','10','11','12','13','14','15','16','17','18','19','20','21','22','23']


for i in range(0,13):
    _month = Months[i]
    for _day in range(1,32):
        if _day > MaxDays[i]:
            continue
        if _day < 10:
            _day = '0'+str(_day)
        else:
            _day = str(_day)
        for _hour in Hours:
            DDateTime = _month + "-" + _day + '%20' + _hour +':00'
            #時間:從2015年7月1日至2016年7月3日
            url = 'http://www.szmb.gov.cn/data_center/?controller=shenzhenweather&action=hismonitor&json=0&date='+DDateTime
            print url
            html = getHtml(url)
            getElement(html)
            #exit()

於是啟動全程連線,開始開心地抓資料了!
附上對實時抓取程式碼的更新(因為實時資料的一小時資料為當前小時的累積資料,所以設定每個小時的58~59分鐘抓取最能滿足1小時條件)
# coding=utf-8
from testString import *
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import string
import os

import time



district_navs = ['nav2','nav1','nav3','nav4','nav5','nav6','nav7','nav8','nav9','nav10']
district_names = ['福田區','羅湖區','南山區','鹽田區','寶安區','龍崗區','光明新區','坪山新區','龍華新區','大鵬新區']
strTime = str(time.strftime("%Y%m%d%H%M", time.localtime(time.time())))

flag = 1
while (flag == 1):
    if (strTime[-2:] == '58'):
        driver = webdriver.Chrome()
        driver.get("http://www.szmb.gov.cn/article/QiXiangJianCe/")
        # 選擇降雨量
        driver.find_element_by_xpath("//span[@id='fenqu_H24R']").click()

        filename = "data/"+strTime + '.txt'
        #建立檔案
        output_file = open(filename, 'w')
        # 選擇行政區
        for i in range(len(district_navs)):
            driver.find_element_by_xpath("//div[@id='" + district_navs[i] + "']").click()
            # print driver.page_source
            timeElem = driver.find_element_by_id("time_shikuang")
            #輸出時間和站點名
            output_file.write(timeElem.text + ',')
            output_file.write(district_names[i] + ',')
            elems = driver.find_elements_by_xpath("//span[@onmouseover='javscript:changeTextOver(this)']")
            #輸出每個站點的資料,格式為:站點名,一小時降雨量,當日累積降雨量
            for elem in elems:
                output_file.write(AMonitorRecord(elem.get_attribute("title")) + ',')
            output_file.write('\n')
        output_file.close()
        driver.close()

    time.sleep(60)
    strTime = str(time.strftime("%Y%m%d%H%M", time.localtime(time.time())))