基于Python的天气API


 ██████╗ ███████╗██████╗ ██╗   ██╗███████╗
██╔═══██╗██╔════╝██╔══██╗╚██╗ ██╔╝██╔════╝
██║   ██║███████╗██████╔╝ ╚████╔╝ █████╗  
██║▄▄ ██║╚════██║██╔══██╗  ╚██╔╝  ██╔══╝  
╚██████╔╝███████║██████╔╝   ██║   ███████╗
 ╚══▀▀═╝ ╚══════╝╚═════╝    ╚═╝   ╚══════╝
                                          

保命声明:笔者代码能力有限,若行文中有错漏之处欢迎大家指出。

天气数据获取

苏州
广州
Python爬虫入门抓取天气信息
Python爬取天气数据

功能介绍

访问http链接,可以以JSON格式获得当日天气、温度、天气资讯.

实现

流程图

数据获取 网络服务

代码

LICENSE Mulan PSL v2

#!/usr/local/bin/python3.7
#-*-encoding:UTF-8

'''
**main.py**
- 主要功能:定时获取天气信息,发出json文件
- 维护:qsbye
- 邮箱:2557877116@qq.com
- LICENSE:Mulan PSL v2
- 依赖第三方库:schedule,BeautifulSoup4,requests,gmssl,base64
'''

'''开始import'''
import sys #系统
import os #系统
import time #时间
from datetime import datetime #时间
import requests #获取网页
from bs4 import BeautifulSoup #解析网页
import sqlite3 #数据库
import json #json操作
import schedule #定时任务
import socket #网络
from urllib.parse import unquote,quote#解析字符串
from gmssl import sm2 #国密算法
from base64 import b64encode,b64decode #base64操作
'''结束import'''

'''开始全局变量'''
pass

'''结束全局变量'''

'''
@分类:获取数据&数据库操作
'''
class Database_Class:
    '获取当日天气信息并保存到数据库'
    #初始化
    def __init__(self):
        pass
    '''
    @功能:调用获取天气信息函数
    '''
    def Update_weather(self):
        print("获取天气数据,now:",datetime.now().strftime("%Y.%m.%d %H:%M:%S"))
        self.main()
    '''
    @功能:获取天气网天气信息
    返回:字典容器
    '''
    def Get_weather_info(self):
        res = requests.get('http://www.weather.com.cn/weather1d/101280101.shtml')
        res.encoding = 'utf-8'
        html = res.text
        soup = BeautifulSoup(html,'html.parser')#解析文档
        #tz=pytz.timezone('Asia/Shanghai')
        os.environ['TZ'] = 'Asia/Shanghai' #设置时区
        #获取完整信息"02月09日08时 周四  小雨  23/17°C" 
        weather_full_info=soup.find(id="hidden_title")['value']
        #print(weather_full_info)
        weathers=soup.find(class_="today clearfix",id="today").find("ul",class_="clearfix").find_all('li')
        weather_tqzx=soup.find(class_="con today clearfix").find(class_="left fl").find(class_="tq_zx",id="tq_zx").find_all("dd")
        my_weather_today={ \
        'weather_wea':weathers[0].find('p',class_="wea").text, \
        'weather_tem':weathers[0].find('p',class_="tem").text, \
        'weather_wind':weathers[0].find('p',class_='win').find('span').text, \
        'weather_source':"中国天气网", \
        'update_time':datetime.now().strftime("%Y.%m.%d %H:%M:%S"), \
        'weather_full':soup.find(class_="con today clearfix").find(class_="left fl").find(class_="today clearfix",id="today").find(id="hidden_title")['value'], \
        'weather_city':soup.find(class_="con today clearfix").find(class_="left fl").find(class_="left-div").find(class_="ctop clearfix").find(class_="crumbs fl").find_all('a')[2].text \
        }
        my_weather_today['weather_news']=[]
        for zx in weather_tqzx:
            my_weather_today['weather_news'].append(zx.find('a').text)
        return my_weather_today
    '''
    @功能:获取心知天气信息
    返回:字典容器
    '''
    def Get_weather_info2(self):
        pass
    '''
    @功能:存储天气信息到数据库,TODO:添加信息有效期
    输入:字典
    '''
    def Save_to_database(self,input):
        #获取今日天气
        weather_today=self.Get_weather_info()
        #调试:打印
        #print('天气资讯:',weather_today['weather_news'])
        #连接数据库
        conn=sqlite3.connect('./files/weather.db')
        #数据库游标
        cursor=conn.cursor()
        #创建表(sqlite语句)
        SQL_CREATE_TABLE= \
        '''
            CREATE TABLE IF NOT EXISTS weather
            (city text,
            wea text,
            temperature text,
            wind text,
            update_time text,
            source text,
            news text
            );
        '''
        #插入数据(sqlite语句)
        SQL_INSERT_DATA= \
        '''INSERT INTO weather(city,wea,temperature,wind,update_time,source,news) values(?,?,?,?,?,?,?);'''
        #转换列表为字符串
        weather_news=','.join(weather_today['weather_news'])
        data=[
            (weather_today['weather_city'],weather_today['weather_wea'],weather_today['weather_tem'], \
            weather_today['weather_wind'],weather_today['update_time'],weather_today['weather_source'], \
            weather_news \
            )
        ]
        #通过上下文与数据库交互
        with conn:
            conn.execute(SQL_CREATE_TABLE)
            conn.executemany(SQL_INSERT_DATA,data)
            #conn.commit()
    '''
    @功能:查表获取天气
    返回:天气数据字典
    '''
    def Query_database(self):
        #打开数据表
        try:
            conn=sqlite3.connect("./files/weather.db")
        except IOError:
            print("Error:没有找到文件或读取文件失败")
        else:
            print("打开数据库成功")
        #查询数据
        SQL_QUERY="SELECT * FROM weather WHERE city = '广州'"
        #通过列名读取数据
        conn.row_factory = sqlite3.Row
        with conn:
            data_s=conn.execute(SQL_QUERY)
            '''
            data_dict={'weather_city':data_s.fetchall()[0]['city'],'weather_wea':data_s.fetchall()[0]['wea'],'weather_tem':data_s.fetchall()[0]['temperature'], \
                        'weather_wind':data_s.fetchall()[0]['wind'],'update_time':data_s.fetchall()[0]['update_time'],'weather_source':data_s.fetchall()[0]['source'] \
                        'weather_news':data_s.fetchall()[0]['news'] \
            }
            '''
            for data in data_s:
                data_dict={'weather_city':data['city'],'weather_wea':data['wea'],'weather_tem':data['temperature'], \
                'weather_wind':data['wind'],'update_time':data['update_time'],'weather_source':data['source'], \
                'weather_news':data['news'] \
                }
        return data_dict
    '''
    @功能:封装数据到json文件
    输入:数据字典,token
    输出:json
    '''
    def Put_data_into_json(self,data,token):
        #判断数据
        if(data['weather_city']!='' or data['weather_city']!=None):
            #传入的是天气数据
            #字典类型转换为JSON对象
            data['token']=token
            json_str=json.dumps(data)
            #调试
            print(json_str)
            #写入JSON文件
            with open('./files/weather.json','w') as f:
                json.dump(data,f)
            return json_str
    '''
    @功能:主函数
    '''
    def main(self):
        self.Save_to_database(0)
        self.Put_data_into_json(self.Query_database(),'1234')
    

'''
@分类:权限控制
TODO:⬇️
'''
class Access_Class:
    pass

'''
@分类:定时任务
'''
class Task_Class:
    '配置定时任务'
    #初始化
    def __init__(self):
        pass
    '''
    @功能:定时任务配置
    '''
    def Schedule_task_init(self):
        print("配置定时任务")
        #每天0:15执行任务
        schedule.every().day.at("00:15").do(Database_Class.Update_weather)
        #添加到循环
        '''
        while 1:
            schedule.run_pending()
        '''

'''
@分类:http服务端
端口:10001
请求:http://127.0.0.1:10001/?file=now.json&key=FTudvvro3fWxMuhW&location=guangzhou
'''
class Web_Server_Class:
    '服务端'
    self_key="FTudvvro3fWxMuhW"
    print("self_key:",self_key)
    port=10001
    #初始化
    def __init__(self):
        pass
        self.s=socket.socket()
        #读取json文件
        with open('./files/weather.json','r') as f:
            self.text=f.read()
        #绑定ip与端口
        self.s.bind(('0.0.0.0',Web_Server_Class.port))
        #开始监听,可以处理5个请求
        self.s.listen(5)
        print("socker监听中...")
    '''
    @功能:解析请求头
    '''
    def Parse_request(self,request):
        raw_list = request.split("\r\n")
        request = {}
        for index in range(1, len(raw_list)):
            item = raw_list[index].split(":")
            if len(item) == 2:
                request.update({item[0].lstrip(' '): item[1].lstrip(' ')})
        return request
    '''
    @功能:分离参数
    返回:字典
    '''
    def Parse_parameters(self,input):
        #分离?之后的内容
        input=input.split('?')[1]
        #分离空格之前内容
        input=input.split(' ')[0]
        print('?之后内容',input)
        args=input.split('&')
        query={}
        for arg in args:
            key,value=arg.split('=')
            print('key:',key,'value:',value)
            query[key]=unquote(value)
        return query
    '''
    @功能:处理网络请求
    '''
    def Handle_http(self):
        #while 1:
            #建立连接
            conn,addr=self.s.accept()
            print('与',addr,'建立连接')
            #解析字节流
            req=conn.recv(1024).decode('utf-8')
            print('接收到:',str(req),'来自:',conn.getpeername())
            #解析参数
            self.Parse_parameters(req)
            #发送json数据(带完整http response返回格式)
            response = 'HTTP/1.1 200 OK\r\nContent-Type: text/plain;charset=utf-8\r\nContent-Length: ' \
                            '{length}\r\n\r\n{body}'.format(length=len(self.text.encode("utf-8")), body=self.text)
            conn.sendall(response.encode('utf-8'))
            #发送数据,默认为utf-8编码
            conn.send('connected'.encode('utf-8'))
            #关闭连接
            conn.close()
            #不让再次连接了
            #break
    '''
    主函数
    '''
    def main(self):
        self.Handle_http()

'''
@功能:主函数
'''
def main():
    print("进入main函数")
    #初次启动先获取一次天气信息,新建文件
    DatabaseClass=Database_Class()#实例化
    DatabaseClass.Update_weather()
    print("初始化完成")
    #设置定时任务
    TaskClass=Task_Class()
    TaskClass.Schedule_task_init()
    print("定时任务设置完成")
    #启动网络服务端
    WebServerClass=Web_Server_Class()
    #WebServerClass.main()
    print("网络服务端启动完成")
    print("进入运行状态")
    #主循环
    while 1:
        schedule.run_pending()
        WebServerClass.main()
    url="http://127.0.0.1:10001/?file=now.json&key=FTudvvro3fWxMuhW&location=guangzhou"
    print("访问:",url)
if(__name__=='__main__'):
    main()

部署

Python脚本制作为docker镜像

获取Python脚本依赖列表

[https://zhuanlan.zhihu.com/p/69058584]

#导出依赖包
pip install pipreqs
python -m pipreqs.pipreqs ./ --encoding=utf8 --force

生成requirements.txt文件.

beautifulsoup4==4.11.2
gmssl==3.2.1
requests==2.23.0
schedule==1.1.0

制作Dockerfile

如何使用 Dockerfile 创建自定义 Docker 镜像 | Linux 中国
Dockerfile

#基础镜像
FROM python:3.7-alpine
#切换包管理器源
RUN python -m pip install pqi
RUN pqi use douban
#复制文件
WORKDIR /usr/src/app
RUN mkdir files
COPY ./requirements.txt ./
COPY ./main3.py ./
COPY ./files/weather.db ./files
COPY ./files/weather.json ./files
#安装依赖
RUN pip install --no-cache-dir -r requirements.txt
#设置容器启动时的命令
CMD [ "python", "./main3.py" ]

开始制作镜像

docker build -t qsbye/sunny-weather:v1 -f Dockerfile .
#查看镜像
docker images

注意:qsbye为笔者的dockerhub用户名,原因⬇️

docker push:denied: requested access to the resource is denied

[https://www.cnblogs.com/luckforefforts/p/13642703.html]
tag 镜像的时候,要加上自己docker hub 的用户名:
docker tag centos/php-70-centos7 shenghp/myphp

上传镜像

docker login
docker push qsbye/sunny-weather:v1

运行

docker pull qsbye/sunny-weather:v1
docker run --name=sunny_weather -p 10001:10001 --restart=always -d qsbye/sunny-weather:v1

效果

wget -O weather_now.json 'http://vpn.qsbye.cn:10001/?file=now.json&key=FTudvvro3fWxMuhW&location=guangzhou' && cat weather_now.json

weather_now.json

{"weather_city": "\u5e7f\u5dde", "weather_wea": "\u9634", "weather_tem": "\n24\u00b0C\n", "weather_wind": "3-4\u7ea7", "update_time": "2023.02.10 17:43:59", "weather_source": "\u4e2d\u56fd\u5929\u6c14\u7f51", "weather_news": "  \u65e0\u7f1d\u8854\u63a5\uff01\u4e2d\u4e1c\u90e8\u53c8\u4e00\u8f6e\u5927\u8303\u56f4\u96e8\u96ea\u6765\u88ad \u4e00\u6587\u4e86\u89e3\u96e8\u96ea\u6709\u591a\u5f3a  ,  \u54c8\u5c14\u6ee8\u964d\u96ea \u80fd\u89c1\u5ea6\u8f83\u5dee\u8def\u9762\u6e7f\u6ed1\u5f71\u54cd\u51fa\u884c  ,  \u6d59\u6c5f\u91d1\u534e\u8349\u7eff\u6885\u7ea2 \u6ee1\u56ed\u6625\u8272\u5173\u4e0d\u4f4f  ,  2\u670811\u65e5\u81f313\u65e5\u6211\u56fd\u4e2d\u4e1c\u90e8\u96e8\u96ea\u964d\u6e29\u5c06\u518d\u81f3  ,  \u6e7f\u6f09\u6f09\uff01\u5e7f\u897f\u5357\u5b81\u5e02\u906d\u9047\u96e8\u96fe\u56de\u5357\u5929\u201c\u4e09\u8fde\u51fb\u201d  ", "token": "1234"}

用[https://www.json.cn]工具解码,

posted @ 2023-02-10 18:29  qsBye  阅读(58)  评论(0编辑  收藏  举报