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


Posted in Python onDecember 30, 2019

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

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

准备爬的历史天气

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

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

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

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

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

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

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

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

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:'(.*?)'.*?}"
 
#这个就是偷懒模式,取出来的内容直接存入元组中

如果严格以2016年为界,用一下偷懒模式还行,但本人在这里遇坑了,原来个别城市的污染物信息是时有时无的,搞不清在某年某月的某天就出现了,因此还得构造一个通用版的,把数据都提出来,再把无用的字符去掉。

def getDf(url):  
  html = getHtml(url)
  pa = re.compile(r'{(ymd.+?)}')           #用'{ymd'打头,把不是每日天气的其它数据忽略掉
  text = re.findall(pa,html)
  list0 = []
  for item in text:
    s = item.split(',')              #分割成每日数据
    d = [i.split(':') for i in s]         #提取冒号前后的数据名称和数据值
    t = {k:v.strip("'").strip('℃') for k,v in d} #用数据名称和数据值构造字典   
    list0.append(t)
  df = pd.DataFrame(list0)              #加入pandas列表中,便于保存
  return df

数据的保存,这里选择了sqlite3轻便型数据库,可以保存成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("出现错误:\n",e)
  finally:
    con.commit()
    con.close()

在这里还有一个小坑,第一次连接数据库文件时,如果文件不存在,会自动添加,后续在写入数据时,如果数据中新增了字段,写入时会报错。可以先把数据库文件字段都设置好,但这样太累,所以本人又搞了个偷懒的方式,即先传入一个2019年某月的单个url搞一下,自动添加好字段,后面再写入时就没问题了。本人觉得这个应该还有更佳的解决办法,目前还在挖掘中。

数据保存后的状态如下:

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

本来考虑过用多线程爬虫,想想又觉得既然人家没有设置反爬措施,咱们也不能太不厚道了,就单线程吧。

最终爬了334个城市,100多万条数据。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python实现程序的单一实例用法分析
Jun 03 Python
使用Pyinstaller的最新踩坑实战记录
Nov 08 Python
Python 带有参数的装饰器实例代码详解
Dec 06 Python
Python3简单实现串口通信的方法
Jun 12 Python
Appium+python自动化之连接模拟器并启动淘宝APP(超详解)
Jun 17 Python
Django forms表单 select下拉框的传值实例
Jul 19 Python
利用python中集合的唯一性实现去重
Feb 11 Python
pycharm 的Structure界面设置操作
Feb 05 Python
requests在python中发送请求的实例讲解
Feb 17 Python
告别网页搜索!教你用python实现一款属于自己的翻译词典软件
Jun 03 Python
Python3.10的一些新特性原理分析
Sep 15 Python
Python字符串的转义字符
Apr 07 Python
pytorch 自定义卷积核进行卷积操作方式
Dec 30 #Python
PyTorch中反卷积的用法详解
Dec 30 #Python
python使用正则表达式(Regular Expression)方法超详细
Dec 30 #Python
Pytorch实现各种2d卷积示例
Dec 30 #Python
Python面向对象之多态原理与用法案例分析
Dec 30 #Python
Pytoch之torchvision.transforms图像变换实例
Dec 30 #Python
python面向对象之类属性和类方法案例分析
Dec 30 #Python
You might like
GD输出汉字的函数的分析
2006/10/09 PHP
php 结果集的分页实现代码
2009/03/10 PHP
CodeIgniter框架过滤HTML危险代码
2014/06/12 PHP
php数组合并array_merge()函数使用注意事项
2014/06/19 PHP
注释PHP和html混合代码的小技巧(分享)
2016/11/03 PHP
JS控制阿拉伯数字转为中文大写示例代码
2013/09/04 Javascript
jQuery中验证表单提交方式及序列化表单内容的实现
2014/01/06 Javascript
ES6生成器用法实例分析
2017/04/10 Javascript
jQuery序列化后的表单值转换成Json
2017/06/16 jQuery
Vue项目中quill-editor带样式编辑器的使用方法
2017/08/08 Javascript
详解weex默认webpack.config.js改造
2018/01/08 Javascript
如何在微信小程序里面退出小程序的方法
2019/04/28 Javascript
vue如何限制只能输入正负数及小数
2019/07/04 Javascript
layui树形菜单动态遍历的例子
2019/09/23 Javascript
vue + el-form 实现的多层循环表单验证
2020/11/25 Vue.js
[01:34]2014DOTA2 TI预选赛预选赛 选手比赛房大揭秘!
2014/05/20 DOTA
[01:16:16]DOTA2-DPC中国联赛定级赛 RNG vs Phoenix BO3第二场 1月8日
2021/03/11 DOTA
Python中正则表达式的用法实例汇总
2014/08/18 Python
python中while循环语句用法简单实例
2015/05/07 Python
Python基于回溯法子集树模板解决最佳作业调度问题示例
2017/09/08 Python
Python实现小数转化为百分数的格式化输出方法示例
2017/09/20 Python
wxPython实现窗口用图片做背景
2018/04/25 Python
Tensorflow模型实现预测或识别单张图片
2019/07/19 Python
python 批量修改 labelImg 生成的xml文件的方法
2019/09/09 Python
基于jupyter代码无法在pycharm中运行的解决方法
2020/04/21 Python
解决运行django程序出错问题 'str'object has no attribute'_meta'
2020/07/15 Python
Python数据库封装实现代码示例解析
2020/09/05 Python
介绍一下ICMP(Internet Control Message Protocol)Internet控制信息协议
2016/11/26 面试题
2014年毕业演讲稿范文
2014/05/13 职场文书
党的群众路线教育实践活动对照检查材料(教师)
2014/09/24 职场文书
教师党的群众路线教育实践活动个人整改方案
2014/10/31 职场文书
环卫个人总结
2015/03/03 职场文书
自主招生推荐信格式模板
2015/03/24 职场文书
主婚人致辞精选
2015/07/28 职场文书
Nginx优化服务之网页压缩的实现方法
2021/03/31 Servers
详解Python牛顿插值法
2021/05/11 Python