python爬取天气与每日一笑并通过微信发送

最近在写一个跑在服务器上的脚本,需要实现的功能是每天九点同时给我和我的女朋友发送微信,内容是我俩相恋时间,今天的天气以及每日一笑。具体实现过程如下:

1.首先想到设定我俩确定关系的那天作为初始时间,利用time函数获取当前时间,然后将这两者的值相减。后来实现的时候还是遇到了一些问题,因为自己设定的时间只能是字符串形式或者整型值,虽然可以将time.time()进行格式化输出,然后转成整型进行相减。

但是这样设计到的问题就有点多,需要分别计算年数,月数和天数。这样虽然输出相恋x年x月x日比较方便,但是这样看起来没什么太大的感觉,不如xxxx天看起来更令人振奋。所以想要转换成天数进行输出展示。

这时涉及到了平年和闰年的问题,也涉及到了不同月份不同天数的问题。虽然实现是可以实现,但是本着不重复造轮子的宗旨,我还是上网搜了一下解决方案。

查看了一些方案,发现都是调用的datetime库。研究了一下发现datetime库确实非常适合解决我的问题。因为datetime.date()函数可以将用户输入转换为datetime类型,datetime.datetime.now()函数可以读取当前时间并格式化显示。最重要的一点,就是datetime类型可以直接进行加减,得出的就是两个日期之间的差值。

这时我们可以将其封装为 Cal_Date()函数,对其进行调用会return当前时间与设定时间之间的天数差。

def Cal_Date():
    First_Day_We_Loved = datetime.datetime(2012, 6, 27)
    Today = datetime.datetime.now()
    The_Day_We_Loved = Today - First_Day_We_Loved
    return The_Day_We_Loved.days

2.获取当前天气,直接百度搜索天气,弹出的第一个就是中国天气网。

爬取这些静态的网站还是比较简单的,对于目前我的一些需求,只需要requests就可以解决了,并不需要scrapy框架。为了锻炼自己的re水平,也没有用beautiful soap或者xpath进行内容提取。直接用re对获取的内容进行匹配,获取的天气的代码如下。

def fetch_weather():
    weather_url = 'http://www.weather.com.cn/weather/101010100.shtml'
    sess = requests.Session()
    res = sess.get(weather_url).content
    weather_pattern = r''
    weather_all = re.findall(weather_pattern, res)
    weather = str(weather_all).split(' ')[3].decode('string-escape')
    temper = str(weather_all).split(' ')[5].decode('string-escape').replace('\'', '').replace(']', '')
    return weather,temper

获取的时候还是遇到了一些问题,用re匹配到的weather_all是一个列表格式的,直接print可以输出中文。可是提取的列表中存在当前的日期,时间。这些不符合我想要的输出格式,所以需要对内容进行编辑。将weather转换为str后,内容全部变为\x43\x54这种16进制的文本。当时想着encode或者decode成utf-8,结果还是无法正常显示。后来找到一篇博客,对该问题进行了一些了解。

string-escape是对二进制的字节流,一个字节一个字节转义,并对每个字节以16进制输出,\xe4\xb8\xad就会先转成E4B8AD,然后再进行utf8转码,就可以正常显示了。这时就可以对字符串进行操作,以空格作为分隔符,取出想要的内容,然后解码成文字,最后返回天气和温度。

3.实现每日一笑,本来想着可以在网上直接找到某个每日一笑的网站,然后直接爬取再展示就行。结果搜了好久,并没有符合条件的网站。都是不定时的发几个笑话,然后没有稳定的更新。这时我考虑到了爬取网页上的文本,然后将其存储为txt文件,每次随机返回某一行。但是这个办法也有局限性,毕竟数据再大也有穷尽的一天,而且还需要占用很大的空间。

结果突然灵光一现,内涵段子不是很多笑话和段子吗,结果被封了。但是最近出了个皮皮虾,网上搜索发现皮皮虾只是一个app,并没有网页形式的,虽然可以通过某些方法获得网址,但是还比较麻烦。百度给我推荐了一个糗事百科,这个真是正中下怀。里面还有一个文本专区,正好方便我爬取。将爬取的代码封装成一个Daily_Laugh()函数,代码如下:

def Daily_Laugh():
    Laugh_url = 'https://www.qiushibaike.com/text/'
    sess = requests.Session()
    res = sess.get(Laugh_url).content
    #print res
    Laugh_pattern = r'(.*?)'
    Laugh_list = re.findall(Laugh_pattern, res,re.S)
    Laugh = Laugh_list[0].replace('
', '\n') return Laugh

中间也遇到了一个小问题,就是r'(.*?)'这个匹配规则匹配到了一些img的url,而不是我想要的文字。观察后发现因为中间的文字过多,导致不在一行,re匹配的时候就匹配了单行的,记得前几天学的时候好像有一个re.S可以匹配多行,所以尝试了一下,一发入魂~由于匹配到的是一个列表,所以返回最新一条就行了。

4.这时将上述函数的返回值组合起来,封装到daily_message()函数中。具体代码如下:

def daily_message():
    weekdic = {'Mon': '星期一', 'Tue': '星期二', 'Wed': '星期三', 'Thu': '星期四', 'Fri': '星期五', 'Sat': '星期六', 'Sun': '星期日'}
    date = time.strftime('%Y年%m月%d日', time.localtime(time.time()))
    week = time.strftime('%a', time.localtime(time.time()))
    daily = '今天是' + date + ' ' + weekdic[week] + ' ' + fetch_weather()[0] + ' ' + fetch_weather()[1] + ',' + '是我们相恋的第' \
            + str(Cal_Date()) + '天。'+ '\n' + '今日份的笑容:' + Daily_Laugh().strip()
    return daily

5.将拼装好的消息通过微信发送。

def send_wx(message):
    my_friend1 = bot.friends().search(u'————')[0]
    my_friend2 = bot.friends().search(u'————')[0]
    Message = unicode(message, 'utf-8')
    my_friend1.send(message)
    my_friend2.send(Message)

这个也出现了一些问题,还是编解码的问题。当时也是想直接decodeutf8,结果也无法实现。后来也是搜索了半天,尝试了各种方法,终于找到了现在的解决方法。

6.最后也是最重要的问题,如何将这个程序定时运行。最开始还是想用APScheduler,而把send_wx作为参数给APS中,结果提示错误, unbound method add_job() must be called with BlockingScheduler instance as first argument (got SentMessage instance instead),其实我也隐隐感觉这个可能存在问题,因为send_wx是一个动态的函数,APS传入的应该是一个可以循环多次执行的程序,所以不能执行。

后来考虑过用while和sleep,然后nohup。结果top一下发现占用cpu能达到98%,吓得我赶紧kill了他。后来就开始考虑,如果不能通过程序内设定,可不可以通过linux系统,设定固定时间执行脚本。然后就找到了crontab.

7.crontab是一个定时执行任务的服务.操作方法如下:

service cron start   //启动服务 
service cron stop    //关闭服务 
service cron restart //重启服务 
service cron reload  //重新载入配置
service cron status  //查看crontab服务状态
service cron start   //手动启动crontab服务
crontab -e           //添加任务
crontab -l           //查看当前任务

当时写了两条语句,发现把'hello’输出到log.txt是没问题的,可是下面的程序却怎么也执行不了。脚本内容如下:

#!/bin/bash
python dailys.py

在当前目录运行时是可以获得结果的,可是定时任务开启的时候却怎么也无法运行,不知道怎么回事。后来尝试了很久后,想着是不是只有在当前目录可以执行,别的目录不行?于是我在~/目录执行~/python/test.sh时出现了问题,可能是没写绝对地址,于是我加上了~/python/test.sh。这回是可以执行了,但是无法获取微信权限,无法进行好友列表的读取和发送。

在刚才查看wxpy文档时候注意到目录下的wxpl是一个缓存文件,只要有这个文件,就可以免登录执行程序,那么看来bash需要在当前目录执行脚本才能正常运行。那怎么才能进入当前目录呢?

我认为sh脚本应该就是在其中执行命令的,可以直接写语句,于是我在python前写了cd ~/python/。此时脚本如下:

#!/bin/bash
cd ~/python/
python dailys.py

这回手机上立马收到了消息,终于实现了!

查看一下最终收到的信息

这次的需求算是完成的比较圆满,下回再考虑干点别的,拜拜~~

点赞

发表评论

[2;3Rer>