41 Commits

Author SHA1 Message Date
RTAkland
235e252bab feat: update README.md 2021-12-24 18:58:26 +08:00
RTAkland
278913b2c3 update language files 2021-12-24 18:57:25 +08:00
RTAkland
3cc8afa1f4 feat: optimized output information 2021-12-24 18:56:16 +08:00
RTAkland
3034346c73 feat: removed some text 2021-12-24 18:55:11 +08:00
RTAkland
7b4a0dd033 feat: update 2021-12-23 21:09:19 +08:00
RTAkland
c9ec788cd3 feat: update version 2021-12-21 21:37:53 +08:00
RTAkland
30240033cf feat: update language files 2021-12-21 21:37:33 +08:00
RTAkland
f986a037a8 feat: added SSL 2021-12-21 21:37:13 +08:00
RTAkland
1b96caf719 feat: fixed a bug 2021-12-21 21:36:29 +08:00
RTAkland
df1d5a13b4 feat: added a small info 2021-12-21 20:59:05 +08:00
RTAkland
2c111536c7 feat: update version 2021-12-21 20:57:56 +08:00
RTAkland
1bedb05ac1 feat: rename webserver -> webservice 2021-12-21 20:56:14 +08:00
RTAkland
fd10791baa feat: update language files 2021-12-21 20:55:39 +08:00
RTAkland
98b4b9305b feat: rename file 2021-12-21 20:55:09 +08:00
RTAkland
62d08096b3 feat: added get_host_ip.py 2021-12-21 20:54:38 +08:00
RTAkland
c32efe4b44 feat: added webservice host ip info 2021-12-21 20:54:02 +08:00
RTAkland
9e3f866fb8 feat: fixed a small bug 2021-12-21 20:53:35 +08:00
RTAkland
e8b1a910ae feat: fixed a bug 2021-12-20 22:03:49 +08:00
RTAkland
dd1dc2e3e6 feat: update README.md 2021-12-20 21:58:03 +08:00
RTAkland
bac4565289 feat: update requirements.txt -> space 2021-12-20 21:38:50 +08:00
RTAkland
25f755fd27 feat: update requirements.txt -> openpyxl 2021-12-20 21:25:40 +08:00
RTAkland
09ebfc1a76 feat: update config.yml 2021-12-20 21:25:23 +08:00
RTAkland
ee9e4a4c0f feat: update language files 2021-12-20 21:24:55 +08:00
RTAkland
c2bc49b0d4 feat: added an error collector 2021-12-20 21:24:26 +08:00
RTAkland
fe8d850422 feat: added some comments 2021-12-20 21:23:57 +08:00
RTAkland
51023efc76 feat: fixed a bug 2021-12-20 21:23:22 +08:00
RTAkland
0c6a267967 feat: added some comments 2021-12-20 21:23:10 +08:00
RTAkland
28e1319ee3 feat: fixed many bugs 2021-12-20 21:22:42 +08:00
RTAkland
c8b2662d02 feat: update README.md 2021-12-18 21:58:56 +08:00
RTAkland
c69dedba45 feat: update requirements.txt 2021-12-18 21:54:55 +08:00
RTAkland
346b8c6289 feat: update .gitignore 2021-12-18 21:54:29 +08:00
RTAkland
35ff3d6e81 feat: removed test file 2021-12-18 21:53:57 +08:00
RTAkland
214ec5bf10 feat: update README.md 2021-12-18 21:53:34 +08:00
RTAkland
89c5ff2597 feat: update webserver 2021-12-18 21:41:59 +08:00
RTAkland
3b14691aea feat: change multiprocessing to concurrent 2021-12-18 21:41:24 +08:00
RTAkland
ae2cfce166 feat: change multiprocessing to concurrent 2021-12-18 21:40:48 +08:00
RTAkland
59f6561159 feat: removed something 2021-12-18 21:39:48 +08:00
RTAkland
95254ab80c feat: removed something 2021-12-18 21:39:14 +08:00
RTAkland
575de9463d feat: use high quality pictures 2021-12-18 21:38:29 +08:00
RTAkland
5db51f09fc feat: fixed a bug 2021-12-18 19:44:12 +08:00
RTAkland
b6577f1926 feat: update README.md 2021-12-18 17:16:48 +08:00
27 changed files with 610 additions and 158 deletions

2
.gitignore vendored
View File

@@ -1,7 +1,5 @@
*.yml *.yml
!config.yml !config.yml
*.token
*.zip
*.log *.log
*.log.* *.log.*
**/__pycache__ **/__pycache__

View File

@@ -8,8 +8,7 @@
import sys import sys
from core import qweather from core import qweather
from core.logger import Logger
if __name__ == '__main__': if __name__ == '__main__':
Logger.info('Start')
sys.exit(qweather.main()) sys.exit(qweather.main())

View File

@@ -1,14 +1,14 @@
<p align="center"> <p align="center">
<a href="https://github.com/MarkusJoe/QWeather"> <a href="https://github.com/MarkusJoe/QWeather">
<img src="https://img.shields.io/badge/Python-3.10.x-blue.svg" alt="PythonVersion"> <img src="https://img.shields.io/badge/Python-3.10.x-blue.svg" alt="PythonVersion">
<img src="https://img.shields.io/badge/release-3.0.1b-green.svg" alt="QWeatherVersion"> <img src="https://img.shields.io/badge/release-3.1.4b-green.svg" alt="QWeatherVersion">
<img src="https://img.shields.io/badge/LINCESE-Apache2.0-orange.svg" alt="LICENSE"> <img src="https://img.shields.io/badge/LINCESE-Apache2.0-orange.svg" alt="LICENSE">
</a> </a>
</p> </p>
<div align="center"> <div align="center">
## *QWeather* ## *QWeatherReporter*
<i style="text-align: center;"><a href="https://www.qweather.com/">QWeather Official Website</a></i>\ <i style="text-align: center;"><a href="https://www.qweather.com/">QWeather Official Website</a></i>\
<i style="text-align: center;"><a href="https://dev.qweather.com/">QWeather Development Platform</a></i> <i style="text-align: center;"><a href="https://dev.qweather.com/">QWeather Development Platform</a></i>
@@ -20,7 +20,24 @@
<b><i><a href="https://markusjoe.github.io/" target="_blank">点击跳转到帮助文档</a></i></b> <b><i><a href="https://markusjoe.github.io/" target="_blank">点击跳转到帮助文档</a></i></b>
</div> </div>
## 问题汇总 ## 声明
- > 程序作者: **RTAkland (markushammered@gmail.com)**
- > 和风天气开发者平台https://dev.qweather.com
- > 和风天气官网: https://qweather.com
### 开源
- 本项目以[Apache-2.0](./LICENSE)许可开源, 即:
- 你可以直接使用该项目提供的功能, 无需任何授权
- 你可以在**注明来源版权信息**的情况下对源代码进行任意分发和修改以及衍生
### 已实现功能
- [x] 发送免费版&开发板右键
- [x] 间隔10分钟请求一次自然灾害预警信息
- [x] 在网页上快速查看天气
- [ ] ~~推送到QQ(咕咕咕)~~
### 问题汇总
#### Python 版本: #### Python 版本:
> 程序使用了Python3.10中的match-case语句 > 程序使用了Python3.10中的match-case语句
> 请使用Python3.10版本运行 > 请使用Python3.10版本运行
@@ -29,14 +46,19 @@
#### 配置填写问题: #### 配置填写问题:
> `location`项和`only-view-settings`类不需要用户填写, 只需要打开`QWeather.py`进行自助填写 > `location`项和`only-view-settings`类不需要用户填写, 只需要打开`QWeather.py`进行自助填写
## 声明
- > 程序作者: **RTAkland (markushammered@gmail.com)**
- > 和风天气开发者平台https://dev.qweather.com
- > 和风天气官网: https://qweather.com
## 如何使用 ## 如何使用
- 程序基于python3.10开发 务必使用python3.10版本运行 - 程序基于python3.10开发 务必使用python3.10版本运行
- 将config.yml正确填写完成 - 将config.yml正确填写完成
- 使用`pip/pip3 install -r requirements.txt` 安装需要的库 - 使用`pip/pip3 install -r requirements.txt` 安装需要的库
- 运行`QWeather.py` - 运行`QWeather.py`
### 网页上查看天气
- 将所有准备工作完成(能正常运行QWeather.py)
- 运行QWeather.py
- 打开浏览器输入**127.0.0.1:7898**
>127.0.0.1可以更改为部署本项目的服务器ip, 7898端口不能被其他程序占用或不开放此端口
## 联系方式
- 邮箱: <markushammered@gmail.com>

View File

@@ -100,13 +100,23 @@ client-settings:
# 可选: "DEBUG" "INFO" "WARNING" "ERROR" "CRITICAL" # 可选: "DEBUG" "INFO" "WARNING" "ERROR" "CRITICAL"
level: DEBUG level: DEBUG
# [选填/只能一个] 开启本地网页快速查看天气
# 默认: False
# 可选: "True" "False"
webservice: false
# [必填/只能一个] 是否使用SSL 连接到邮箱服务器
# 默认 True
# 可选: "True" "False"
SSL: True
# [标识/不填] 仅作用户读取标识 # [标识/不填] 仅作用户读取标识
only-view-settings: only-view-settings:
# 城市名 # 城市名
city-name: 黄岩-台州-台州 city-name: 黄岩-台州-台州
# 修改时间 # 修改时间
time: Sun Dec 12 2021 14:49:38 time: Mon Dec 20 2021 21:08:22
# 修改用户 # 修改用户
user: rtakland user: rtakland

View File

@@ -5,32 +5,8 @@
# @Create Time: 2021/12/15 # @Create Time: 2021/12/15
# @File Name: __init__.py # @File Name: __init__.py
"""
Check the configuration file
"""
import os import os
import sys
from core.logger import Logger
from core.language import Language
from core.read_config import read_config
Logger.info('Be imported')
settings = read_config()
if not os.path.exists('./logs'): if not os.path.exists('./logs'):
os.mkdir('./logs') os.mkdir('./logs')
for mail in settings[0].values():
if not mail:
Logger.critical('mail-settings 有未填写项目')
sys.exit(1)
for request in settings[1].values():
if not request:
Logger.critical('request-settings 有未填写项目')
sys.exit(1)
for other in settings[1].values():
if not other:
Logger.critical('client-settings 有未填写项目')
sys.exit(1)

View File

@@ -6,7 +6,7 @@
# @File Name: information.py # @File Name: information.py
import requests import requests
from core import read_config from core.read_config import read_config
class WeatherInfo: class WeatherInfo:

View File

@@ -10,6 +10,10 @@ import json
def Language(): def Language():
"""
读取配置文件中的语言选项并返回相对因的语言文件的读取结果
:return:
"""
with open('./config.yml', 'r', encoding='utf-8') as lang: with open('./config.yml', 'r', encoding='utf-8') as lang:
config = YAML().load(lang.read()) config = YAML().load(lang.read())
language_sel = config['client-settings']['language'] language_sel = config['client-settings']['language']

View File

@@ -13,7 +13,7 @@ import time
level = read_config()[2]['level'] level = read_config()[2]['level']
date_format = '%H:%M:%S' date_format = '%H:%M:%S'
info_format_console = '%(log_color)s[%(asctime)s] |%(filename)s[ %(lineno)-3s] |%(levelname)-8s |%(message)s' info_format_console = '%(log_color)s[%(asctime)s] |%(filename)s[%(lineno)-3s] |%(levelname)-8s |%(message)s'
info_format_file = '[%(asctime)s] |%(filename)s[%(funcName)sline:%(lineno)d] |%(levelname)-8s |%(message)s' info_format_file = '[%(asctime)s] |%(filename)s[%(funcName)sline:%(lineno)d] |%(levelname)-8s |%(message)s'
formatter = ColoredFormatter(fmt=info_format_console, formatter = ColoredFormatter(fmt=info_format_console,
datefmt=date_format, datefmt=date_format,

View File

@@ -9,17 +9,20 @@
import sys import sys
import time import time
import argparse import argparse
from concurrent.futures import ProcessPoolExecutor
from core.logger import Logger from core.logger import Logger
from core.language import Language from core.language import Language
from core.settings import change_settings from core.settings import change_settings
from core import read_config from core.read_config import read_config
from core.sendmail import Mail from core.sendmail import Mail
from multiprocessing import Process from lib.get_host_ip import get_host_ip
from lib import webservice
def check_time(): def check_time():
""" """
if the local time is the time in config, send a mail 通过多进程让函数和主程序并行,
并持续检测本地计算机时间是否和配置文件内填写的发送时间一致
:return: :return:
""" """
mode = settings[1]['mode'] mode = settings[1]['mode']
@@ -45,7 +48,42 @@ def check_time():
time.sleep(60) time.sleep(60)
def check_config():
"""
返回配置文件中的location项是否填写
:return: True or False
"""
location = settings[1]['location']
if location:
return True
else:
return False
def setting():
"""
检查配置文件是否填写完成
:return:
"""
for mail in settings[0].values():
if not mail:
Logger.critical('mail-settings 有未填写项目')
sys.exit(1)
for request in settings[1].values():
if not request:
Logger.critical('request-settings 有未填写项目')
sys.exit(1)
for other in settings[1].values():
if not other:
Logger.critical('client-settings 有未填写项目')
sys.exit(1)
def main(): def main():
"""
主程序
:return:
"""
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
arg_keywords = ['free', 'dev', 'warning', 'setting'] arg_keywords = ['free', 'dev', 'warning', 'setting']
parser.add_argument('-t', parser.add_argument('-t',
@@ -68,12 +106,18 @@ def main():
Logger.debug(f'{language["debug_done"]}') Logger.debug(f'{language["debug_done"]}')
sys.exit(0) sys.exit(0)
case 'setting': case 'setting':
change_settings(False) change_settings()
Logger.debug(f'{language["debug_done"]}') Logger.debug(f'{language["debug_done"]}')
case _: case _:
pass if check_config():
setting()
else:
change_settings()
Process(target=check_time).run() processes.submit(check_time)
if settings[2]['webservice']:
Logger.info(f'{language["webservice_ip"]}:{get_host_ip()}:7898')
processes.submit(webservice.process_request())
time_count = 0 time_count = 0
while True: while True:
@@ -87,6 +131,7 @@ def main():
if __name__ != '__main__': if __name__ != '__main__':
language = Language() language = Language()
settings = read_config() settings = read_config()
processes = ProcessPoolExecutor(max_workers=3)
Logger.info(f'{language["statement_1"]}') Logger.info(f'{language["statement_1"]}')
Logger.info(f'{language["statement_2"]}') Logger.info(f'{language["statement_2"]}')

View File

@@ -10,10 +10,11 @@ from ruamel.yaml import YAML
def read_config(): def read_config():
""" """
读取配置文件并返回读取到的内容同
:return: mail-settings, request-settings, client-settings, only-view-settings --> 0, 1, 2, 3 :return: mail-settings, request-settings, client-settings, only-view-settings --> 0, 1, 2, 3
""" """
with open('./config.yml', 'r') as conf: config_file = 'config.yml'
with open(f'./{config_file}', 'r') as conf:
config = YAML().load(conf.read()) config = YAML().load(conf.read())
mail_settings = config['mail-settings'] mail_settings = config['mail-settings']
request_settings = config['request-settings'] request_settings = config['request-settings']

View File

@@ -12,7 +12,7 @@ from core.language import Language
def read_excel(kw: str): def read_excel(kw: str):
""" """
Read xlsx file and return searched results 读取china_city_list.xlsx并搜索匹配关键字的结果并输出到终端
:param kw: keyword :param kw: keyword
:return: city_list :return: city_list
""" """

View File

@@ -16,6 +16,7 @@ from core.logger import Logger
from core.language import Language from core.language import Language
from core.information import WeatherInfo from core.information import WeatherInfo
from core.read_config import read_config from core.read_config import read_config
from lib.hitokoto import hitokoto
class Mail: class Mail:
@@ -33,12 +34,18 @@ class Mail:
self.message['From'] = Header('QWeather') # 发件人名称 self.message['From'] = Header('QWeather') # 发件人名称
self.message['To'] = Header('All allowed User') # 收件人显示名称 self.message['To'] = Header('All allowed User') # 收件人显示名称
self.hitokoto = hitokoto() # 一言
if self.enableSSL: if self.enableSSL:
self.smtp = smtplib.SMTP_SSL(self.server, self.port) # 登录服务器 使用SSL连接 self.smtp = smtplib.SMTP_SSL(self.server, self.port) # 登录服务器 使用SSL连接
else: else:
self.smtp = smtplib.SMTP(self.server, self.port) # 登录邮箱服务器 不使用SSL连接 self.smtp = smtplib.SMTP(self.server, self.port) # 登录邮箱服务器 不使用SSL连接
def dev_version(self): def dev_version(self):
"""
开发者版本
:return:
"""
dev_weather = WeatherInfo().dev_version() dev_weather = WeatherInfo().dev_version()
dates = dev_weather[0] dates = dev_weather[0]
day_weathers = dev_weather[1] day_weathers = dev_weather[1]
@@ -124,8 +131,8 @@ class Mail:
<th>&nbsp;</th> <th>&nbsp;</th>
</tr> </tr>
<tr> <tr>
<th>风速/级/向</th> <th>风速/级/向</th>
<th>相对湿度</th> <th>湿度</th>
<th>紫外线</th> <th>紫外线</th>
</tr> </tr>
<tr> <tr>
@@ -138,8 +145,8 @@ class Mail:
</tr> </tr>
<tr> <tr>
<th>能见度</th> <th>能见度</th>
<th>大气压强</th> <th>压强</th>
<th>相对云量</th> <th>云量</th>
</tr> </tr>
<tr> <tr>
<td>{vis}km&nbsp;</td> <td>{vis}km&nbsp;</td>
@@ -162,9 +169,13 @@ class Mail:
<td>&nbsp;{sunset}&nbsp;</td> <td>&nbsp;{sunset}&nbsp;</td>
</tr> </tr>
</table> </table>
<br />
<div style="text-align: center" id="hitokoto">
<p>
{self.hitokoto}
</p>
</div>
<div style="text-align: center;" id="About"> <div style="text-align: center;" id="About">
<br />
<br />
<br /> <br />
<i> <i>
<b> <b>
@@ -203,6 +214,10 @@ class Mail:
sys.exit(1) sys.exit(1)
def free_version(self): def free_version(self):
"""
免费版本
:return:
"""
free_weather = WeatherInfo().free_version() free_weather = WeatherInfo().free_version()
dates = free_weather[0] dates = free_weather[0]
day_weathers = free_weather[1] day_weathers = free_weather[1]
@@ -263,8 +278,8 @@ class Mail:
<th>&nbsp;</th> <th>&nbsp;</th>
</tr> </tr>
<tr> <tr>
<th>风速/级/向</th> <th>风速/级/向</th>
<th>相对湿度</th> <th>湿度</th>
<th>紫外线</th> <th>紫外线</th>
</tr> </tr>
<tr> <tr>
@@ -277,8 +292,8 @@ class Mail:
</tr> </tr>
<tr> <tr>
<th>能见度</th> <th>能见度</th>
<th>大气压强</th> <th>压强</th>
<th>相对云量</th> <th>云量</th>
</tr> </tr>
<tr> <tr>
<td>{vis}km&nbsp;</td> <td>{vis}km&nbsp;</td>
@@ -301,9 +316,13 @@ class Mail:
<td>&nbsp;{sunset}&nbsp;</td> <td>&nbsp;{sunset}&nbsp;</td>
</tr> </tr>
</table> </table>
<br />
<div style="text-align: center" id="hitokoto">
<p>
{self.hitokoto}
</p>
</div>
<div style="text-align: center;" id="About"> <div style="text-align: center;" id="About">
<br />
<br />
<br /> <br />
<i> <i>
<b> <b>
@@ -342,6 +361,10 @@ class Mail:
sys.exit(1) sys.exit(1)
def warning_(self): def warning_(self):
"""
自然灾害预警
:return:
"""
info = WeatherInfo().warning_() info = WeatherInfo().warning_()
release_time = info[0] release_time = info[0]
title = info[1] title = info[1]

View File

@@ -11,62 +11,60 @@ import getpass
from core.logger import Logger from core.logger import Logger
from core.language import Language from core.language import Language
from core.read_excel import read_excel from core.read_excel import read_excel
from core.read_config import read_config
from ruamel.yaml import YAML from ruamel.yaml import YAML
def change_settings(flag: bool = True): def change_settings():
""" """
使用read_excel.py搜索到的结果再次进行二次选择, 并写入文件
:return: None :return:
""" """
language = Language() language = Language()
settings = read_config()
if not settings[1]['mode'] or not flag: Logger.info(f'[Modify]{language["change_setting"]}')
Logger.info(f'[Modify]{language["fill_the_config"]}') Logger.info(f'[Modify]{language["fill_the_config"]}')
Logger.info(f'[Modify]{language["input_a_city_name"]}') Logger.info(f'[Modify]{language["input_a_city_name"]}')
while True: while True:
time.sleep(0.3)
city_name = input('-->')
match city_name:
case 'q':
Logger.info(f'[Modify]User quit.')
sys.exit(0)
case '':
Logger.critical(f'[Modify]{language["null_value"]}')
continue
case _:
break
searched_city = read_excel(city_name)
Logger.info(f'[Modify]{language["user_input"]}:[{city_name}]')
Logger.info(f'[Modify]{language["select_a_index"]}')
if not searched_city:
Logger.error(f'[Modify]{language["no_result"]}')
sys.exit(1)
time.sleep(0.3) time.sleep(0.3)
while True: city_name = input('-->')
try: match city_name:
time.sleep(0.3) case 'q':
user_input = input('-->') Logger.info(f'[Exit]{language["exit"]}')
if user_input == 'q':
Logger.info('[Quit]User quit')
sys.exit(1)
index = searched_city[int(user_input)]
with open('./config.yml', 'r', encoding='utf-8') as of:
data = YAML().load(of)
data['request-settings']['location'] = index[1]
data['only-view-settings']['city-name'] = f'{index[3]}-{index[7]}-{index[7]}'
data['only-view-settings']['time'] = time.strftime("%a %b %d %Y %H:%M:%S", time.localtime())
data['only-view-settings']['user'] = getpass.getuser()
with open('./config.yml', 'w', encoding='utf-8') as wf:
YAML().dump(data, wf)
Logger.info(f'[Write]{language["write_successfully"]}:config.yml')
break
except (IndexError, ValueError) as e:
Logger.info(e)
Logger.error(f'[Write]{language["input_type_error"]}')
continue
finally:
Logger.info('[Done]Program has done.')
sys.exit(0) sys.exit(0)
case '':
Logger.error(f'[Modify]{language["null_value"]}')
continue
case _:
break
searched_city = read_excel(city_name)
Logger.info(f'[Modify]{language["user_input"]}:[{city_name}]')
Logger.info(f'[Modify]{language["select_a_index"]}')
if not searched_city:
Logger.error(f'[Modify]{language["no_result"]}')
sys.exit(1)
time.sleep(0.3)
while True:
try:
time.sleep(0.3)
user_input = input('-->')
if user_input == 'q':
Logger.info(f'[Exit]{language["exit"]}')
sys.exit(1)
index = searched_city[int(user_input)]
with open('./config.yml', 'r', encoding='utf-8') as of:
data = YAML().load(of)
data['request-settings']['location'] = index[1]
data['only-view-settings']['city-name'] = f'{index[3]}-{index[7]}-{index[7]}'
data['only-view-settings']['time'] = time.strftime("%a %b %d %Y %H:%M:%S", time.localtime())
data['only-view-settings']['user'] = getpass.getuser()
with open('./config.yml', 'w', encoding='utf-8') as wf:
YAML().dump(data, wf)
Logger.info(f'[Write]{language["write_successfully"]}:config.yml')
break
except (IndexError, ValueError) as e:
Logger.info(e)
Logger.error(f'[Write]{language["input_type_error"]}')
continue
finally:
Logger.info(f'[Exit]{language["exit"]}')
sys.exit(0)

View File

@@ -4,7 +4,3 @@
# @Development Tool: PyCharm # @Development Tool: PyCharm
# @Create Time: 2021/10/16 # @Create Time: 2021/10/16
# @File Name: __init__.py # @File Name: __init__.py
from core.logger import Logger
Logger.info('Be imported')

View File

@@ -10,17 +10,27 @@
启用等级: DEV 启用等级: DEV
""" """
from core.read_config import read_config
import requests import requests
import json import json
def hourly_weather(location: int, key: str, lang: str = 'zh', unit: str = 'm'): def hourly_weather():
"""
获取24小时的天气
:return:
"""
settings = read_config()
location = settings[1]['location']
key = settings[1]['key']
lang = settings[1]['lang']
unit = settings[1]['unit']
r = requests.get( r = requests.get(
f'https://devapi.qweather.com/v7/weather/24h?location={location}&key={key}&lang={lang}&unit={unit}') f'https://devapi.qweather.com/v7/weather/24h?location={location}&key={key}&lang={lang}&unit={unit}')
data = json.loads(r.text) data = json.loads(r.text)
status_code = data['code'] status_code = data['code']
updateTime = str(data['updateTime'][:-6]).replace('T', '') updateTime = str(data['updateTime'][:-6])[10:].replace('T', '')
main_data = data['hourly'] # 24 main_data = data['hourly'] # 24
return status_code, updateTime, main_data return status_code, updateTime, main_data

20
lib/get_host_ip.py Normal file
View File

@@ -0,0 +1,20 @@
# -- coding:utf-8 --
# @Author: markushammered@gmail.com
# @Development Tool: PyCharm
# @Create Time: 2021/12/21
# @File Name: get_host_ip.py
import socket
def get_host_ip():
"""
查询本机ip地址
:return: ip
"""
ip_s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
ip_s.connect(('8.8.8.8', 80))
ip = ip_s.getsockname()[0]
ip_s.close()
return ip

View File

@@ -11,11 +11,21 @@
启用等级: DEV 启用等级: DEV
""" """
from core.read_config import read_config
import requests import requests
import json import json
def indices(location: int, key: str, lang: str = 'zh', unit: str = 'm'): def indices():
"""
获取生活建议
:return:
"""
settings = read_config()
location = settings[1]['location']
key = settings[1]['key']
lang = settings[1]['lang']
unit = settings[1]['unit']
r = requests.get( r = requests.get(
f'https://devapi.qweather.com/v7/indices/1d?type=0&location={location}&key={key}&lang={lang}&unit={unit}') f'https://devapi.qweather.com/v7/indices/1d?type=0&location={location}&key={key}&lang={lang}&unit={unit}')
data = json.loads(r.text) data = json.loads(r.text)

View File

@@ -10,29 +10,24 @@
启用等级: DEV 启用等级: DEV
""" """
from core.read_config import read_config
import requests import requests
import json import json
import sys
from ruamel.yaml import YAML
def real_time_air_quality(): def real_time_air_quality():
yaml = YAML() """
with open(sys.path[1] + '/config.yml', 'r', encoding='utf-8') as f: 获取实时的空气质量数据
config = yaml.load(f.read()) :return:
"""
settings = read_config()
location = settings[1]['location']
key = settings[1]['key']
lang = settings[1]['lang']
unit = settings[1]['unit']
mode = config['request-settings']['mode'] r = requests.get(f'https://devapi.qweather.com/v7/air/now?'
key = config['request-settings']['key'] f'location={location}&key={key}&lang={lang}&unit={unit}&gzip=y')
location = config['request-settings']['location']
unit = config['request-settings']['unit']
lang = config['request-settings']['lang']
if mode != 'dev':
return False, print('Only Dev-mode')
session = requests.Session()
session.trust_env = False
r = session.get(f'https://devapi.qweather.com/v7/air/now?'
f'location={location}config.yml&key={key}&lang={lang}&unit={unit}&gzip=y')
_data = json.loads(r.text) _data = json.loads(r.text)
return _data['code'], _data['now'] return _data['now']

View File

@@ -10,18 +10,19 @@
启用等级: DEV 启用等级: DEV
""" """
from core.read_config import read_config
import requests import requests
import json import json
from ruamel.yaml import YAML
def get_warning_list(_range='cn'): def get_warning_list(_range='cn'):
yaml = YAML() """
with open('./config.yml', 'r', encoding='utf-8') as f: 获取当前正在发送自然灾害的城市id列表
config = yaml.load(f.read()) :param _range: Range
key = config['request-settings']['key'] :return:
session = requests.Session() """
session.trust_env = False settings = read_config()
r = session.get(f'https://devapi.qweather.com/v7/warning/list?range={_range}&key={key}') key = settings[1]['key']
r = requests.get(f'https://devapi.qweather.com/v7/warning/list?range={_range}&key={key}')
_data = json.loads(r.text) _data = json.loads(r.text)
return _data['code'], _data['warningLocList'][0]['locationId'] return _data['code'], _data['warningLocList'][0]['locationId']

5
lib/hitokoto.py Normal file
View File

@@ -0,0 +1,5 @@
# -- coding:utf-8 --
# @Author: markushammered@gmail.com
# @Development Tool: PyCharm
# @Create Time: 2021/12/24
# @File Name: hitokoto.py

326
lib/webservice.py Normal file
View File

@@ -0,0 +1,326 @@
#!/usr/bin/env python3
# -- coding:utf-8 --
# @Author: markushammered@gmail.com
# @Development Tool: PyCharm
# @Create Time: 2021/12/18
# @File Name: webservice.py
import socket
import sys
from core.logger import Logger
from core.read_config import read_config
from core.information import WeatherInfo
from core.language import Language
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind(('localhost', 7898))
server.listen(5)
language = Language()
def build_html():
"""
构建html主体
:return:
"""
settings = read_config()
city = settings[3]['city-name']
mode = settings[1]['mode']
match mode:
case 'dev':
dev_weather = WeatherInfo().dev_version()
dates = dev_weather[0]
day_weathers = dev_weather[1]
night_weathers = dev_weather[2]
highest_temps = dev_weather[3]
lowest_temps = dev_weather[4]
icons = dev_weather[5]
sunset = dev_weather[6]
sunrise = dev_weather[7]
humidity = dev_weather[8]
wind_speed = dev_weather[9]
wind_scale = dev_weather[10]
wind_dir = dev_weather[11]
uv_index = dev_weather[12]
cloud = dev_weather[13]
pressure = dev_weather[14]
vis = dev_weather[15]
html = f"""
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>QWeather|网页查看天气服务</title>
</head>
<body>
<p style="text-align: center"><i><b>地区:{city}</b></i></p>
<br />
<table style="border: 0; text-align: center; margin:0 auto">
<tr>
<th>|&nbsp;日期&nbsp;&nbsp;</th>
<th>|&nbsp;天气&nbsp;&nbsp;</th>
<th>|&nbsp;最低温度&nbsp;&nbsp;</th>
<th>|&nbsp;最高温度&nbsp;&nbsp;</th>
</tr>
<tr>
<!--日期 天气 最低 最高/Date Weather LowestTemp HighestTemp-->
<td>今天</td>
<td>{day_weathers[0]}<img src="./res/icons/{icons[0]}.png" width="20" alt="">/{night_weathers[0]}
<img src="./res/icons/{icons[1]}.png"
width="20" alt=""></td> <td>{lowest_temps[0]}℃</td>
<td>{highest_temps[0]}℃</td>
</tr>
<tr>
<td>{dates[1]}</td>
<td>{day_weathers[1]}<img src="./res/icons/{icons[2]}.png" width="20" alt="">/{night_weathers[1]}
<img src="./res/icons/{icons[3]}.png"
width="20" alt=""></td> <td>{lowest_temps[1]}℃</td>
<td>{highest_temps[1]}℃</td>
</tr>
<tr>
<td>{dates[2]}</td>
<td>{day_weathers[2]}<img src="./res/icons/{icons[4]}.png" width="20" alt="">/{night_weathers[2]}
<img src="./res/icons/{icons[5]}.png"
width="20" alt=""></td> <td>{lowest_temps[2]}℃</td>
<td>{highest_temps[2]}℃</td>
</tr>
<tr>
<td>{dates[3]}</td>
<td>{day_weathers[3]}<img src="./res/icons/{icons[6]}.png" width="20" alt="">/{night_weathers[3]}
<img src="./res/icons/{icons[7]}.png"
width="20" alt=""></td> <td>{lowest_temps[3]}℃</td>
<td>{highest_temps[3]}℃</td>
</tr>
<tr>
<td>{dates[4]}</td>
<td>{day_weathers[4]}<img src="./res/icons/{icons[8]}.png" width="20" alt="">/{night_weathers[4]}
<img src="./res/icons/{icons[9]}.png"
width="20" alt=""></td> <td>{lowest_temps[4]}℃</td>
<td>{highest_temps[4]}℃</td>
</tr>
<tr>
<td>{dates[5]}</td>
<td>{day_weathers[5]}<img src="./res/icons/{icons[10]}.png" width="20" alt="">/{night_weathers[5]}
<img src="./res/icons/{icons[11]}.png"
width="20" alt=""></td> <td>{lowest_temps[5]}℃</td>
<td>{highest_temps[5]}℃</td>
</tr>
<tr>
<td>{dates[6]}</td>
<td>{day_weathers[6]}<img src="./res/icons/{icons[12]}.png" width="20" alt="">/{night_weathers[6]}
<img src="./res/icons/{icons[13]}.png"
width="20" alt=""></td> <td>{lowest_temps[6]}℃</td>
<td>{highest_temps[6]}℃</td>
</tr>
</table>
<table style="border: 0;text-align: center; margin:0 auto">
<tr>
<th>&nbsp;</th>
</tr>
<tr>
<th>风速/级/向</th>
<th>湿度</th>
<th>紫外线</th>
</tr>
<tr>
<td>{wind_speed}m/s&nbsp; {wind_scale}&nbsp; {wind_dir}&nbsp;</td>
<td>{humidity}%&nbsp;</td>
<td>{uv_index}&nbsp;</td>
</tr>
<tr>
<th>&nbsp;</th>
</tr>
<tr>
<th>能见度</th>
<th>压强</th>
<th>云量</th>
</tr>
<tr>
<td>{vis}km&nbsp;</td>
<td>{pressure}hPa&nbsp;</td>
<td>{cloud}%&nbsp;</td>
</tr>
</table>
<table style="border: 0;text-align: center; margin:0 auto">
<tr>
<th>&nbsp;</th>
</tr>
<tr>
<td><img src="./res/basic-resources/sunrise.png" alt="Sunrise" width="30"></td>
<td>&nbsp;</td>
<td><img src="./res/basic-resources/sunset.png" alt="Sunset" width="30"></td>
</tr>
<tr>
<td>&nbsp;{sunrise}&nbsp;</td>
<td>---------------</td>
<td>&nbsp;{sunset}&nbsp;</td>
</tr>
</table>
<div style="text-align: center;" id="About">
<br />
<br />
<br />
<i>
<b>
<a href="https://dev.qweather.com/" style="color: black" target="_blank">QWeather</a>
<a style="color: black">&nbsp;·&nbsp;</a>
<a href="https://github.com/MarkusJoe/QWeather" style="color: black" target="_blank">Github Repo</a>
</b>
</i>
</div>
</body>
</html>"""
return html
case 'free':
dev_weather = WeatherInfo().free_version()
dates = dev_weather[0]
day_weathers = dev_weather[1]
night_weathers = dev_weather[2]
highest_temps = dev_weather[3]
lowest_temps = dev_weather[4]
icons = dev_weather[5]
sunset = dev_weather[6]
sunrise = dev_weather[7]
humidity = dev_weather[8]
wind_speed = dev_weather[9]
wind_scale = dev_weather[10]
wind_dir = dev_weather[11]
uv_index = dev_weather[12]
cloud = dev_weather[13]
pressure = dev_weather[14]
vis = dev_weather[15]
html = f"""
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>QWeather|网页查看天气服务</title>
</head>
<body>
<p style="text-align: center"><i><b>地区:{city}</b></i></p>
<br />
<table style="border: 0; text-align: center; margin:0 auto">
<tr>
<th>|&nbsp;日期&nbsp;&nbsp;</th>
<th>|&nbsp;天气&nbsp;&nbsp;</th>
<th>|&nbsp;最低温度&nbsp;&nbsp;</th>
<th>|&nbsp;最高温度&nbsp;&nbsp;</th>
</tr>
<tr>
<!--日期 天气 最低 最高/Date Weather LowestTemp HighestTemp-->
<td>今天</td>
<td>{day_weathers[0]}<img src="./res/icons/{icons[0]}.png" width="20" alt="">/{night_weathers[0]}
<img src="./res/icons/{icons[1]}.png"
width="20" alt=""></td> <td>{lowest_temps[0]}℃</td>
<td>{highest_temps[0]}℃</td>
</tr>
<tr>
<td>{dates[1]}</td>
<td>{day_weathers[1]}<img src="./res/icons/{icons[2]}.png" width="20" alt="">/{night_weathers[1]}
<img src="./res/icons/{icons[3]}.png"
width="20" alt=""></td> <td>{lowest_temps[1]}℃</td>
<td>{highest_temps[1]}℃</td>
</tr>
<tr>
<td>{dates[2]}</td>
<td>{day_weathers[2]}<img src="./res/icons/{icons[4]}.png" width="20" alt="">/{night_weathers[2]}
<img src="./res/icons/{icons[5]}.png"
width="20" alt=""></td> <td>{lowest_temps[2]}℃</td>
<td>{highest_temps[2]}℃</td>
</table>
<table style="border: 0;text-align: center; margin:0 auto">
<tr>
<th>&nbsp;</th>
</tr>
<tr>
<th>风速/风级/风向</th>
<th>相对湿度</th>
<th>紫外线</th>
</tr>
<tr>
<td>{wind_speed}m/s&nbsp; {wind_scale}&nbsp; {wind_dir}&nbsp;</td>
<td>{humidity}%&nbsp;</td>
<td>{uv_index}&nbsp;</td>
</tr>
<tr>
<th>&nbsp;</th>
</tr>
<tr>
<th>能见度</th>
<th>压强</th>
<th>云量</th>
</tr>
<tr>
<td>{vis}km&nbsp;</td>
<td>{pressure}hPa&nbsp;</td>
<td>{cloud}%&nbsp;</td>
</tr>
</table>
<table style="border: 0;text-align: center; margin:0 auto">
<tr>
<th>&nbsp;</th>
</tr>
<tr>
<td><img src="./res/basic-resources/sunrise.png" alt="Sunrise" width="30"></td>
<td>&nbsp;</td>
<td><img src="./res/basic-resources/sunset.png" alt="Sunset" width="30"></td>
</tr>
<tr>
<td>&nbsp;{sunrise}&nbsp;</td>
<td>---------------</td>
<td>&nbsp;{sunset}&nbsp;</td>
</tr>
</table>
<div style="text-align: center;" id="About">
<br />
<br />
<br />
<i>
<b>
<a href="https://dev.qweather.com/" style="color: black" target="_blank">QWeather</a>
<a style="color: black">&nbsp;·&nbsp;</a>
<a href="https://github.com/MarkusJoe/QWeather" style="color: black" target="_blank">Github Repo</a>
</b>
</i>
</div>
</body>
</html>"""
return html
case _:
return "You hadn't selected a mode"
def process_request():
"""
处理请求
:return:
"""
try:
while True:
c, a = server.accept()
data = str(c.recv(1024)).split(':')[0][6:][:-17]
html = build_html()
if data == '/': # 判断用户请求的目标是否为根目录, 如果是则返回html; 如果不是则继续判断
c.send('HTTP1.1/ 200 OK\r\n\r\n'.encode('utf-8'))
c.send(html.encode('utf-8'))
Logger.info(f'{language["get_resource"]} {data} {language["get_resource_from"]} {a[0]}:{a[1]}')
else: # 继续判断用户请求的文件是否存在
try:
with open(f'.{data}', 'rb') as f:
c.send('HTTP1.1/ 200 OK\r\n\r\n'.encode('utf-8'))
c.send(f.read())
Logger.info(f'{language["get_resource"]} {data} {language["get_resource_from"]} {a[0]}:{a[1]}')
except FileNotFoundError:
c.send(f'HTTP1.1/ 404 Not Found\r\n\r\n{html}'.encode('utf-8'))
c.close()
except BrokenPipeError:
Logger.critical(f'{language["connection_speed_too_fast"]}')
sys.exit(1)
except IOError:
Logger.critical(f'{language["an_io_error"]}')
sys.exit(1)

View File

@@ -1,7 +1,5 @@
requests==2.26.0 requests>=2.26.0
ruamel.yaml==0.17.17 ruamel.yaml>=0.17.17
pandas==1.3.4 pandas>=1.3.4
pyppeteer==0.2.6 colorlog>=6.5.0
bs4==0.0.1 openpyxl>=3.0.9
openpyxl==3.0.9
colorlog==6.5.0

Binary file not shown.

Before

Width:  |  Height:  |  Size: 993 B

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1005 B

After

Width:  |  Height:  |  Size: 6.5 KiB

View File

@@ -28,5 +28,15 @@
"no_result": "Nothing has searched.", "no_result": "Nothing has searched.",
"config_file_read_successfully": "Read config file successfully.", "config_file_read_successfully": "Read config file successfully.",
"language_file_read_successfully": "Multi-language module load successfully", "language_file_read_successfully": "Multi-language module load successfully",
"language_not_filled": "Language hasn't filled, default: zh_cn" "language_not_filled": "Language hasn't filled, default: zh_cn.",
"no_location": "You haven't fill the location in the config file.",
"change_setting": "You are changing setting.",
"exit": "Exited.",
"webservice_ip": "Local webservice ip",
"connection_speed_too_fast": "Connection speed is too fast, subprocess: webservice has exited.",
"an_io_error": "An IO error.",
"noname": "No name.",
"hitokoto": "Get hitokoto successfully.",
"get_resource": "Get resource",
"get_resource_from": "from"
} }

View File

@@ -28,5 +28,14 @@
"no_result": "没有搜索到相关结果", "no_result": "没有搜索到相关结果",
"config_file_read_successfully": "配置文件读取成功", "config_file_read_successfully": "配置文件读取成功",
"language_file_read_successfully": "多语言模块加载成功", "language_file_read_successfully": "多语言模块加载成功",
"language_not_filled": "语言选项为填写完成或填写错误, 默认zh_cn" "language_not_filled": "语言选项为填写完成或填写错误, 默认zh_cn",
} "change_setting": "更改设置",
"exit": "已退出",
"webservice_ip": "webservice地址",
"connection_speed_too_fast": "连接速度过快, 子进程:webservice.py 已退出",
"an_io_error": "一个IO错误",
"noname": "佚名",
"hitokoto": "一言获取成功",
"get_resource": "获取资源",
"get_resource_from": "来自"
}

View File

@@ -4,7 +4,3 @@
# @Development Tool: PyCharm # @Development Tool: PyCharm
# @Create Time: 2021/11/7 # @Create Time: 2021/11/7
# @File Name: __init__.py.py # @File Name: __init__.py.py
from core.logger import Logger
Logger.info('Be imported')