APScheduler定时任务使用以及在flask中的调用
任务需求:在flask中每天自动同步大众点评数据到数据库,这里选择了Flask-APScheduler
APScheduler简介
APScheduler基于Quartz的一个Python定时任务框架,实现了Quartz的所有功能,使用起来十分方便。提供了基于日期、固定时间间隔以及crontab类型的任务,并且可以持久化任务。基于这些功能,我们可以很方便的实现一个python定时任务系统。
组成部分
APScheduler有四种组成部分:
- 触发器(trigger)包含调度逻辑,每一个作业有它自己的触发器,用于决定接下来哪一个作业会运行。除了他们自己初始配置意外,触发器完全是无状态的。
- 作业存储(jobstore)存储被调度的作业,默认的作业存储是简单地把作业保存在内存中,其他的作业存储是将作业保存在数据库中。一个作业的数据讲在保存在持久化作业存储时被序列化,并在加载时被反序列化。调度器不能分享同一个作业存储。
- 执行器(executor)处理作业的运行,他们通常通过在作业中提交制定的可调用对象到一个线程或者进城池来进行。当作业完成时,执行器将会通知调度器。
- 调度器(scheduler)是其他的组成部分。你通常在应用只有一个调度器,应用的开发者通常不会直接处理作业存储、调度器和触发器,相反,调度器提供了处理这些的合适的接口。配置作业存储和执行器可以在调度器中完成,例如添加、修改和移除作业。
调度器
APScheduler提供了多种调度器,可以根据具体需求来选择合适的调度器,常用的调度器有:
-
BlockingScheduler:适合于只在进程中运行单个任务的情况,通常在调度器是你唯一要运行的东西时使用。
-
BackgroundScheduler: 适合于要求任何在程序后台运行的情况,当希望调度器在应用后台执行时使用。
-
AsyncIOScheduler:适合于使用asyncio框架的情况
-
GeventScheduler: 适合于使用gevent框架的情况
-
TornadoScheduler: 适合于使用Tornado框架的应用
-
TwistedScheduler: 适合使用Twisted框架的应用
-
QtScheduler: 适合使用QT的情况
安装
普通使用安装
pip install apscheduler
结合flask使用安装
pip install Flask-APScheduler
使用
添加job
- work1使用add_job()方法添加,表示每隔5秒执行一次,第一次执行是程序运行5秒后
- work2使用装饰器添加
import time
from apscheduler.schedulers.blocking import BlockingScheduler
sched = BlockingScheduler()
def work1():
print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())))
@sched.scheduled_job('interval', seconds=2)
def work2():
print('work2222')
sched.add_job(work1, 'interval', seconds=5)
sched.start()
add_job参数详解
id
# id代表该job唯一标识,不可重复,之后可以用id查找job
sched.add_job(work1, 'interval', seconds=5, id='my_work1')
trigger
它管理着作业的调度方式。它可以为date, interval或者cron。对于不同的trigger,对应的参数也不同。
interval 间隔时间(每隔一段时间执行)
后面可以写的参数:
- weeks (int) – number of weeks to wait
- days (int) – number of days to wait
- hours (int) – number of hours to wait
- minutes (int) – number of minutes to wait
- seconds (int) – number of seconds to wait
- start_date (datetime|str) – starting point for the interval
calculation - end_date (datetime|str) – latest possible date/time to trigger on
- timezone (datetime.tzinfo|str) – time zone to use for the date/time
calculations
#表示每隔3天17时19分07秒执行一次任务
sched.add_job(my_job, 'interval',days=3,hours=17,minutes=19,seconds=7)
date 定时调度(只执行一次)
- run_date (datetime|str) – the date/time to run the job at -(任务开始的时间)
- timezone (datetime.tzinfo|str) – time zone for run_date if it doesn’t have one already
# The job will be executed on November 6th, 2009
sched.add_job(func=work1, trigger='date', run_date=date(2009, 11, 6), args=['text'])
# The job will be executed on November 6th, 2009 at 16:30:05
sched.add_job(func=work1, trigger='date', run_date=datetime(2009, 11, 6, 16, 30, 5), args=['text'])
cron定时调度(某一定时时刻执行)
后面参数和interval大致相同
# 表示2017年3月22日17时19分07秒执行该程序
sched.add_job(work1, 'cron', year=2017, month=3, day=22, hour=17, minute=19, second=7)
# 表示任务在6,7,8,11,12月份的第三个星期五的00:00,01:00,02:00,03:00 执行该程序
sched.add_job(work1, 'cron', month='6-8,11-12', day='3rd fri', hour='0-3')
# 表示从星期一到星期五5:30(AM)直到2014-05-30 00:00:00
sched.add_job(work1, 'cron', day_of_week='mon-fri', hour=5, minute=30, end_date='2014-05-30')
# 表示每5秒执行该程序一次,相当于interval 间隔调度中seconds = 5
sched.add_job(work1, 'cron', second='*/5')
args 参数,要可迭代对象
job的其他操作
# 移除所有,移除要放在start之前才有效
sched.remove_all_jobs()
# 根据id移除job
sched.remove_job('my_work1')
sched.pause_job('my_work1') # 暂停
sched.resume_job('my_work1') # 恢复
sched.get_job('my_work1') # 获取
sched.get_jobs() # 获取所有job列表
# 默认情况是调度器等所有job完成后关闭,设为False时直接关闭
sched.shutdown(wait=False)
结合flask使用(大众点评数据同步实例)
flask的项目结构是util目录下有个dianpingUtil.py文件,文件里有个函数dianPing()是要执行的定时任务
import hashlib
import time
import json
from http import client
from urllib.parse import urlencode
from model.ZLHModel import ZlhUserFinanceDianping
def dianPing(current_app):
data_type = 1
today_date = time.strftime("%Y-%m-%d", time.localtime())
_where = (ZlhUserFinanceDianping.ufd_date == today_date) & (ZlhUserFinanceDianping.ufd_data_type == data_type)
# 如果已存在则不访问
user_finance_dianping_count = ZlhUserFinanceDianping.select().where(_where).count()
if not user_finance_dianping_count:
host = 'openapi.dianping.com'
appsecret = current_app.config['DIANPING_APPSECRET']
time_stamp = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
params = {'app_key': current_app.config['DIANPING_APPKEY'], 'timestamp': time_stamp,
'session': current_app.config['DIANPING_SESSION'], 'format': "json", 'v': "1",
'sign_method': "MD5",
'open_shop_uuid': current_app.config['DIANPING_OPEN_SHOP_UUID'], 'date_type': str(data_type)}
signstr = sign(params, appsecret, 'MD5')
params['sign'] = signstr
encode_params = urlencode(params)
request_url = "https://openapi.dianping.com/router/merchant/data/consumption"
header = {"Content-type": "application/x-www-form-urlencoded ; charset=UTF-8"}
conn = client.HTTPConnection(host)
conn.request(method="POST", url=request_url, headers=header, body=encode_params)
response = conn.getresponse()
res = response.read()
result = json.loads(res)
if result.get('code') == 200:
for data in result.get('data'):
ZlhUserFinanceDianping.create(ufd_tg_consume_amount=data.get('tg_consume_amount') * 100,
ufd_tg_consume_count=data.get('tg_consume_count'),
ufd_mopay_consume_amount=data.get('mopay_consume_amount') * 100,
ufd_mopay_consume_count=data.get('mopay_consume_count'),
ufd_reservation_consume_amount=data.get(
'reservation_consume_amount') * 100,
ufd_reservation_consume_count=data.get('reservation_consume_count'),
ufd_platform=data.get('platform'),
ufd_date=today_date, ufd_data_type=data_type,
)
current_app.logger.info('大众点评完成同步')
else:
current_app.logger.info('大众点评返回结果错误' + result.get('msg'))
else:
current_app.logger.info('点评当日已保存')
def sign(param, appsecret, signmethod):
if signmethod !="MD5":
return ''
lists = []
param_str = appsecret
for item in param:
lists.append(item)
lists.sort()
for key in lists:
param_str = param_str + key + param[key]
param_str += appsecret
param_str = param_str.strip()
return genMd5(param_str)
def genMd5(str):
md5 = hashlib.md5()
md5.update(str.encode("utf8"))
md5.hexdigest()
return md5.hexdigest()
在flask的config配置中添加:
SCHEDULER_API_ENABLED = True
# 添加需要的配置
# 大众点评
DIANPING_APPSECRET = '***'
DIANPING_APPKEY = '***'
DIANPING_OPEN_SHOP_UUID = '***'
DIANPING_SESSION = '***'
DIANPING_REFRESH_SESSION = '**'
在main.py文件创建flask实例并初始化APScheduler
这里的重点是定时任务需要用到flask app上下文,所以直接将app作为参数传过去即可
from flask import Flask
from flask_apscheduler import APScheduler
... # 省略导入配置文件
app = Flask(__name__, template_folder='templates', static_url_path='/static')
# 注册APScheduler,添加任务
scheduler = APScheduler()
scheduler.init_app(app)
# 表示一天后开始执行,然后每天执行一次
scheduler.add_job(id='dianping', func='util.DianpingUtil:dianPing',
trigger='interval', day=1, args=[app, ])
scheduler.start()
app.config.from_object(app_config[‘dev’]) # 配置文件
# 省略
...
本文介绍了如何在Flask应用中结合APScheduler进行定时任务的设置,包括APScheduler的基本组件、安装方法和不同类型的调度器。通过示例展示了如何添加基于interval、date和cron的job,以及在Flask中配置和执行定时任务,实现大众点评数据的每日同步。


被折叠的 条评论
为什么被折叠?



