本文主要谈谈如何做一个具有天气预报功能的公众号。
话不多说先上图,实现的功能如下图所示:
点击微信右下角的“+”号,分享任意一个位置信息,公众号后台自动回复当地的天气情况。这里的天气预报是用python从中国天气网抓取的雷达数据。有没有更精准的数据源呢,当然有啦,但这不是本文的重点,这里我就不详说了。
用到的工具:新浪SAE + 微信公众平台 + python2.7(新浪SAE目前仅支持2.7版本)
由于本文的重点不是使用python搭建微信公众平台,网上已经有很多不错的教程,为了避免重复造轮子,我在这里贴一个不错的教程,很适合新手入门:
在开始之前我们有必要了解一下微信公众平台的开发者文档,查阅可知,微信的消息是以XML(可扩展标记语言)的形式传输的,其中地理位置信息的具体格式是:
相应的参数意义如下:
因此天气预报功能的实现流程为:
在读取经纬度时涉及到一个问题,由于百度地图与谷歌地图采用的是不同协议的坐标,腾讯、高德地图与谷歌地图采用的是同种协议。而微信的经纬度信息是腾讯地图给出的,在网站上查看中国天气网发送的url请求可知,中国天气网采用的是百度地图,因此在查询之前需要对经纬度信息做一次转换。具体的转换方式请查看:
如何根据经纬度查询当地天气信息?
1.用chrome浏览器进入中国天气网临近预报页面
2.按F12打开控制台,点击地图上任意一个点
3.查看Network,发现有一条萌萌哒url
4.点击url查看请求和响应信息,发现响应的是一段Json信息,猜想可能是天气信息;
5.打开该url,发现一段萌萌哒数据
红色部分就是我们想要的东西了
6.接下来要做的就是利用Python抓取这段数据了,由于这段数据并不是严格的Json数据(可能是为了防爬虫而采取的简单措施吧),所以需要先截取出Json部分。不过相对还是比较简单的。
下面就直接上代码啦,此处默认读者已经会使用web.py搭建微信公众号了。代码里面有彩蛋请自行查阅~这里不方便宣传,因为偷偷用了人家的url…
1 # -*- coding: utf-8 -*- 2 import hashlib 3 import web 4 import lxml 5 import time 6 import os 7 import urllib2,json 8 import urllib 9 import re 10 import random 11 import hashlib 12 import cookielib 13 import requests 14 import math 15 import re 16 import sys 17 reload(sys) 18 sys.setdefaultencoding('utf8') 19 from bs4 import BeautifulSoup 20 from urllib import urlencode 21 from lxml import etree 22 from smtplib import SMTP_SSL 23 from email.header import Header 24 from email.mime.text import MIMEText 25 26 #session = requests.Session() 27 #s.config['keep_alivesession = requests.Session() 28 class WeixinInterface: 29 30 def __init__(self): 31 self.app_root = os.path.dirname(__file__) 32 self.templates_root = os.path.join(self.app_root, 'templates') 33 self.render = web.template.render(self.templates_root) 34 35 def GET(self): 36 #获取输入参数 37 data = web.input() 38 signature=data.signature 39 timestamp=data.timestamp 40 nonce=data.nonce 41 echostr = data.echostr 42 #自己的token 43 token="" #这里改写你在微信公众平台里输入的token 44 #字典序排序 45 list=[token,timestamp,nonce] 46 list.sort() 47 sha1=hashlib.sha1() 48 map(sha1.update,list) 49 hashcode=sha1.hexdigest() 50 #sha1加密算法 51 52 #如果是来自微信的请求,则回复echostr 53 if hashcode == signature: 54 return echostr 55 56 def POST(self): 57 str_xml = web.data() #获得post来的数据 58 xml = etree.fromstring(str_xml)#进行XML解析 59 msgType=xml.find("MsgType").text 60 fromUser=xml.find("FromUserName").text 61 toUser=xml.find("ToUserName").text 62 if msgType == 'location': 63 wdu = xml.find("Location_X").text 64 wdu = float(wdu) 65 66 jdu = xml.find("Location_Y").text 67 jdu = float(jdu) 68 #转换为百度标准 69 x_pi = 3.14159265358979324 * 3000.0 / 180.0 70 x = jdu 71 y = wdu 72 z = math.sqrt(x * x + y * y) + 0.00002 * math.sin(y * x_pi) 73 theta = math.atan2(y, x) + 0.000003 * math.cos(x * x_pi) 74 jdu = z * math.cos(theta) + 0.0065 75 wdu = z * math.sin(theta) + 0.006 76 wdu = str(wdu) 77 jdu = str(jdu) 78 Lmesag = u"您的位置:" 79 Lmesag += xml.find("Label").text 80 myres = requests.get('http://d3.weather.com.cn/webgis_rain_new/webgis/ele?lat='+ wdu + '&lon='+ jdu + '&callback=fc5m&_=1470809429568') 81 if myres.status_code != 200: 82 if myres.status_code == 500: 83 status_error = u"服务器未响应,请稍后再试~" 84 return self.render.reply_text(fromUser,toUser,int(time.time()), status_error) 85 myres.encoding = 'utf-8' 86 text = myres.text 87 text = text[9:-2] 88 data = json.loads(text) 89 pretime = data['time'] 90 msg = data['msg'] 91 pretime1 = u"查询时间:" 92 pretime1 += pretime 93 msg1 = "天气预报: 中国天气网雷达数据(雷达外推数据,仅供参考):" 94 msg1 += msg 95 Lmesag += ' ' 96 Lmesag += pretime1 97 Lmesag += ' ' 98 Lmesag += msg1 99 cyres = requests.get('http://www.caiyunapp.com/fcgi-bin/v1/api.py?lonlat=' + jdu + ',' + wdu + '&format=json&product=minutes_prec&token=96Ly7wgKGq6FhllM&random=0.8600497214532319') 100 cyres.encoding = "utf-8" 101 cyData = json.loads(cyres.text) 102 cymsg = u" 彩云天气数据(准确率较高):" 103 #cymsg += cyData['summary'] 104 cytemp = u" 温度:" 105 cytemp += str(cyData['temp']) 106 cymsg += cytemp 107 cymsg +=u" 未来1小时天气预报:" 108 cymsg += cyData['summary'] 109 Lmesag += cymsg 110 return self.render.reply_text(fromUser,toUser,int(time.time()), Lmesag) 111 else: 112 pass