用perl脚本获取天气
前言
说一下这个想法的由来。其实最初目的不是为了获取天气的,这只是一个练习而已。最初是想自动获取公司的出勤情况,提醒我前一天有没有忘记打卡的。公司打卡是由网站可以查询的,有时忘记了或者系统出错,可能当天打卡没有打上,不去查看的话就记为缺勤了(这可是关乎工资啊啊啊啊),于是想到了每天定时执行一次查询任务,要是差到有缺勤记录就在登录系统时发出提示。所以作为一个初学者我就自然想到怎么获取网站固定信息了。由于在公司是内网,无法在家测试,所以就写个查询天气的脚本来确定基本的脚本结构。
原理
原理呢,其实就是字符串的处理。我知道可以用网站的api发出请求,然后返回数据,这样更加方便快捷。但是,我不是学软件的不会这个,233333。当然 这不是理由,可以去学,只是有更简便的方式。我选择将网页源码下载下来然后分析字符获取字段,毕竟如果登录网页能看到信息,那么在网页的html里应该也有这个字段。那么现在大概的步骤就明确了:
- 下载网页源码。
- 查看源码,分析关键字段的特征,从而能够查找匹配。
这种方式只适合不需要网页交互的查询,假如查询时还要输入密码这些就不能查到了。只要在浏览器直接输入网址就能访问的网页可以用这种方法查询需要的信息。
详细分析
在这里我选取中国天气网上海天气来作为查询的网址。首先用浏览器将网页另存为html格式,然后查看文本内容(在这里推荐使用代码编辑器查看,浏览器有浏览网页源码功能的也可以查看。我将网页文件传到树莓派用vim查看了,后面perl也是在树莓派上写)。用vim查看代码,然后搜索日期,天气应该是按日期来排的。太幸运了,直接就搜到了:
天气信息所在行实在是easy啊。那么我们来分析这一行。
<input type="hidden" id="hidden_title" value="10月27日20时 周五 晴转多云 16/22°C" />
这一行的分析思路有以下几点:
- 这一句是通过搜索日期的到的,那么我们可以在代码中使用查找日期来定位这一行。
- 我们需要的天气信息在
value=
关键词后面用双引号包起来的字段,我们可以在定位行后在行里定位字符串value=
,相信这不难做到。最简单粗暴的方式就是用数组把每个字符保存起来,然后一个一个遍历。这一行的字符也不多,占用内存也不大。 - 我还发现,我需要的字段被双引号
"
包起来,那么我联想到perl中的split
函数。可以将这一行用split
函数将字符分解为以"
隔开的列表,这样我们只要访问列表元素就可以了。
代码实现
首先使用shell的curl
命令下载网页。这里解释一下为什么不用perl
的命令(当然是因为技术不好啊_)。perl对网络的操作好像需要一些模块,不知道这些模块是安装perl
时自带的还是需要额外添加,也不确定公司的perl
是不是带有这些模块。但是shell的curl
命令是自带的,我就使用shell命令来下载网页了。在perl
中调用shell命令表达如下:
`curl -o wether.html http://www.weather.com.cn/weather/101020100.shtml`
注意两边的单引号!网址中的101020100.shtml
指的是上海的天气页面,不清楚具体城市编码方式,可以一个一个去网站查询看。命令中的-o wether.html
参数指的是将下载的网页另存为wether.html
文件。
下载好网页后就可以以文本方式读取网页内容了。在处理文件字符之前,我们需要获得查询的关键字,也就是日期。获得关键字后去读取文件每一行,并判断当前行是否包含关键字,包含关键字则将当前行分解为列表,得到列表就可以输出天气信息了。
最后得到代码如下:
#!/usr/bin/perl -w
`curl -o wether.html http://www.weather.com.cn/weather/101020100.shtml`;
if ( ! open HTML,'<','wether.html' ) {
die "cannot open:$!"; #文件打开失败提示
}
$date =`date`; #获取当前时间
chomp($date);
@date_list = split /\s+/,$date; #将获取到的时间以空格分解,提取出日期。也可以通过控制
#获取时间命令的参数来直接获得日期。比如 date "+%m月%d日"
#这样就可以直接获取"x月x日"格式的时间
while (defined ($line = <HTML>)) { #读取文件每一行到$line变量里
$gre=(grep /$date_list[2]/,$line) + (grep /value=/,$line);#如果有日期,又有value关键词,则认为找到了
if ($gre == 2){
@val_list=split /"/,$line; #将文本行以"为分隔符分解字段
print $val_list[5]."\n"; #天气信息在列表元素5里
last;
}
}
close HTML;
以上就是代码实现过程,很简单的几行就搞定了。方法很偏门啊,慎用。
运行结果
脚本运行结果想要获取更准确更实时的数据也可以在网页中继续查找,主要是字符串的定位问题。更简单粗暴的方式是查看数据在哪一行,直接跳到那一行去分解字符串获取数据,这就免得去分析查找的关键字怎么获取了。但这种方法的前提是网页的内容变动不太大,需要的信息总是出现在那一行。就天气来说,网页内容还是比较固定的,可以采用这种方式。