19 Commits

Author SHA1 Message Date
RTAkland
639b24a99f feat: update README.md 2021-12-09 22:05:49 +08:00
RTAkland
a43312b65f feat: removed the style 2021-12-09 21:50:20 +08:00
RTAkland
525ec40322 feat: according to QWeather platform update, I deleted old icon styles and added the newest style 2021-12-09 21:49:54 +08:00
RTAkland
383e5e7f78 fix: fixed a bug 2021-12-09 20:50:54 +08:00
RTAkland
f0ffe3a409 feat: increased the log file limit size 2021-12-04 15:55:17 +08:00
RTAkland
efcf52a8c3 feat: reduces log file size limit 2021-12-04 15:32:46 +08:00
RTAkland
07bb161df3 feat: reduces log file size 2021-12-04 15:32:04 +08:00
RTAkland
e994cc4456 feat: updtae something 2021-12-04 15:29:32 +08:00
RTAkland
72dd1e0f98 fix: fixed a bug 2021-12-04 15:29:13 +08:00
RTAkland
616a44d1b0 fix: fixed a bug 2021-12-04 15:08:08 +08:00
RTAkland
52fc71ce92 feat: fixed a bug 2021-12-04 15:07:03 +08:00
RTAkland
a711f11855 feat: modified the HEAD 2021-12-04 14:04:46 +08:00
RTAkland
80fcdbe305 feat: deleted the PAST directory 2021-11-26 20:05:48 +08:00
RTAkland
01ad27fec7 feat: fixed html url target 2021-11-25 13:11:15 +08:00
RTAkland
bf4831f1e6 feat: Modified the README.md 2021-11-24 12:48:02 +08:00
RTAkland
f9e999c85d Merge branch 'main' of github.com:MarkusJoe/QWeather 2021-11-24 12:41:18 +08:00
RTAkland
2ac7aee620 feat: Modified the import 2021-11-24 12:40:12 +08:00
RTAkland
1ed08c6379 feat: 2021-11-24 12:38:16 +08:00
RTAkland
ce3097090a feat: removed the old resource 2021-11-22 20:49:56 +08:00
14 changed files with 79 additions and 255 deletions

View File

@@ -1,10 +1,12 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -- coding:utf-8 --
# @Author: markushammered@gmail.com
# @Development Tool: PyCharm
# @Create Time: 2021/10/23
# @File Name: QWeather.py
import os.path
import os
import sys
import json
import time
@@ -28,8 +30,6 @@ class SendWeatherMail:
def __init__(self):
with open(CONFIG_NAME, 'r', encoding='utf-8') as config_f:
self.config = YAML().load(config_f)
with open('resource/type_warning.json', 'r', encoding='utf-8') as type_f:
self.type_name = json.loads(type_f.read())
self.location = self.config['request-settings']['location'] # 城市ID
self.key = self.config['request-settings']['key'] # API密钥
@@ -41,16 +41,9 @@ class SendWeatherMail:
self.password = self.config['mail-settings']['password'] # 服务器登录密码
self.server = self.config['mail-settings']['server'] # 邮箱服务器
self.port = self.config['mail-settings']['port'] # 邮箱端口号
self.icon_style = self.config['client-settings']['icon-style'] # 天气图标
self.enableSSL = self.config['client-settings'] # 是否使用SSL连接到邮箱服务器
self.city_name = self.config['only-view-settings']['city-name'] # 城市名称仅作邮件内容
self.style_list = ['style1', 'style2', 'style3']
# 如果配置文件内填错 默认选择第一套图标(style1)
if self.icon_style not in self.style_list:
self.icon_style = 'style1'
self.dev_url = 'https://devapi.qweather.com/v7/weather/7d' # 开发版本天气信息url
self.free_url = 'https://devapi.qweather.com/v7/weather/3d' # 免费版本天气信息url
self.warning_url = 'https://devapi.qweather.com/v7/warning/now' # 自然灾害预警信息url
@@ -247,7 +240,7 @@ class SendWeatherMail:
<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/HeWeatherReporter" style="color: black" target="_blank">Github Repo</a>
<a href="https://github.com/MarkusJoe/QWeather" style="color: black" target="_blank">Github Repo</a>
</b>
</i>
</div>"""
@@ -257,17 +250,17 @@ class SendWeatherMail:
# 循环将图片attach到html里
image_count = 1
for image_resource in icon_list:
with open(f'./resource/{self.icon_style}/{image_resource}.png', 'rb') as fp:
with open(f'./resource/icons/{image_resource}.png', 'rb') as fp:
MyImage = MIMEImage(fp.read())
MyImage.add_header('Content-ID', f'img{image_count}')
self.message.attach(MyImage)
image_count += 1
with open('resource/basic-resources/sunrise.png', 'rb') as sr_f:
with open('./resource/basic-resources/sunrise.png', 'rb') as sr_f:
sunrise_img = MIMEImage(sr_f.read())
sunrise_img.add_header('Content-ID', 'sunrise')
self.message.attach(sunrise_img)
with open('resource/basic-resources/sunset.png', 'rb') as ss_f:
with open('./resource/basic-resources/sunset.png', 'rb') as ss_f:
sunset_img = MIMEImage(ss_f.read())
sunset_img.add_header('Content-ID', 'sunset')
self.message.attach(sunset_img)
@@ -410,7 +403,7 @@ class SendWeatherMail:
image_count = 1
for image_source_free in icon_list:
with open(f'./resource/{self.icon_style}/{image_source_free}.png', 'rb') as file:
with open(f'./resource/icons/{image_source_free}.png', 'rb') as file:
MyImage = MIMEImage(file.read())
MyImage.add_header('Content-ID', f'img{image_count}')
self.message.attach(MyImage)
@@ -448,20 +441,19 @@ class SendWeatherMail:
如果不为空则单独发送一封邮件
:return:
"""
r = session.get(self.warning_url, headers=self.headers, params=self.params)
data = r.json()
r = session.get(self.warning_url, headers=self.headers, params=self.params).json()
logger.info(f'{language["request_result_warning"]}:{data["code"]}')
if data['warning']:
public_time = data['warning'][0]['pubTime']
title = data['warning'][0]['title']
start_time = data['warning'][0]['startTime']
end_time = data['warning'][0]['endTime']
logger.info(f'{language["request_result_warning"]}:{r["code"]}')
if r['warning']:
public_time = r['warning'][0]['pubTime']
title = r['warning'][0]['title']
start_time = r['warning'][0]['startTime']
end_time = r['warning'][0]['endTime']
if not start_time:
start_time = None
elif not end_time:
end_time = None
warning_status = data['warning'][0]['status']
warning_status = r['warning'][0]['status']
if warning_status == 'update':
warning_status = {language["new_warning"]}
logger.info(f'{language["new_warning"]}')
@@ -471,10 +463,9 @@ class SendWeatherMail:
elif warning_status == 'cancel':
logger.info(f'{language["warning_canceled"]}')
level = data['warning'][0]['level']
type_ = data['warning'][0]['type']
type_ = self.type_name[type_] # 将数字type转换为文字
text = data['warning'][0]['text']
level = r['warning'][0]['level']
type_ = r['warning'][0]['typeName']
text = r['warning'][0]['text']
self.message['Subject'] = language['subject_war']
self.message['Subject'] = f'{title}'
mail_html = f"""
@@ -489,7 +480,7 @@ class SendWeatherMail:
<h2>{title}</h2>
<h3>{language['release_time']}:{public_time[:10]} {level}{language['early_warning']}</h3>
<p>
{language['warning_status']}:{warning_status} {language['warning_type']}:{type_} {language['warning_duration']}:{start_time[:10]}-{end_time[:10]}
{language['warning_status']}:{warning_status} {language['warning_type']}:{type_} {language['warning_duration']}:{start_time[:10]}~{end_time[:10]}
<br />
{text}
</p>
@@ -525,24 +516,25 @@ def loop_check(mode: str, time_list: list):
循环检测时间如果本地时间等于配置文件内填写的时间则发送一封天气信息的邮件
:return:
"""
if mode == 'dev':
while True:
local_time = time.strftime("%H:%M", time.localtime())
time.sleep(1)
if local_time in time_list:
SendWeatherMail().dev_mode()
logger.info(f'{language["mail_succeed"]}')
logger.info(f'{language["wait_seconds"]}')
time.sleep(61)
elif mode == 'free':
while True:
local_time = time.strftime("%H:%M", time.localtime())
time.sleep(1)
if local_time in time_list:
SendWeatherMail().free_mode()
logger.info(f'{language["mail_succeed"]}')
logger.info(f'{language["wait_seconds"]}')
time.sleep(61)
match mode:
case 'dev':
while True:
local_time = time.strftime("%H:%M", time.localtime())
time.sleep(1)
if local_time in time_list:
SendWeatherMail().dev_mode()
logger.info(f'{language["mail_succeed"]}')
logger.info(f'{language["wait_seconds"]}')
time.sleep(61)
case 'free':
while True:
local_time = time.strftime("%H:%M", time.localtime())
time.sleep(1)
if local_time in time_list:
SendWeatherMail().free_mode()
logger.info(f'{language["mail_succeed"]}')
logger.info(f'{language["wait_seconds"]}')
time.sleep(61)
def check_config():
@@ -601,11 +593,15 @@ def modify_config(mode: bool = False):
while True:
time.sleep(0.3)
city_name = input('-->')
if not city_name:
logger.critical(f'[Modify]{language["null_value"]}')
continue
else:
break
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"]}')
@@ -624,7 +620,7 @@ def modify_config(mode: bool = False):
with open(CONFIG_NAME, 'r', encoding='utf-8') as of:
data = YAML().load(of)
data['request-settings']['location'] = index[1]
data['only-view-settings']['city-name'] = f'{index[2]}-{index[3]}-{index[4]}'
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_NAME, 'w', encoding='utf-8') as wf:
@@ -636,14 +632,13 @@ def modify_config(mode: bool = False):
logger.error(f'[Write]{language["input_type_error"]}')
continue
finally:
if not mode:
logger.info('[Done]Program has done.')
sys.exit(0)
logger.info('[Done]Program has done.')
sys.exit(0)
if __name__ == '__main__':
CONFIG_NAME = 'config.yml' # 配置文件名称
LOCATION_ID_FILE_NAME = 'china_city_list_xlsx' # 城市id文件必须为xlsx文件
LOCATION_ID_FILE_NAME = 'china_city_list.xlsx' # 城市id文件必须为xlsx文件
# logs为空文件夹git上传时会自动忽略此文件夹 故添加自动创建文件夹
if not os.path.isdir('./logs'):
@@ -670,8 +665,8 @@ if __name__ == '__main__':
ConsoleLogger.setFormatter(formatter)
log_name = time.strftime('%Y-%m-%d#%H') # 一小时内使用的日志文件都是同一个
FileLogger = logging.handlers.RotatingFileHandler(filename=f'./logs/{log_name}.log',
maxBytes=1024000,
backupCount=5) # 每个日志文件最大1024000字节(≈0.976563Mb)
maxBytes=102400,
backupCount=5) # 每个日志文件最大102400字节(100Kb)
FileLogger.setFormatter(formatter_file)
logger.addHandler(ConsoleLogger)
logger.addHandler(FileLogger)
@@ -733,7 +728,7 @@ if __name__ == '__main__':
logger.info(f'{language["statement_2"]}')
logger.info(f'{language["statement_3"]}')
logger.info(f'{language["statement_4"]}')
logger.info(f'{language["current_profile"]}')
logger.info(f'{language["current_profile"]}: {CONFIG_NAME}')
# 另开一个进程与主进程同时运行 --> 运行loopCheck --> 循环检查本地时间是否与配置内时间相符
multiprocessing.Process(target=loop_check, args=(_MODE, _TIMES,)).run()

View File

@@ -1,7 +1,7 @@
<p align="center">
<a href="https://github.com/MarkusJoe/QWeather">
<img src="https://img.shields.io/badge/Python-V3.10-blue.svg" alt="PythonVersion">
<img src="https://img.shields.io/badge/release-V2.7.0-green.svg" alt="QWeatherVersion">
<img src="https://img.shields.io/badge/release-V2.8.1-green.svg" alt="QWeatherVersion">
<img src="https://img.shields.io/badge/LINCESE-Apache2.0-orange.svg" alt="LICENSE">
</a>
</p>
@@ -10,17 +10,20 @@
## *QWeather*
> <i><a href="https://www.qweather.com/">QWeather Official Website</a></i>\
> <i><a href="https://dev.qweather.com/">QWeather Development Platform</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>
</div>
## Python版本问题
- > 程序使用了Python3.10中的match-case语句
- > 请使用Python3.10版本运行
## 问题汇总
#### Python 版本:
> 程序使用Python3.10中的match-case语句
> 请使用Python3.10版本运行
#### 主题选择:
> 在2.9.0之后的版本不支持自定义天气图标 只能使用最新的图标
#### 配置填写问题:
> `location`项和`only-view-settings`类不需要用户填写, 只需要打开`QWeather.py`进行自助填写
## 配置文件填写问题
- > `location`项和`only-view-settings`类不需要用户填写, 只需要打开`QWeather.py`进行自助填写
## 声明
- > 程序作者: **RTAkland (markushammered@gmail.com)**
@@ -32,15 +35,3 @@
- 将config.yml正确填写完成
- 使用`pip/pip3 install -r requirements.txt` 安装需要的库
- 运行`QWeather.py`
## English README.md
## Statement
- > Developed by **RTAkland (markushammered@gmail.com)**
- > The weather API from QWeather: https://qweather.com
- > QWeather Developer Platform: https://dev.qweather.com
## How to use
- Run program using Python3
- Fill in the configuration file correctly
- Use `pip/pip3 -install -r requirements.txt` to install required libraries
- Run `QWeather.py`

View File

@@ -81,13 +81,6 @@ request-settings:
# 客户端设置
client-settings:
# [必填/只能一个] 图标风格
# 默认: "style1"
# 可选: "style1" , "style2" , "style3"
# 注: style1为简约无色图标 style2为简约有色图标 style3为彩色图标
icon-style: style1
# [必填/可多个] 发送邮件时间 不管有几个必须是列表
# 默认: ['08:00', '12:00', '18:00']
# 具体填写见 *receiver* 示例
@@ -105,9 +98,9 @@ client-settings:
# [标识/不填] 仅作用户读取标识
only-view-settings:
# 城市名
city-name: 黄岩-浙江省-台州
city-name: 黄岩-台州-台州
# 修改时间
time: Thu Nov 18 2021 22:23:29
time: Sat Dec 04 2021 15:27:51
# 修改用户
user: Tapso
user: rtakland

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Author: markushammered@gmail.com
# @Development Tool: PyCharm

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -- coding:utf-8 --
# @Author: markushammered@gmail.com
# @Development Tool: PyCharm

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -- coding:utf-8 --
# @Author: markushammered@gmail.com
# @Development Tool: PyCharm

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Author: markushammered@gmail.com
# @Development Tool: PyCharm

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Author: markushammered@gmail.com
# @Development Tool: PyCharm

Binary file not shown.

View File

@@ -1,68 +0,0 @@
{
"11B01": "台风",
"11B02": "龙卷风",
"11B03": "暴雨",
"11B04": "暴雪",
"11B05": "寒潮",
"11B06": "大风",
"11B07": "沙尘暴",
"11B08": "低温冻害",
"11B09": "高温",
"11B10": "热浪",
"11B11": "干热风",
"11B12": "下击暴流",
"11B13": "雪崩",
"11B14": "雷电",
"11B15": "冰雹",
"11B16": "霜冻",
"11B17": "大雾",
"11B18": "低空风切变",
"11B19": "霾",
"11B20": "雷雨大风",
"11B21": "道路结冰",
"11B22": "干旱",
"11B23": "海上大风",
"11B24": "高温中暑",
"11B25": "森林火险",
"11B26": "草原火险",
"11B27": "冰冻",
"11B28": "空间天气",
"11B29": "重污染",
"11B30": "低温雨雪冰冻",
"11B31": "强对流",
"11B32": "臭氧",
"11B33": "大雪",
"11B34": "寒冷",
"11B35": "连阴雨",
"11B36": "渍涝风险",
"11B37": "地质灾害气象风险",
"11B38": "强降雨",
"11B39": "强降温",
"11B40": "雪灾",
"11B41": "森林(草原)火险",
"11B42": "医疗气象",
"11B43": "雷暴",
"11B44": "停课信号",
"11B45": "停工信号",
"11B46": "海上风险",
"11B47": "春季沙尘天气",
"11B48": "降温",
"11B49": "台风暴雨",
"11B50": "严寒",
"11B51": "沙尘",
"11B52": "海上雷雨大风",
"11B53": "海上大雾",
"11B54": "海上雷电",
"11B55": "海上台风",
"11B56": "低温",
"11B57": "道路冰雪",
"11A01": "洪水",
"11B101": "大风",
"11B102": "强降雪和结冰",
"11B103": "大雾",
"11E101": "海岸风险",
"11B104": "森林火险",
"11B105": "雨",
"11A106": "大雨洪水",
"11B99": "其他"
}

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -- coding:utf-8 --
# @Author: markushammered@gmail.com
# @Development Tool: PyCharm

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Author: markushammered@gmail.com
# @Development Tool: PyCharm

View File

@@ -1,81 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author: markushammered@gmail.com
# @Development Tool: PyCharm
# @Create Time: 2021/10/9
# @File Name: SearchCity.py
import getpass
import time
import sys
import pandas as pd
import logging
from ruamel.yaml import YAML
from colorlog import ColoredFormatter
def read_excel(kw: str):
"""
读取城市列表并根据传入的参数进行搜索
:param kw: 进行匹配的关键字
:return: city_list
"""
index_count = 0
city_list = []
logger.info('文件读取中...')
df = pd.read_excel('./resource/China-City-List.xlsx')
pd.set_option('max_rows', None) # 读取xlsx文件不折叠
data_records = df.to_dict(orient='split')
for i in data_records['data']:
if kw in str(i):
print(
f'\033[32;32m[{time.strftime("%H:%M:%S", time.localtime())}] [INFO] {index_count} {i[2]}-{i[4]}-{i[6]}')
index_count += 1
city_list.append(i)
if not city_list:
return False
return city_list
if __name__ == '__main__':
logger = logging.getLogger("autotest")
logger.setLevel(logging.DEBUG)
fmt = "%(log_color)s[%(asctime)s] [%(log_color)s%(levelname)s] %(log_color)s%(message)s"
dateformat = '%H:%M:%S'
formatter = ColoredFormatter(fmt=fmt, datefmt=dateformat, reset=True, secondary_log_colors={}, style='%')
hd_1 = logging.StreamHandler()
hd_1.setFormatter(formatter)
logger.addHandler(hd_1)
yaml = YAML()
keyword = input(f'\033[32;32m[{time.strftime("%H:%M:%S", time.localtime())}] [INFO] 输入城市名进行搜索:')
if keyword:
result = read_excel(keyword)
if result:
try:
select_index = int(
input(f'\033[32;32m[{time.strftime("%H:%M:%S", time.localtime())}] [INFO] 请输入数据前的索引选择城市:'))
with open('../../config.yml', 'r', encoding='utf-8') as of:
data = yaml.load(of)
data['request-settings']['location'] = result[select_index][0]
data['only-view-settings'][
'city-name'] = f'{result[select_index][2]}-{result[select_index][4]}-{result[select_index][6]} '
data['only-view-settings']['time'] = time.strftime("%a %b %d %H:%M:%S %Y", 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('写入完成')
sys.exit(0)
except ValueError or IndexError:
logger.error('请输入正确的索引')
sys.exit(1)
else:
logger.error('无搜索结果')
sys.exit(1)
else:
logger.error('无搜索结果')
sys.exit(1)

View File

@@ -1,6 +0,0 @@
#!/usr/bin/env python
# -- coding:utf-8 --
# @Author: markushammered@gmail.com
# @Development Tool: PyCharm
# @Create Time: 2021/11/15
# @File Name: __init__.py.py