52 Commits

Author SHA1 Message Date
RTAkland
451aed59d0 feat: del 2021-12-26 10:34:10 +08:00
RTAkland
0b41c9c1f5 feat: update README.md 2021-12-26 10:00:07 +08:00
RTAkland
b205533ae7 feat: del 2021-12-26 09:39:03 +08:00
RTAkland
b493c06387 feat: update .gitignore 2021-12-26 09:36:33 +08:00
RTAkland
936dd14a87 feat: updated 2021-12-25 12:18:22 +08:00
RTAkland
21a7f9140d feat: updated 2021-12-25 12:15:13 +08:00
RTAkland
23f44c3f78 feat: fixed a bug 2021-12-25 12:14:53 +08:00
RTAkland
9477c33952 feat: update 2021-12-25 12:09:30 +08:00
RTAkland
7fdd0d56a1 feat: fixed a bug 2021-12-25 12:08:52 +08:00
RTAkland
2117771518 feat: update README.md 2021-12-24 19:52:11 +08:00
RTAkland
ea4d04a71c feat: add hitokoto 2021-12-24 19:51:49 +08:00
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
26 changed files with 622 additions and 161 deletions

3
.gitignore vendored
View File

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

View File

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

View File

@@ -1,14 +1,14 @@
<p align="center">
<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/release-3.0.1b-green.svg" alt="QWeatherVersion">
<img src="https://img.shields.io/badge/release-3.2.0-green.svg" alt="QWeatherVersion">
<img src="https://img.shields.io/badge/LINCESE-Apache2.0-orange.svg" alt="LICENSE">
</a>
</p>
<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://dev.qweather.com/">QWeather Development Platform</a></i>
@@ -20,23 +20,46 @@
<b><i><a href="https://markusjoe.github.io/" target="_blank">点击跳转到帮助文档</a></i></b>
</div>
## 问题汇总
#### Python 版本:
> 程序使用了Python3.10中的match-case语句
> 请使用Python3.10版本运行
#### 主题选择:
> 在2.9.0之后的版本不支持自定义天气图标 只能使用最新的图标
#### 配置填写问题:
> `location`项和`only-view-settings`类不需要用户填写, 只需要打开`QWeather.py`进行自助填写
## 声明
- > 程序作者: **RTAkland (markushammered@gmail.com)**
- > 和风天气开发者平台https://dev.qweather.com
- > 和风天气官网: https://qweather.com
### 开源
- 本项目以[Apache-2.0](./LICENSE)许可开源, 即:
- 你可以直接使用该项目提供的功能, 无需任何授权
- 你可以在**注明来源版权信息**的情况下对源代码进行任意分发和修改以及衍生
### 已实现功能
- [x] 发送免费版&开发版天气预报功能
- [x] 间隔10分钟请求一次自然灾害预警信息
- [x] 在网页上快速查看天气
- [x] 在邮件html内附带一句一言
- [ ] ~~推送到QQ(咕咕咕)~~
### 问题汇总
#### Python 版本:
> 程序使用了*Python3.10.x*中的match-case语句
> 请使用*Python3.10.x*版本运行
#### 主题选择:
> 在2.9.0之后的版本不支持自定义天气图标 只能使用最新的图标
#### 配置填写问题:
> `location`项和`only-view-settings`类不需要用户填写, 只需要打开`QWeather.py`进行自助填写
## 如何使用
- 程序基于python3.10开发 务必使用python3.10版本运行
- 将config.yml正确填写完成
- 使用`pip/pip3 install -r requirements.txt` 安装需要的库
- 运行`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"
level: DEBUG
# [选填/只能一个] 开启本地网页快速查看天气
# 默认: False
# 可选: "True" "False"
webservice: false
# [必填/只能一个] 是否使用SSL 连接到邮箱服务器
# 默认 True
# 可选: "True" "False"
SSL: True
# [标识/不填] 仅作用户读取标识
only-view-settings:
# 城市名
city-name: 黄岩-台州-台州
# 修改时间
time: Sun Dec 12 2021 14:49:38
time: Mon Dec 20 2021 21:08:22
# 修改用户
user: rtakland

View File

@@ -5,32 +5,8 @@
# @Create Time: 2021/12/15
# @File Name: __init__.py
"""
Check the configuration file
"""
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'):
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
import requests
from core import read_config
from core.read_config import read_config
class WeatherInfo:

View File

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

View File

@@ -13,7 +13,7 @@ import time
level = read_config()[2]['level']
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'
formatter = ColoredFormatter(fmt=info_format_console,
datefmt=date_format,

View File

@@ -9,17 +9,19 @@
import sys
import time
import argparse
from concurrent.futures import ProcessPoolExecutor
from core.logger import Logger
from core.language import Language
from core.settings import change_settings
from core import read_config
from core.read_config import read_config
from core.sendmail import Mail
from multiprocessing import Process
from lib.webservice import accept_requests
def check_time():
"""
if the local time is the time in config, send a mail
通过多进程让函数和主程序并行,
并持续检测本地计算机时间是否和配置文件内填写的发送时间一致
:return:
"""
mode = settings[1]['mode']
@@ -45,7 +47,42 @@ def check_time():
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():
"""
主程序
:return:
"""
parser = argparse.ArgumentParser()
arg_keywords = ['free', 'dev', 'warning', 'setting']
parser.add_argument('-t',
@@ -68,12 +105,18 @@ def main():
Logger.debug(f'{language["debug_done"]}')
sys.exit(0)
case 'setting':
change_settings(False)
change_settings()
Logger.debug(f'{language["debug_done"]}')
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"]}:127.0.0.1:7898')
processes.submit(accept_requests())
time_count = 0
while True:
@@ -87,6 +130,7 @@ def main():
if __name__ != '__main__':
language = Language()
settings = read_config()
processes = ProcessPoolExecutor(max_workers=3)
Logger.info(f'{language["statement_1"]}')
Logger.info(f'{language["statement_2"]}')

View File

@@ -10,10 +10,11 @@ from ruamel.yaml import YAML
def read_config():
"""
读取配置文件并返回读取到的内容同
: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())
mail_settings = config['mail-settings']
request_settings = config['request-settings']

View File

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

View File

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

View File

@@ -11,62 +11,60 @@ import getpass
from core.logger import Logger
from core.language import Language
from core.read_excel import read_excel
from core.read_config import read_config
from ruamel.yaml import YAML
def change_settings(flag: bool = True):
def change_settings():
"""
:return: None
使用read_excel.py搜索到的结果再次进行二次选择, 并写入文件
:return:
"""
language = Language()
settings = read_config()
if not settings[1]['mode'] or not flag:
Logger.info(f'[Modify]{language["fill_the_config"]}')
Logger.info(f'[Modify]{language["input_a_city_name"]}')
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)
Logger.info(f'[Modify]{language["change_setting"]}')
Logger.info(f'[Modify]{language["fill_the_config"]}')
Logger.info(f'[Modify]{language["input_a_city_name"]}')
while True:
time.sleep(0.3)
while True:
try:
time.sleep(0.3)
user_input = input('-->')
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.')
city_name = input('-->')
match city_name:
case 'q':
Logger.info(f'[Exit]{language["exit"]}')
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
# @Create Time: 2021/10/16
# @File Name: __init__.py
from core.logger import Logger
Logger.info('Be imported')

View File

@@ -10,17 +10,27 @@
启用等级: DEV
"""
from core.read_config import read_config
import requests
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(
f'https://devapi.qweather.com/v7/weather/24h?location={location}&key={key}&lang={lang}&unit={unit}')
data = json.loads(r.text)
status_code = data['code']
updateTime = str(data['updateTime'][:-6]).replace('T', '')
updateTime = str(data['updateTime'][:-6])[10:].replace('T', '')
main_data = data['hourly'] # 24
return status_code, updateTime, main_data

View File

@@ -11,11 +11,21 @@
启用等级: DEV
"""
from core.read_config import read_config
import requests
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(
f'https://devapi.qweather.com/v7/indices/1d?type=0&location={location}&key={key}&lang={lang}&unit={unit}')
data = json.loads(r.text)

View File

@@ -10,29 +10,24 @@
启用等级: DEV
"""
from core.read_config import read_config
import requests
import json
import sys
from ruamel.yaml import YAML
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']
key = config['request-settings']['key']
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')
r = requests.get(f'https://devapi.qweather.com/v7/air/now?'
f'location={location}&key={key}&lang={lang}&unit={unit}&gzip=y')
_data = json.loads(r.text)
return _data['code'], _data['now']
return _data['now']

View File

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

23
lib/hitokoto.py Normal file
View File

@@ -0,0 +1,23 @@
# -- coding:utf-8 --
# @Author: markushammered@gmail.com
# @Development Tool: PyCharm
# @Create Time: 2021/12/24
# @File Name: hitokoto.py
import requests
from core.language import Language
from core.logger import Logger
def hitokoto():
language = Language()
url = 'https://v1.hitokoto.cn/'
Logger.info(f'{language["hitokoto"]}')
res = requests.get(url).json()
speaker = res['from_who']
text = res['hitokoto']
if not speaker:
speaker = language['noname']
full_text = f'{text} --{speaker}'
return full_text

336
lib/webservice.py Normal file
View File

@@ -0,0 +1,336 @@
#!/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 threading
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(('127.0.0.1', 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_requests(c, a):
"""
处理请求
:param c: connection
:param a: address
:return:
"""
try:
data = str(c.recv(1024)).split(':')[0][6:][:-17]
html = build_html()
if data == '/' or '': # 判断用户请求的目标是否为根目录, 如果是则返回html; 如果不是则继续判断
c.sendto('HTTP1.1/ 200 OK\r\n\r\n'.encode('utf-8'), a)
c.sendto(html.encode('utf-8'), a)
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.sendto('HTTP1.1/ 200 OK\r\n\r\n'.encode('utf-8'), a)
c.sendto(f.read(), a)
Logger.info(f'{language["get_resource"]} {data} {language["get_resource_from"]} {a[0]}:{a[1]}')
except FileNotFoundError:
c.sendto(f'HTTP1.1/ 404 Not Found\r\n\r\n{html}'.encode('utf-8'), a)
except BrokenPipeError:
Logger.error(f'{language["connection_speed_too_fast"]}')
except IOError:
Logger.error(f'{language["an_io_error"]}')
finally:
c.close()
return
def accept_requests():
"""
接受请求
:return:
"""
while True:
c, a = server.accept()
threading.Thread(target=process_requests, args=(c, a,)).start()

View File

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

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.",
"config_file_read_successfully": "Read config file 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",
"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": "没有搜索到相关结果",
"config_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": "连接速度过快",
"an_io_error": "一个IO错误",
"noname": "佚名",
"hitokoto": "一言获取成功",
"get_resource": "获取资源",
"get_resource_from": "来自"
}

View File

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