用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 cookbook(数据结构与算法)通过公共键对字典列表排序算法示例
Mar 15 Python
Python学习笔记之open()函数打开文件路径报错问题
Apr 28 Python
python MNIST手写识别数据调用API的方法
Aug 08 Python
解决python测试opencv时imread导致的错误问题
Jan 26 Python
利用Python半自动化生成Nessus报告的方法
Mar 19 Python
python与C、C++混编的四种方式(小结)
Jul 15 Python
python tkinter窗口最大化的实现
Jul 15 Python
Python for循环搭配else常见问题解决
Feb 11 Python
关于Kotlin中SAM转换的那些事
Sep 15 Python
python利用线程实现多任务
Sep 18 Python
Python爬虫之Selenium中frame/iframe表单嵌套页面
Dec 04 Python
python 基于pygame实现俄罗斯方块
Mar 02 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
php部分常见问题总结
2008/03/27 PHP
ThinkPHP整合datatables实现服务端分页的示例代码
2018/02/10 PHP
关于ThinkPHP中的异常处理详解
2018/05/11 PHP
php中关于换行的实例写法
2019/09/26 PHP
自己动手制作jquery插件之自动添加删除行的实现
2011/10/13 Javascript
html中使用javascript调用本地程序(exe、doc等)实现代码
2013/04/26 Javascript
Js实现手机发送验证码时按钮延迟操作
2014/06/20 Javascript
JQuery实现表格动态增加行并对新行添加事件
2014/07/30 Javascript
Jquery设置attr的disabled属性控制某行显示或者隐藏
2014/09/25 Javascript
JS实现超简单的鼠标拖动效果
2015/11/02 Javascript
Prototype框架详解
2015/11/25 Javascript
JavaScript操作选择对象的简单实例
2016/05/16 Javascript
详解通过源码解析Node.js中cluster模块的主要功能实现
2018/05/16 Javascript
JavaScript实现的DOM绘制柱状图效果示例
2018/08/08 Javascript
一文读懂ES7中的javascript修饰器
2019/05/06 Javascript
使vue实现jQuery调用的两种方法
2019/05/12 jQuery
JavaScript实现省市区三级联动
2020/02/13 Javascript
使用eslint和githooks统一前端风格的技巧
2020/07/29 Javascript
在antd Table中插入可编辑的单元格实例
2020/10/28 Javascript
[01:20]DOTA2 2017国际邀请赛冠军之路无止竞
2017/06/19 DOTA
Python中operator模块的操作符使用示例总结
2016/06/28 Python
浅谈python socket函数中,send与sendall的区别与使用方法
2017/05/09 Python
Python爬虫通过替换http request header来欺骗浏览器实现登录功能
2018/01/07 Python
Python爬虫实现获取动态gif格式搞笑图片的方法示例
2018/12/24 Python
python的sorted用法详解
2019/06/25 Python
python 如何去除字符串头尾的多余符号
2019/11/19 Python
使用python远程操作linux过程解析
2019/12/04 Python
python scatter函数用法实例详解
2020/02/11 Python
解决django无法访问本地static文件(js,css,img)网页里js,cs都加载不了
2020/04/07 Python
简单了解Python字典copy与赋值的区别
2020/09/16 Python
Python中return函数返回值实例用法
2020/11/19 Python
css3 position fixed固定居中问题解决方案
2014/08/19 HTML / CSS
采购部部门职责
2013/12/15 职场文书
护士毕业实习感言
2014/03/05 职场文书
村干部培训方案
2014/05/02 职场文书
2015年大学社团工作总结
2015/04/09 职场文书