本文是原创文章,如有转载请注明出处!
开发环境:python3.8+pycharm2020专业版+双核浏览器
用到的库:python标准库time库+第三方库requests、xpath、pyecharts
(请在下载安装pyecharts的时候使用pip install pyecharts==0.1.9.4,否则在后期导入第三方库的时候会出现问题)
服务器:阿里云esc服务器+centos7操作系统
先给出我们要爬取的网页http://www.weather.com.cn/textFC/**.shtml#因为在中国天气网上将全国分为了华北、华南、华东、华中、东北、西北、西南、港澳台这几个地区(本文不爬取港澳台地区),而每个地区的url不一样,使用*来代替不同地区对应的url的不同之处
这里我们给出截图
这里我们以华北地区为例来讲解,地址:http://www.weather.com.cn/textFC/hb.shtml#,首先在日期栏点明天对应的日期,然后按下F12打开开发者模式,然后按下ctrl+shift+c选择元素,当我们选择北京这个盒子的时候会发现如下结果:
可以看到北京对应的内容在class=hanml的div下的第二个盒子,经过分析小编发现这个class=hanml的div下的每一个div对应该地区所有省份一天的天气。接下来我们分析北京所对应的这个盒子,如图:
发现这个盒子包含一个tbody标签,在这个标签下的tr从第三个开始,每一个tr标签代表北京的一行数据,然后我们可以从每一个tr标签的第二个td(width=83)下获得城市名称,width=92的td下获得最高温度,width=86的td下获得最低温度。
因为不同地区的天气所对应的盒子的网页布局完全一致,因此我们分析了一个盒子就可以循环获取所有的地区,这也是爬虫可以获取大量信息的基础。
话不多说,直接来干货
因为讲解原因,这里分块给出代码,但是只需要按顺序复制就是可以运行的完整代码
先来导入需要的库
import time
import requests
from lxml import etree
from pyecharts import Bar
然后是全局变量
ALL_CITY_DATA = [] # 创建一个列表,用来存储所有城市的信息,每个城市的信息是字典
BASE_URL = 'http://www.weather.com.cn/textFC/{}.shtml' # 不同地区的天气预报的url的共有部分
再然后是爬取一个网页的函数
# 爬取一个网页数据
def get_data(location):
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
} # 定义请求头
try:
response = requests.get(BASE_URL.format(location), headers= headers)
response.raise_for_status()
response.encoding = 'utf-8' # 转换编码方式,否则得到乱码
# 在打开文件的时候需要指出编码方式,否则会报错
with open('data.txt', 'w', encoding='utf-8') as fp:
fp.write(response.text)
except:
print("爬取数据失败")
然后是解析爬取下来的网页数据的函数,这里我们用xpath去获得需要的内容,当然也可以使用bs4.
这里简单讲解一下xpath语法,/:①代表根节点②获取某目录下的子节点;//:从当前节点下选取符合的所有节点,不考虑子孙关系;xpath("//div[@class=’’, id=’’]")——获取属性class=’’&&id=’'的div标签;xpath(‘.//a/@href’)——获取a标签的href的属性值
# 解析网页数据
def get_usefuldata():
with open('data.txt', 'r', encoding='utf-8') as fp:
text = fp.read()
html = etree.HTML(text)
divs = html.xpath("//div[@class='hanml']/div[2]/div") # 取到明天天气对应的多个div,每一个div代表一个地点
for div in divs:
trs = div.xpath("./table//tr[position()>2]") # 获取第三个及其以后的tr标签
for tr in trs:
city_data = {}
city_data['city_name'] = tr.xpath("./td[@width='83']/a/text()")[0] # 得到城市名称
city_data['max_tem'] = int(tr.xpath("./td[@width='92']/text()")[0]) # 得到城市最高气温
city_data['min_tem'] = int(tr.xpath("./td[@width='86']/text()")[0]) # 得到城市最低气温
ALL_CITY_DATA.append(city_data) # 将一个城市的数据以字典类型加入到全局变量ALL_CITY_DATA中
接下来是对ALL_CITY_DATA的排序,并且返回排在前十的城市数据,方便接下来做可视化处理
这里讲一下sort函数,这里用到这个函数的两个参数,reverse是否降序,默认为flase;key的作用是确定按照可迭代对象的哪个值排序。再讲一下lambda,这是匿名函数的关键字,适合写一行代码就能完成的函数,lambda x: x[‘max_tem’]代表传入参数x,返回值是x[‘max_tem’]
# 对所有信息进行排序,并取前十
def data_sort(min_or_max):
if(min_or_max == 'max'):
ALL_CITY_DATA.sort(key=lambda x: x['max_tem'], reverse=True) # 按照最高气温对ALL_CITY_DATA排序
elif(min_or_max == 'min'):
ALL_CITY_DATA.sort(key=lambda x: x['min_tem']) # 按照最低气温对ALL_CITY_DATA排序
else:
print('传参错误')
return ALL_CITY_DATA[0:10] # 取前十名
接下来就是简单的可视化处理,这里我们打算将其做成直方图,这里我们再来讲一下map函数,map第一个参数是一个函数,第二个参数是一个可迭代对象,将可迭代对象中的每一个都放到函数中执行一遍,返回值是一个可迭代对象
# 简单的可视化处理
def data_vis():
# 处理最高气温
data_max = data_sort('max')
city_max_names = list(map(lambda one_data: one_data['city_name'], data_max)) # 使用list()将map返回的可迭代对象转化为一个列表
max_tems = list(map(lambda one_data: one_data['max_tem'], data_max))
bar = Bar('最高温排行榜') # 创建一个Bar对象,参数是直方图的标题
bar.add('温度', city_max_names, max_tems) # 第一个参数是直方图的竖线代表的内容,第二个参数是横坐标,第三个参数是纵坐标
bar.render('最高气温排行榜.html') # 对图表进行渲染,参数是文件名以及路径,这里我们保存到当前目录
# 处理最低气温
data_min = data_sort('min')
city_min_names = list(map(lambda one_data: one_data['city_name'], data_min))
min_tems = list(map(lambda one_data: one_data['min_tem'], data_min))
bar = Bar('最低温排行榜')
bar.add('温度', city_min_names, min_tems)
bar.render('最低气温排行榜.html')
最后再给出我们的主程序
def main():
locations = ['hb', 'db', 'hd', 'hz', 'hn', 'xb', 'xn'] # 不同地区的url的不同部分
for location in locations:
get_data(location)
get_usefuldata()
data_vis()
if __name__ == '__main__':
while True:
time_now = time.strftime("%H:%M:%S", time.localtime()) # 永不停歇的刷新当前时间
if time_now == "07:00:00": # 此处设置每天早上7点执行程序
main()
time.sleep(2) # 因为以秒定时,所以暂停2秒,使之不会在1秒内执行多次
到此,我们的项目代码部分就完成了!
接下来我们讲讲如何将项目部署到服务器上。
先来说说服务器的好处,对于这个项目,只要我们将项目部署到服务器上并且后台运行以后,我们自己的电脑就可以 关闭程序了,但是该程序依旧在运行,一到7点就会自动执行,完全不需要我们去操心。
然后再来介绍一下利用pycharm如何将项目部署到自己的服务器上,注意pycharm专业版才可以部署项目。进入pycharm选择Tools下的Deployment下的cunfiguration,然后点击左上角的加号,选择sftp然后随便起一个名字,然后出现以下界面:
点击图片的1处,输入你的服务器的公网ip、密码等账户信息然后点击ok,然后在图片的2处填上你的公网ip,注意它的上一个空不需要更改。然后再点击图片的3处,来到一下界面:
1处是指你当前电脑的项目绝对路径,2处是你想要把你的项目上传到服务器的哪个目录(一般新建一个文件来存放项目)配置完项目路径以后点击ok。
写下来上传项目,先单击项目,然后点击Tools下的Deployment下的第一个选项就可以上传项目了。
然后我们需要点击pycharm底部的Terminal
然后在弹出的终端输入ssh -p 22 root@公网IP 然后会提示你输入密码,输入完密码后就成功连接了。
(如果服务器上还没有下载python3,就需要在终端输入(一步一步来):
sudo yum -y groupinstall “Development tools”
sudo yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel libffi-devel
wget https://www.python.org/ftp/python/3.7.3/Python-3.7.3.tar.xz
tar -xvJf Python-3.7.3.tar.xz
cd Python-3.7.3
./configure --prefix=/usr/local/bin/python3
sudo make
sudo make install
安装好以后可以创建软连接,命令为:
ln -s /usr/local/bin/python3/bin/python3 /usr/bin/python3
ln -s /usr/local/bin/python3/bin/pip3 /usr/bin/pip3
最后敲入命令python3 --version检查一下是否是python3的版本)
我们需要在服务器上下载安装对应的第三方库,pip3 install pyecharts==0.1.9.4
pip3 install requests pip3 install lxml
安装完以后在pycharm的终端使用cd命令,进入到你的项目所在路径,然后输入nohup python3 文件名.py 2>&1 | tee &就可以在后台运行程序了,这时项目就部署到服务器并且后台运行了,你就可以关掉与服务器的连接,关闭pycharm了。
到此,我们的全部工作就完成了。