文章目录
- 前言
- 实现思路
- 实现过程
- 寻找目标网站
- 爬取目标网页
- 解析网页整理数据
- 创建语音接口
- 将数据与接口对接实现效果
- 实例全代码
- 脚本打包
- 总结
前言
Python是一门很强大的语言,用它可以做到很多事情,我自己也学Python一些天了,也了解了一些知识,最近忙于整理比较重要的知识写成博客记录下来,可是心里突然总想着要用Python做点什么有意思的事情,就想到了这里,用它写个简单的脚本能够爬取最近的天气情况并且实现语言播报,最后给打包成exe程序后放在电脑桌面,再也不用打开手机或者打开网站查看天气了哈哈。
实现思路
- 首先,爬取天气情况首先要找个天气网站,然后用爬虫爬取网页,再解析网页获得我们需要的天气信息,然后把数据整理一下变成便于我们操作的形式。然后实现语言播报有几种方法,比较方便的是使用
pyttsx3
这个库,它可以很方便的将字符串转化为语言播放,但我在这里使用的是百度的API接口(可能因为声音好听吧哈哈哈),在百度AI开放平台上它们提供了很多接口供我们使用,包括语音合成、图片识别等等一些高端接口,我们只需要在上面创建接口供我们调用就行(注意百度接口的使用需要联网),在这里我利用百度提供的接口将目标字符串合成为.mp3
格式文件,然后使用playsound
库将其播放,最终达到我们想要的效果,下面是思路实现流程图:
实现过程
寻找目标网站
天气网站有很多哈,然后我就随便找了一个,到底多随便呢,我只是打开我电脑上的QQ浏览器,如图:
看网页上边不是有天气情况吗,点击打开就好,如下:
好了,等我打开这个网页,哇塞,数据也挺详细的了,行吧,这就是我要爬取的网页了,到这里目标网站已经找好,是不是既方便又随意,接下来就是希望我能成功获得我想要的数据了,首先想一下,我想要的数据也就是最近几天的天气状况比如阴天晴天之类的以及最高温度最低温度罢了,要的数据并不多,这些在网页上都有,于是开始下一步。
爬取目标网页
首先鼠标右键点击查看网页源代码,如下:
因为本来这个网页里边杂七杂八的东西都比较少,所有打开源代码看一下,结构是非常清晰的,接下来就是需要找到我们想要的数据了,可以通过快捷键ctrl+f
的形式对我们要的数据进行查找,不过因为网页内容比较少,我随意往下滑了两下就看到了我想要的数据:
简单分析一下,我们要的数据(日期、天气情况)都被封装在一个li
的大标签之中,而它们自身也被封装在相应的name
(名字)为p
,attrs
(属性)分别为date和des
的子标签中,不过,等等,我好像没看到温度的数据啊,别急再往下滑一下:
看到了吗,它们是被单独封装在了属性为r-temp
的div
标签中了,那么到现在为止我们想要的数据都已经找到,并且它们都被特定的标签封装,因此我们使用BeautifulSoup
库可以非常非常方便的得到我们想要的数据。所以你觉得好搞吗?好搞!那就开搞!
首先,定义一个函数,用来得到网页信息,废话不多说,直接上代码:
def gethtmltext(url):try:r = requests.get(url)r.raise_for_status()r.encoding = r.apparent_encodingreturn r.textexcept:return print('爬取有误')
OK,仅仅需要这几行代码,我们已经爬取了这个网页。
解析网页整理数据
网页内容都给爬取了下来,接下来就需要对数据进行整理了,整理的这个过程是最头疼的,因为我水平有限很多东西不了解,我使用的方法可能非常繁琐,不过好在还是整理成功了,这时候我的目标是定义一个函数,通过输入我们刚才爬取的网页的信息,来对我们需要的那几样数据进行提取整理并最终放进一个列表中供我们使用,话不多说,还是上代码:
def putweather(html):soup = BeautifulSoup(html,'html.parser') #将获得的响应文本树形解析date = soup.find_all('p','date') #找到所有标签名称为P,属性为date的标签date_str_list = []for i in range(7):date_str_list.append(str(date[i]))date_list = []for i in range(7):date_list.append(date_str_list[i][16:21]) #解析出日期并放进一个列表#日期列表即为date_listdes = soup.find_all('p','des') #同上des_str_list = []for i in range(7):des_str_list.append(str(des[i]))des_list = []for i in range(7):des_list.append(des_str_list[i][15:23])new_des_list = []des___list = []for i in range(7):new_des_list.append(des_list[i].split('<')) des___list.append(new_des_list[i][0]) #解析出天气情况并放进列表#des___list即为天气列表temp = soup.find_all('div','r-temp')str_temp = str(temp)temp_str = str_temp.split('"')temp_data_list = []temp_data_list.append(temp_str[3])temp_data_list.append(temp_str[5])temp_data_high = []temp_data_low = []high_list = temp_data_list[0].split(',')low_list = temp_data_list[1].split(',')for i in range(7):temp_data_high.append(high_list[i])temp_data_low.append(low_list[i])All_list = []All_list.append(date_list)All_list.append(des___list)All_list.append(temp_data_high)All_list.append(temp_data_low)return All_list
好的,到现在为止我们想要的信息已经整理好,所有需要的数据被存放在All_list
列表中,给大家看一下其样子:
[[‘02-18’, ‘02-19’, ‘02-20’, ‘02-21’, ‘02-22’, ‘02-23’, ‘02-24’], [‘晴转多云’, ‘阴’, ‘阴’, ‘晴’, ‘晴’, ‘阴’, ‘小雨’], [‘14’, ‘13’, ‘14’, ‘16’, ‘14’, ‘18’, ‘16’], [‘2’, ‘0’, ‘1’, ‘2’, ‘1’, ‘3’, ‘3’]]
所有的数据被工整的存在列表中,不过大家可能有疑问,今天是2月19号,要2月18号的数据有什么用哈哈,答案是:没有用!!这是网页里边显示的,我也没办法,没必要提取的时候对它单独进行筛选了,只是在等会我们播报的时候忽略它就行了。
OK,到现在为止数据也已经整理好,我们想让程序让语言给播放出来,就需要搞个语音接口了。
创建语音接口
在这里说明一下,使用百度的API你需要在其平台上注册账号并且创建应用,在应用创建成功后会得到其发给你的密匙,同时网站上面还有调用的SDK文档,使用起来非常简单,不懂的大家伙可以看一下其它人的博客有很多教程,不过很简单的,相信我你只要点进去就会用了哈哈哈,百度AI开放平台链接如下:
https://ai.baidu.com/?track=cp:aipinzhuan|pf:pc|pp:AIpingtai|pu:title|ci:|kw:10005792
对于我们将要创建的语音接口,我的想法是输入字符串让其将对应的语音播报即可,话不多说,还是上代码:
def words_to_voice(astring):# 你的 APPID AK SKglobal kk = k+1APP_ID = '这里是你的APP_ID'API_KEY = '这里是你的API_KEY'SECRET_KEY = '这里是你的SECRET_KEY'client = AipSpeech(APP_ID, API_KEY, SECRET_KEY)string = astringresult = client.synthesis(string,'zh', 1, {'spd':4,'vol': 6,'per':0})if isinstance(result, bytes):with open(str(k)+'result.mp3', 'wb') as f:f.write(result)else:print('有误')playsound(str(k)+'result.mp3')os.remove(str(k)+'result.mp3')
对于本例代码我稍微解释一下,因为百度API提供的是语音合成功能,并不是播放功能,因此用到了playsound
来播放语音,同时用到os
库来将播放过的mp3
文件删除,至于为什么代码中用到全局变量k
,是用来给创建的mp3
文件进行不同的命名,因为在我自己是实现过程中发现,假如每次的命名相同的话,即使在语音播放完毕后将文件关闭并且删除,从程序第二次开始调用函数开始就会没有权限打开创建这个刚关闭删除的同名文件,程序会报错退出,这一点我也搞不懂为什么,于是我想办法这样避免了那个问题,还请有大佬看到的话教一下我为什么,麻烦了,哈哈。
将数据与接口对接实现效果
这点就比较简单了,又是直接上代码:
if __name__ == '__main__':k = 1url = 'https://tianqi.sogou.com/?tid=101180403(这里是我们爬取网页的网址,我附带的这个是我家乡这里的哈哈)'html = gethtmltext(url)finall_list = putweather(html)print(finall_list)words_to_voice('您好,我的主人,我将为您播报最近六天的天气情况')for i in range(1,7):word_str = '{}月{}日的天气是{},最高温度是{}摄氏度,最低温度是{}摄氏度'.format(finall_list[0][i][1],finall_list[0][i][3:5],finall_list[1][i],finall_list[2][i],finall_list[3][i])words_to_voice(word_str)
实例全代码
import requests
from bs4 import BeautifulSoup
import os
from playsound import playsound
from aip import AipSpeechdef gethtmltext(url):try:r = requests.get(url)r.raise_for_status()r.encoding = r.apparent_encodingreturn r.textexcept:return print('爬取有误')
def words_to_voice(astring):# 你的 APPID AK SKglobal kk = k+1APP_ID = '你的APP_ID'API_KEY = '你的API_KEY'SECRET_KEY = '你的SECRET_KEY'client = AipSpeech(APP_ID, API_KEY, SECRET_KEY)string = astringresult = client.synthesis(string,'zh', 1, {'spd':4,'vol': 6,'per':0})if isinstance(result, bytes):with open(str(k)+'result.mp3', 'wb') as f:f.write(result)else:print('有误')playsound(str(k)+'result.mp3')os.remove(str(k)+'result.mp3')def putweather(html):soup = BeautifulSoup(html,'html.parser') #将获得的响应文本树形解析date = soup.find_all('p','date') #找到所有标签名称为P,属性为date的标签date_str_list = []for i in range(7):date_str_list.append(str(date[i]))date_list = []for i in range(7):date_list.append(date_str_list[i][16:21]) #解析出日期并放进一个列表#日期列表即为date_listdes = soup.find_all('p','des') #同上des_str_list = []for i in range(7):des_str_list.append(str(des[i]))des_list = []for i in range(7):des_list.append(des_str_list[i][15:23])new_des_list = []des___list = []for i in range(7):new_des_list.append(des_list[i].split('<'))des___list.append(new_des_list[i][0]) #解析出天气情况并放进列表#des___list即为天气列表temp = soup.find_all('div','r-temp')str_temp = str(temp)temp_str = str_temp.split('"')temp_data_list = []temp_data_list.append(temp_str[3])temp_data_list.append(temp_str[5])temp_data_high = []temp_data_low = []high_list = temp_data_list[0].split(',')low_list = temp_data_list[1].split(',')for i in range(7):temp_data_high.append(high_list[i])temp_data_low.append(low_list[i])All_list = []All_list.append(date_list)All_list.append(des___list)All_list.append(temp_data_high)All_list.append(temp_data_low)return All_listif __name__ == '__main__':k = 1url = '你要爬取的网页地址'html = gethtmltext(url)finall_list = putweather(html)print(finall_list)words_to_voice('您好,我的主人,我将为您播报最近六天的天气情况')for i in range(1,7):word_str = '{}月{}日的天气是{},最高温度是{}摄氏度,最低温度是{}摄氏度'.format(finall_list[0][i][1],finall_list[0][i][3:5],finall_list[1][i],finall_list[2][i],finall_list[3][i])words_to_voice(word_str)
- 这个程序中总共用到了5个第三方库,其中
requests
、和BeautifulSoup
库就不用说了,如果你没有用过BeautifulSoup,那么值得一提的是它是bs4的子库,在安装的时候需要安装bs4
库,另外os
库是标准库,我的上一篇博客有很多相关重要函数,有兴趣的大家可以去看一下掌握以下:
《能让你解放鼠标的Python标准库-os》
以及还有关于Requests
库的一篇方法解析博客:
《爬虫入门-Requests库》
另外还需要安装playsound
库以及baidu-aip
库,前者用来播放mp3
文件,后者包含我们要用的AipSpeech
子库,实际上baidu-aip
包含所有的调用百度API的子库,使用百度API的其它功能如图片识别也需要安装baidu-aip
,只是使用的子库不一样了,这点在其SDK文档上面都有示例。
另外,如果你是新手,以上安装各个库的方法均是使你的电脑连接互联网,并用管理员身份打开cmd
命令行,输入以下命令即可。
pip install XXX(库名)
脚本打包
打包是为了方便我们的使用,如将打包好的exe
应用程序放在桌面,双击即可使用,另一点是使其可以摆脱Python
环境,让这个程序可以在其它的环境下运行,这个时候你也可以将其直接发给你的朋友了。
打包的方法很简单,也是使用一个第三方库Pyinstaller
,这个库有一些参数,那些参数可以让你更改打包后程序的图标什么的等等,在这里不再详细介绍,只负责可以将你的.py
文件打包成.exe
程序即可,安装这个库的方法也是使用pip
,方法如上文所述,打包具体方法可以参考我的博客,里面有详细介绍:
《库引用、库安装、说明文档查看、文件打包》
总结
- 这个我们希望爬取的网页其实很简单,但我在数据提取存放那里用了很长的冗余代码,甚至很多人根本看不懂,不过代码写成这样也是水平所限,简单的方法不会,只能用非常笨的方法解决,不过还是将数据给提取出来了,提取出来的数据很少,不过有了思路及方法,其它的数据也是可以提取出来了,在这里我只提取了这么点数据,大家有想法的可以去试试多提取一些数据,将程序完善成为你期望的样子,总的来说,效果还是让我满意,路还很长,加油!