Skip to content

Commit 2fbbce4

Browse files
committed
Python Busclock
1 parent fcb855f commit 2fbbce4

File tree

6 files changed

+273
-0
lines changed

6 files changed

+273
-0
lines changed

taiyangxue/busclock/BusClock.py

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
import httpx
2+
import mail
3+
import datetime
4+
from bs4 import BeautifulSoup as bs4
5+
import re
6+
import config as conf
7+
import os
8+
9+
class BjBusClock():
10+
def __init__(self, logger, config=None, ):
11+
self.logger = logger
12+
import json
13+
if config is None:
14+
with open(r"C:\config.json", "r", encoding='UTF-8') as config_file:
15+
config = json.load(config_file)
16+
if config is None:
17+
raise "没有提供配置且没找到配置文件"
18+
19+
self.config = conf.Config(config) # 整体配置
20+
21+
if self.config.mailConfig is None:
22+
raise "没有发送通知的邮箱配置"
23+
self.config.alertMail = config.get("alertMail", None)
24+
if self.config.alertMail is None:
25+
raise "没有接收通知的邮箱地址"
26+
self.mailClient = mail.MailSent(self.config.mailConfig)
27+
self.logger.info("BusClock 初始化完毕")
28+
29+
30+
def run(self):
31+
self.logger.info("BusClock 执行运算")
32+
for line in self.config.lines:
33+
self.logger.info("BusClock 执行线路:" + "@" + line['line'])
34+
if self.onTime(line['begin'], line['end']):
35+
self.logger.info("BusClock 达到提示时间 " + "@" + line['line'])
36+
if line.get('needSentMail', True):
37+
self.logger.info("BusClock 需要发提醒 " + "@" + line['line'])
38+
bustime = self.getBusTime(line)
39+
if bustime is None:
40+
self.logger.info("BusClock 尚未发车: " + "@" + line['line'])
41+
else:
42+
self.logger.info("BusClock 得到车辆时间: " + bustime + "@" + line['line'])
43+
if int(bustime) <= int(line.get('latestLeaveMinute', self.config.latestLeaveMinute)):
44+
self.logger.info("BusClock 可以发邮件提醒了" + "@" + line['line'])
45+
self.mailClient.send_mail(self.config.alertMail, '班车提醒: '+line['line'], '车辆即将到站,现在出发正当时')
46+
self.logger.info("BusClock 邮件提醒已发送" + "@" + line['line'])
47+
line['needSentMail'] = False # 发送通知后,不必再发了
48+
else:
49+
self.logger.info("BusClock 没到发邮件的时候" + "@" + line['line'])
50+
else:
51+
self.logger.info("BusClock 已经发过邮件了" + "@" + line['line'])
52+
else:
53+
line['needSentMail'] = True
54+
self.logger.info("BusClock 未到时间窗口" + "@" + line['line'])
55+
56+
57+
def onTime(self, begin, end):
58+
d_time = datetime.datetime.strptime(
59+
str(datetime.datetime.now().date())+begin, '%Y-%m-%d%H:%M')
60+
d_time1 = datetime.datetime.strptime(
61+
str(datetime.datetime.now().date())+end, '%Y-%m-%d%H:%M')
62+
n_time = datetime.datetime.now()
63+
if n_time > d_time and n_time < d_time1:
64+
return True
65+
else:
66+
return False
67+
68+
def getBusTime(self, line):
69+
url = 'http://www.bjbus.com/home/ajax_rtbus_data.php?act=busTime&selBLine=%(line)s&selBDir=%(dir)s&selBStop=%(stop)s' % line
70+
result = None
71+
try:
72+
r = httpx.get(url).json()
73+
b = bs4(r.get('html'), 'html.parser')
74+
info = b.find('article')
75+
i = info.find_all('p')[1]
76+
ret = re.search(r'\d+(?=\s分钟)', i.text)
77+
result = None
78+
if ret:
79+
result = ret.group()
80+
except BaseException:
81+
pass
82+
83+
return result
84+
85+
86+
if __name__ == "__main__":
87+
import logging
88+
logging.basicConfig(filename=r'D:\busclock.log', level=logging.INFO)
89+
bus = BjBusClock(logging, {
90+
"loopWaitSeconds": 60,
91+
"spurtWaitSeconds": 10,
92+
"latestLeaveMinute": 5,
93+
"mailConfig": {
94+
"FROM": "tom@example.com",
95+
"HOST": "smtp.example.com",
96+
"PORT": "465",
97+
"USER": "tom",
98+
"PASS": "password",
99+
"SSL": True
100+
},
101+
"alertMail": "lily@example.com",
102+
"lines": [{
103+
"line": "835快",
104+
"dir": "5066222788346588777",
105+
"stop": "13",
106+
"begin": "08:00",
107+
"end": "08:30"
108+
}, {
109+
"line": "835快",
110+
"dir": "4997908670784162973",
111+
"stop": "3",
112+
"begin": "19:00",
113+
"end": "20:30"
114+
}]
115+
})
116+
print(bus.onTime("12:00", "13:00"))
117+
print(bus.getBusTime(bus.config.lines[0]))
118+
print(bus.run())

taiyangxue/busclock/config.json

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"loopWaitSeconds": 60,
3+
"spurtWaitSeconds": 10,
4+
"latestLeaveMinute": 5,
5+
"mailConfig": {
6+
"FROM": "tom@example.com",
7+
"HOST": "smtp.example.com",
8+
"PORT": "465",
9+
"USER": "tom",
10+
"PASS": "password",
11+
"SSL": true
12+
},
13+
"alertMail": "lily@example.com",
14+
"lines": [{
15+
"line": "835快",
16+
"dir": "5066222788346588777",
17+
"stop": "13",
18+
"begin": "08:00",
19+
"end": "08:30"
20+
}, {
21+
"line": "835快",
22+
"dir": "4997908670784162973",
23+
"stop": "3",
24+
"begin": "19:00",
25+
"end": "20:30"
26+
}]
27+
}

taiyangxue/busclock/config.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
class Config:
2+
def __init__(self, config):
3+
self.loopWaitSeconds = config.get("loopWaitSeconds", 60)
4+
self.spurtWaitSeconds = config.get("spurtWaitSeconds", 10)
5+
self.mailConfig = config.get("mailConfig", None)
6+
self.latestLeaveMinute = config.get("latestLeaveTime", 5)
7+
self.lines = config.get("lines", {})

taiyangxue/busclock/mail.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#!/usr/local/bin/python3
2+
# coding=utf-8
3+
4+
import smtplib
5+
from email.mime.multipart import MIMEMultipart
6+
from email.mime.text import MIMEText
7+
8+
9+
class MailSent(object):
10+
default_config = {
11+
'PORT': '465',
12+
'SSL': True
13+
}
14+
15+
def __init__(self, config):
16+
self.config = {
17+
'FROM': config.get('mail_from', self.default_config['FROM']),
18+
'HOST': config.get('mail_host', self.default_config['HOST']),
19+
'PORT': config.get('port', self.default_config['PORT']),
20+
'USER': config.get('user', self.default_config['USER']),
21+
'PASS': config.get('mail_pass', self.default_config['PASS']),
22+
'SSL': config.get('ssl', self.default_config['SSL']),
23+
}
24+
25+
def send_mail(self, to_mail, title, content):
26+
ret = True
27+
FROM_MAIL = self.config['FROM'] # 发件人
28+
if type(to_mail) == 'list':
29+
TO_MAIL = to_mail # 收件人
30+
else:
31+
TO_MAIL = [to_mail]
32+
33+
SMTP_SERVER = self.config['HOST'] # qq邮箱服务器
34+
SSL_PORT = self.config['PORT'] # 加密端口
35+
USER_NAME = self.config['USER'] # qq邮箱用户名
36+
USER_PWD = self.config['PASS'] # qq邮箱授权码
37+
msg = MIMEMultipart('alternative') # 实例化email对象
38+
msg['from'] = FROM_MAIL # 对应发件人邮箱昵称、发件人邮箱账号
39+
msg['to'] = ';'.join(TO_MAIL) # 对应收件人邮箱昵称、收件人邮箱账号
40+
msg['subject'] = title # 邮件的主题
41+
txt = MIMEText(content, 'html')
42+
msg.attach(txt)
43+
try:
44+
# 纯粹的ssl加密方式
45+
smtp = smtplib.SMTP_SSL(SMTP_SERVER, SSL_PORT) # 邮件服务器地址和端口
46+
smtp.ehlo() # 用户认证
47+
smtp.login(USER_NAME, USER_PWD) # 括号中对应的是发件人邮箱账号、邮箱密码
48+
smtp.sendmail(FROM_MAIL, TO_MAIL, str(msg)) # 收件人邮箱账号、发送邮件
49+
smtp.quit() # 等同 smtp.close() ,关闭连接
50+
# print('发送成功')
51+
except Exception:
52+
ret = False
53+
return ret
188 Bytes
Binary file not shown.

taiyangxue/busclock/service.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import sys
2+
import time
3+
from datetime import datetime
4+
5+
import win32api
6+
import win32event
7+
import win32service
8+
import win32serviceutil
9+
import servicemanager
10+
import logging
11+
12+
import BusClock
13+
14+
15+
class MyService(win32serviceutil.ServiceFramework):
16+
17+
_svc_name_ = "MYBusClock"
18+
_svc_display_name_ = "MyBusClock"
19+
_svc_description_ = "提醒公交车到站时间,帮助我节约时间"
20+
21+
def __init__(self, args):
22+
logging.basicConfig(filename=r'D:\busclock.log', level=logging.INFO)
23+
logging.info("init")
24+
win32serviceutil.ServiceFramework.__init__(self, args)
25+
self.stop_event = win32event.CreateEvent(None, 0, 0, None)
26+
self.isAlive = True
27+
self.loopWaitSeconds = 5
28+
self.busClock = BusClock.BjBusClock(logging)
29+
30+
def SvcDoRun(self):
31+
self.ReportServiceStatus(win32service.SERVICE_START_PENDING)
32+
try:
33+
self.ReportServiceStatus(win32service.SERVICE_RUNNING)
34+
logging.info('start')
35+
self.start()
36+
logging.info('wait')
37+
win32event.WaitForSingleObject(
38+
self.stop_event, win32event.INFINITE)
39+
logging.info('done')
40+
except BaseException as e:
41+
logging.info('Exception : %s' % e)
42+
self.SvcStop()
43+
44+
def SvcStop(self):
45+
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
46+
logging.info('stopping')
47+
self.stop()
48+
logging.info('stopped')
49+
win32event.SetEvent(self.stop_event)
50+
self.ReportServiceStatus(win32service.SERVICE_STOPPED)
51+
52+
def start(self):
53+
logging.info("svc do run....")
54+
while self.isAlive:
55+
self.busClock.run()
56+
time.sleep(self.loopWaitSeconds)
57+
58+
def stop(self):
59+
self.isAlive = False
60+
pass
61+
62+
if __name__ == "__main__":
63+
if len(sys.argv) == 1:
64+
servicemanager.Initialize()
65+
servicemanager.PrepareToHostSingle(MyService)
66+
servicemanager.StartServiceCtrlDispatcher()
67+
else:
68+
win32serviceutil.HandleCommandLine(MyService)

0 commit comments

Comments
 (0)