Python中定时任务的解决方案,总体来说就四种,分别是:crontab、 scheduler、 Celery、 APScheduler,其中 crontab不适合多台服务器的配置、scheduler太过于简单、 Celery依赖的软件比较多,比较耗资源。最好的解决方案就是 APScheduler
from apscheduler.schedulers.blocking import BlockingScheduler
from datetime import datetime
from selenium import webdriver
from time import sleep
def schedule_task():
"""
create one schedule visitor
:return:
"""
chrome_driver = webdriver.Chrome()
chrome_driver.get("http://online10110.leadscloud.com")
chrome_driver.maximize_window()
sleep(3)
chrome_driver.find_element_by_id("xhl-launch-button-div").click()
sleep(3)
chrome_driver.find_element_by_id("messageText").send_keys("robot visitor")
sleep(3)
chrome_driver.find_element_by_id("sendBtn").click()
print("current time is: %s" % datetime.now())
if __name__ == '__main__':
scheduler = BlockingScheduler()
scheduler.add_job(schedule_task, "interval", seconds=3)
scheduler.start()
在某个日期时间只触发一次事件
from datetime import date
from apscheduler.schedulers.blocking import BlockingScheduler
from selenium import webdriver
from time import sleep
from datetime import datetime
def schedule_task():
"""
create one schedule visitor
:return:
"""
chrome_driver = webdriver.Chrome()
chrome_driver.get("http://online10110.leadscloud.com")
chrome_driver.maximize_window()
sleep(3)
chrome_driver.find_element_by_id("xhl-launch-button-div").click()
sleep(3)
chrome_driver.find_element_by_id("messageText").send_keys("robot visitor")
sleep(3)
chrome_driver.find_element_by_id("sendBtn").click()
print("current time is: %s" % datetime.now())
if __name__ == '__main__':
scheduled_job = BlockingScheduler()
scheduled_job.add_job(schedule_task, 'date', run_date=date(2020, 5, 22))
scheduled_job.start()
想要在固定的时间间隔触发事件。
interval的触发器可以设置以下的触发参数:
from apscheduler.schedulers.blocking import BlockingScheduler
from selenium import webdriver
from time import sleep
from datetime import datetime
def schedule_task():
"""
create one schedule visitor
:return:
"""
chrome_driver = webdriver.Chrome()
chrome_driver.get("http://online10110.leadscloud.com")
chrome_driver.maximize_window()
sleep(3)
chrome_driver.find_element_by_id("xhl-launch-button-div").click()
sleep(3)
chrome_driver.find_element_by_id("messageText").send_keys("robot visitor")
sleep(3)
chrome_driver.find_element_by_id("sendBtn").click()
print("current time is: %s" % datetime.now())
if __name__ == '__main__':
scheduled_job = BlockingScheduler()
scheduled_job.add_job(schedule_task, 'interval', hours=2)
scheduled_job.start()
还可以加上起止时间scheduled_job.add_job(schedule_task, 'interval', hours=2, start_date='2020-10-10 09:30:00', end_date='2024-06-15 11:00:00')
在某个确切的时间周期性的触发事件
也可以用表达式类型,可以用以下方式:
表达式 | 字段 | 描述 |
---|---|---|
* | 任何 | 在每个值都触发 |
*/a | 任何 | 每隔 a触发一次 |
a-b | 任何 | 在 a-b区间内任何一个时间触发( a必须小于 b) |
a-b/c | 任何 | 在 a-b区间内每隔 c触发一次 |
xth y | day | 第 x个星期 y触发 |
lastx | day | 最后一个星期 x触发 |
last | day | 一个月中的最后一天触发 |
x,y,z | 任何 | 可以把上面的表达式进行组合 |
month和day_of_week两个字段接受英文的月和星期的缩写,例如jan – dec and mon – sun
from apscheduler.schedulers.blocking import BlockingScheduler
from selenium import webdriver
from time import sleep
from datetime import datetime
def schedule_task():
"""
create one schedule visitor
:return:
"""
chrome_driver = webdriver.Chrome()
chrome_driver.get("http://online10110.leadscloud.com")
chrome_driver.maximize_window()
sleep(3)
chrome_driver.find_element_by_id("xhl-launch-button-div").click()
sleep(3)
chrome_driver.find_element_by_id("messageText").send_keys("robot visitor")
sleep(3)
chrome_driver.find_element_by_id("sendBtn").click()
print("current time is: %s" % datetime.now())
if __name__ == '__main__':
schedule_job = BlockingScheduler()
schedule_job.add_job(schedule_task, 'cron', month='6-8,11-12', day='3rd fri', hour='0-3')
schedule_job.start()
任务存储器的选择有两种。一是内存,也是默认的配置。二是数据库。使用内存的方式是简单高效,但是不好的是,一旦程序出现问题,重新运行的话,会把之前已经执行了的任务重新执行一遍。数据库则可以在程序崩溃后,重新运行可以从之前中断的地方恢复正常运行
执行器的选择取决于应用场景。通常默认的 ThreadPoolExecutor已经在大部分情况下是可以满足我们需求的。如果我们的任务涉及到一些 CPU密集计算的操作。那么应该考虑 ProcessPoolExecutor。然后针对每种程序, apscheduler也设置了不同的 executor
from apscheduler.schedulers.blocking import BlockingScheduler
from datetime import datetime
from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore
from apscheduler.executors.pool import ThreadPoolExecutor
from selenium import webdriver
from time import sleep
def schedule_task():
"""
create one schedule visitor
:return:
"""
chrome_driver = webdriver.Chrome()
chrome_driver.get("http://online10110.leadscloud.com")
chrome_driver.maximize_window()
sleep(3)
chrome_driver.find_element_by_id("xhl-launch-button-div").click()
sleep(3)
chrome_driver.find_element_by_id("messageText").send_keys("robot visitor")
sleep(3)
chrome_driver.find_element_by_id("sendBtn").click()
print("current time is: %s" % datetime.now())
def interval_task():
# 配置default的任务存储器为SQLAlchemyJobStore(使用SQLite)
jobstores={'default':SQLAlchemyJobStore(url='sqlite:///jobs.sqlite')}
# 配置 default执行器为 ThreadPoolExecutor,并且设置最多的线程数是20个
executors={'default':ThreadPoolExecutor(20)}
'''
设置 coalesce为 False:设置这个目的是,比如由于某个原因导致某个任务积攒了很多次没有执行(比如有一个任务是1分钟跑一次,但是系统原因断了5分钟)
如果 coalesce=True,那么下次恢复运行的时候,会只执行一次,而如果设置 coalesce=False,那么就不会合并,会5次全部执行。
max_instances=5:同一个任务同一时间最多只能有5个实例在运行。比如一个耗时10分钟的job,被指定每分钟运行1次,如果我 max_instance值5,
那么在第6~10分钟上,新的运行实例不会被执行,因为已经有5个实例在跑了
'''
job_defaults={'coalesce':False,'max_instances':3}
scheduler=BlockingScheduler(jobstores=jobstores, executors=executors, job_defaults=job_defaults)
scheduler.add_job(schedule_task, "interval", minutes=1)
scheduler.start()
if __name__ == '__main__':
interval_task()
当我们的任务抛出异常后,我们可以监听到,然后把错误信息进行记录。示例代码如下:
from apscheduler.schedulers.blocking import BlockingScheduler
from apscheduler.events import EVENT_JOB_EXECUTED, EVENT_JOB_ERROR
import datetime
import logging
# 配置日志显示
logging.basicConfig(level=logging.INFO,
format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
datefmt='%Y-%m-%d %H:%M:%S',
filename='log1.txt',
filemode='a'
)
def one_time_task(say_something):
"""
一次性任务
:param say_something:
:return:
"""
print(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), say_something)
def loop_task(say_something):
"""
循环任务
:param say_something:
:return:
"""
print(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), say_something)
# 故意抛出异常
print(1 / 0)
def schedule_job_listener(event):
"""
定时任务监听器
:param event:
:return:
"""
if event.exception:
print('任务出错了!!!!!!')
else:
print('任务照常运行......')
scheduler = BlockingScheduler()
scheduler.add_job(func=one_time_task, args=('一次性任务,会出错',),
next_run_time=datetime.datetime.now() + datetime.timedelta(seconds=15), id='date_task')
scheduler.add_job(func=loop_task, args=('循环任务',), trigger='interval', seconds=3, id='interval_task')
# 配置任务执行完成和执行错误的监听
scheduler.add_listener(schedule_job_listener, EVENT_JOB_EXECUTED | EVENT_JOB_ERROR)
# 设置日志
scheduler._logger = logging
scheduler.start()