当前位置 主页 > 网站技术 > 代码类 >

    用python爬取历史天气数据的方法示例

    栏目:代码类 时间:2019-12-30 18:07

    某天气网站(www.数字.com)存有2011年至今的天气数据,有天看到一本爬虫教材提到了爬取这些数据的方法,学习之,并加以改进。

    准备爬的历史天气

    爬之前先分析url。左上有年份、月份的下拉选择框,按F12,进去看看能否找到真正的url:


    很容易就找到了,左边是储存月度数据的js文件,右边是文件源代码,貌似json格式。

    双击左边js文件,地址栏内出现了url:http://tianqi.数字.com/t/wea_history/js/54511_20161.js

    url中的“54511”是城市代码,“20161”是年份和月份代码。下一步就是找到城市代码列表,按城市+年份+月份构造url列表,就能开始遍历爬取了。

    城市代码也很诚实,很快就找到了:

    下一步得把城市名称和代码提取出来,构造一个“城市名称:城市代码”的字典,或者由元组(城市名称,城市代码)组成的列表,供爬取时遍历。考虑到正则提取时,构造元组更便捷,就不做成字典了。

    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)  #只提取了地级市及以上城市的名称和代码,5以上的是县级市  
      city = list(set(city))                    #去掉重复城市数据
      print('城市列表获取成功')
      return city
    

    接下来是构造url列表,感谢教材主编的提醒,这里避免了一个大坑。原来2017年之前的url结构和后面的不一样,在这里照搬了主编的构造方法:

    def getUrls(cityCode):
      urls = []
      for year in range(2011,2020):
        if year <= 2016:
          for month in range(1, 13):
            urls.append('https://tianqi.数字.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.数字.com/t/wea_history/js/%s0%s/%s_%s0%s.js' %(year,month,cityCode,year,month))          
            else:
              urls.append('https://tianqi.数字.com/t/wea_history/js/%s%s/%s_%s%s.js' %(year,month,cityCode,year,month))
      return urls
    

    接下来定义一个爬取页面的函数getHtml(),这个是常规操作,用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') #经试解析,这里得用gbk模式
      time.sleep(random.randint(1,3))    #随机暂停,减轻服务器压力
      return text
    

    然后就是重点部分了,数据解析与提取。

    试了试json解析,发现效果不好,因为页面文本里面含杂质。

    还是用正则表达式吧,能够提取有效数据,尽可能少浪费机器时间。

    2016年开始的数据和之前年份不一样,多了PM2.5污染物情况,因此构造正则表达式时,还不能用偷懒模式。

    str1 = "{ymd:'(.*?)',bWendu:'(.*?)℃',yWendu:'(.*?)℃',tianqi:'(.*?)',fengxiang:'(.*?)',fengli:'(.*?)',aqi:'(.*?)',aqiInfo:'(.*?)',aqiLevel:'(.*?)'.*?}"
    str2 = "{ymd:'(.*?)',bWendu:'(.*?)℃',yWendu:'(.*?)℃',tianqi:'(.*?)',fengxiang:'(.*?)',fengli:'(.*?)'.*?}"
     
    #这个就是偷懒模式,取出来的内容直接存入元组中