Python爬取天气实况(2)

三、对爬取天气实况程序的进一步优化
对上一篇的程序进行优化,加上了处理异常机制,比如爬取失败怎么处理,比如站号不存在怎么处理,使程序更加健壮。
代码如下:

import requests
import re


def getHTMLtext(url):
    try:
        r = requests.get(url, timeout=30)
        r.raise_for_status() #如果状态不是200,引发HTTPError异常
        r.encoding = r.apparent_encoding
        return r.text
    except:
        return "ERROR"


def parseHTML(s):
    try:
        pat_title = re.compile(r'[A-Z]?\d{4,5}.*站的当前实况')
        title = pat_title.search(s).group(0)
        print(title)

        lst = re.findall(r'<tr align=\"center\">[\d\D]*?</tr>', s)
        for l in lst:
            m = re.sub(r'[\n\t]+|<td>|</tr>|<tr align=\"center\">', '', l)
            result = re.split('</td>',m)
            print(result[0]+':'+result[1]+' (更新时间:'+result[2]+')')
    except:
        print("该站号可能不存在!")


num = input("请输入站号:")
url = "http://q-weather.info/weather/" + str(num) + "/realtime/"
s = getHTMLtext(url)

if(s == "ERROR"):
    print("查询失败!请重试")
else:
    parseHTML(s)
        

几个运行结果如下:
1.站号存在的情况:
在这里插入图片描述
2.站号不存在的情况:
在这里插入图片描述
3.网络问题
这种情况会输出“查询失败!请重试”,由于我碰到的几率较小,因此也没有截图放出来了。

四、爬取站号的详细信息
我们以59659茂名站为例(http://q-weather.info/weather/59659/),下图就是查天气网站截图:
在这里插入图片描述
爬取的HTML源代码如下:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">\n<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="zh-CN">\n<head>\n\t<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />\n\t<title>气象站59659的详细信息</title>\n\t<style type="text/css">\n\t\ttable {\n\t\t\tborder-width: 0px;\n\t\t\tborder-style: solid;\n\t\t\tborder-collapse: collapse;\n\t\t}\n\t\ttable th {\n\t\t\tborder-width: 1px;\n\t\t\tpadding: 3px;\n\t\t\tborder-style: solid;\n\t\t}\n\t\ttable td {\n\t\t\tborder-width: 1px;\n\t\t\tpadding: 3px;\n\t\t\tborder-style: solid;\n\t\t}\n\t</style>\n</head>\n<body>\n\t<center>\n\t\t<h1>站点59659的信息</h1>\n\t\t<table>\n\t\t\t<tr>\n\t\t\t\t<td width="100px">WMO编号</td>\n\t\t\t\t<td width="200px">59659</td>\n\t\t\t</tr>\n\t\t\t<tr>\n\t\t\t\t<td>站名</td>\n\t\t\t\t<td>茂名</td>\n\t\t\t</tr>\n\t\t\t<tr>\n\t\t\t\t<td>所在市</td>\n\t\t\t\t<td>茂名</td>\n\t\t\t</tr>\n\t\t\t<tr>\n\t\t\t\t<td>地理位置</td>\n\t\t\t\t<td>21.75N<br />\n\t\t\t\t\t110.92E<br />\n\t\t\t\t\t33.3m</td>\n\t\t\t</tr>\n\t\t</table>\n\t\t<h2>服务列表</h2>\n\t\t<p><a href="realtime/">查询当前实况</a></p>\n\t\t<p><a href="today/">查询今日实况</a></p>\n\t\t<p><a href="cma7day/">中国气象局7天预报</a></p>\n\t\t<p><a href="t77day/">T7Online 7天预报</a></p>\n\t\t<p><a href="t7en8day/">WeatherOnline 8天预报</a></p>\n\t</center>\n</body>\n</html>\n

如果将转义字符转义(就是将\n和\t变成换行和制表),也就是:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="zh-CN">
<head>
	<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
	<title>气象站59659的详细信息</title>
	<style type="text/css">
		table {
			border-width: 0px;
			border-style: solid;
			border-collapse: collapse;
		}
		table th {
			border-width: 1px;
			padding: 3px;
			border-style: solid;
		}
		table td {
			border-width: 1px;
			padding: 3px;
			border-style: solid;
		}
	</style>
</head>
<body>
	<center>
		<h1>站点59659的信息</h1>
		<table>
			<tr>
				<td width="100px">WMO编号</td>
				<td width="200px">59659</td>
			</tr>
			<tr>
				<td>站名</td>
				<td>茂名</td>
			</tr>
			<tr>
				<td>所在市</td>
				<td>茂名</td>
			</tr>
			<tr>
				<td>地理位置</td>
				<td>21.75N<br />
					110.92E<br />
					33.3m</td>
			</tr>
		</table>
		<h2>服务列表</h2>
		<p><a href="realtime/">查询当前实况</a></p>
		<p><a href="today/">查询今日实况</a></p>
		<p><a href="cma7day/">中国气象局7天预报</a></p>
		<p><a href="t77day/">T7Online 7天预报</a></p>
		<p><a href="t7en8day/">WeatherOnline 8天预报</a></p>
	</center>
</body>
</html>

这个就比之前的好弄很多了,所在市信息、地理位置都包围在tr标签里面,一个很简单的想法就是将所有符合以下正则表达式:

r'<tr>[\d\D]*?</tr>'

全部都找出来,所用的函数是findall函数,然后将结果存进列表中。由于WMO不是我们想要的信息,它位于list[0]里面,我们不管它就是了。接着再用:

r'[\n\t]+|<tr>|</tr>|<td>'

删掉我们不需要的符号\n\t和tr标签、td标签,留下/td标签以作分隔符。
所以我们提取出来的其实是以下结果:

站名</td>#这是list[1]的内容!!!
茂名</td>
			
所在市</td>#这是list[2]的内容!!!
茂名</td>
			
地理位置</td>#这是list[3]的内容!!!
21.75N<br />
110.92E<br />
33.3m</td>

list[1]和[2]很好处理,用re.split函数以/td作为分隔,将有用信息拿出来就是了。
我们发现地理位置信息(list[3])与其他两个有一点不同,那就是list[3]多了两个br/标签,因此我们需要特别处理。
完整代码如下:

import requests
import re


def getHTMLtext(url):
    try:
        r = requests.get(url, timeout=30)
        r.raise_for_status() #如果状态不是200,引发HTTPError异常
        r.encoding = r.apparent_encoding
        return r.text
    except:
        return "ERROR"
    

def parseInform(s):
    lst = re.findall(r'<tr>[\d\D]*?</tr>', s)
    #处理站名信息和所在市信息
    for l in lst[1:3] :
        l = re.sub(r'[\n\t]+|<tr>|</tr>|<td>', '', l)
        result = re.split(r'</td>', l)
        print(result[0] + ':' + result[1])
     #对地理信息做特殊处理
    l = re.sub(r'[\n\t]+|<tr>|</tr>|<td>', '', lst[3])
    result = re.split(r'</td>|<br />', l)
    print(result[0] + ':' + result[1] + '/' + result[2] + '\n海拔:' + result[3])

            
num = input("请输入站号:")
url = "http://q-weather.info/weather/" + str(num)
s = getHTMLtext(url)

if(s == "ERROR"):
    print("查询失败!请重试")
else:
    parseInform(s)

运行结果如下:
在这里插入图片描述
我们最后可以将查询站点的详细信息程序和实时天气程序连接在一起,稍作修改,就能够得到一个不错的查询天气脚本了。
当然,这个网站还有查询最近24小时天气的功能,有时间的话我们会继续做做爬虫。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
天气查询APP,两种JSON解析方式 /** * 原始json数据解析 * */ // JSONObject jsonObject = new JSONObject(res); // String reason=jsonObject.getString("reason"); // if (reason.equals("参数不正确")){ // handler.sendEmptyMessage(1); // return; // } // JSONObject result=jsonObject.getJSONObject("result"); // JSONObject realtime=result.getJSONObject("realtime"); // JSONObject life=result.getJSONObject("life"); // JSONObject wind=realtime.getJSONObject("wind"); // String time=realtime.getString("time"); // JSONObject weather=realtime.getJSONObject("weather"); // String date=realtime.getString("date"); // dateStr=time+date; // weekStr=realtime.getString("week"); // calendarStr=realtime.getString("moon"); // windpowerStr=wind.getString("direct")+" "+wind.getString("power"); // weatherStr=weather.getString("info"); // temperatureStr=weather.getString("temperature"); // JSONObject info=life.getJSONObject("info"); // JSONArray kongtiao=info.getJSONArray("kongtiao"); // JSONArray yundong=info.getJSONArray("yundong"); // JSONArray ziwaixian=info.getJSONArray("ziwaixian"); // ACStr=kongtiao.getString(0)+" "+kongtiao.getString(1); // sportStr=yundong.getString(0)+" "+yundong.getString(1); // lightStr=ziwaixian.getString(0)+" "+ziwaixian.getString(1); /** * Gson数据解析 */ WheatherBean wheatherBean=new Gson().fromJson(res,WheatherBean.class); String reason=wheatherBean.getReason(); if (reason.equals("参数不正确")){ handler.sendEmptyMessage(1); return; } WheatherBean.ResultBean resultBean=wheatherBean.getResult(); WheatherBean.ResultBean.RealtimeBean realtimeBean=resultBean.getRealtime(); WheatherBean.ResultBean.RealtimeBean.WindBean windBean=realtimeBean.getWind(); String time=realtimeBean.getTime(); WheatherBean.ResultBean.RealtimeBean.WeatherBean weatherBean=realtimeBean.getWeather(); String date=realtimeBean.getDate(); dateStr=time+date; weekStr=realtimeBean.getWeek(); calendarStr=realtimeBean.getMoon(); windpowerStr=windBean.getDirect()+" "+windBean.getPower(); temperatureStr=weatherBean.getTemperature(); weatherStr=weatherBean.getInfo(); WheatherBean.ResultBean.LifeBean lifeBean=resultBean.getLife(); WheatherBean.ResultBean.LifeBean.InfoBean infoBean=lifeBean.getInfo(); List<String> kongtiao=infoBean.getKongtiao(); List<String> yundong=infoBean.getYundong(); List<String> ziwaixian=infoBean.getZiwaixian(); ACStr=kongtiao.get(0)+" "+kongtiao.get(1); sportStr=yundong.get(0)+" "+yundong.get(1); lightStr=ziwaixian.get(0)+" "+ziwaixian.get(1); }
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值