celery 可视化_Celery部署爬虫(三)

今天就来点比较有意思的东西

面前两篇充其量就是 Celery 的入门级,接下来就深入编写 Celery 框架,让 Celery 更 加健壮。

首先是定时任务,上文的编写的定时任务是在 config 文件里进行配置的,其实在Celery中提供了一系列的装饰器,比如前面说的 @app.task 等等,来看看如何使用装饰器来实现 app 实例中的定时任务

# 定时任务在文件中的写法

# -*- coding:utf-8 -*-

from Celery import app

from celery.schedules import crontab

from celery.utils.log import get_task_logger

logger = get_task_logger(__name__)

# 通过beat组件周期性将任务发送给woker执行。在示例中 新建文件period_task.py 并添加任务到配置文件中

@app.on_after_configure.connect

def setup_periodic_tasks(sender, **kwargs):

sender.add_periodic_task(10.0, add.s(1,3), name='1+3=') # 每10秒执行add

sender.add_periodic_task(

crontab(hour=16, minute=56, day_of_week=1), #每周一下午四点五十六执行sayhai

sayhi.s('wd'),name='say_hi'

)

也就是说通过方法调用的形式来执行定时任务

一般而言,这种格式需要在配置 Beat 中无法达到逻辑需求的时候使用,比较少见。

如果在 config 配置文件中编写了定时任务并希望 Celery Worker 服务进程的同时启动 Beat 模块,需要加入 -B 参数

celery -A haha worker -B -l info

关于路由指定的队列

一般是一个 task 对应一个队列 各个队列相互独立 可以执行不同的操作 比如taskA执行即时任务,taskB执行定时 延时任务等等 需要的是在 config 文件里声明

CELERY_QUEUES = (

Queue("default",Exchange("default"),routing_key="default"),

Queue("for_add",Exchange("for_add"),routing_key="for_add"),

Queue("for_max",Exchange("for_max"),routing_key="for_max")

)

# 路由

CELERY_ROUTES = {

'tasks.add':{"queue":"for_add","routing_key":"for_add"},

'tasks.max':{"queue":"for_max","routing_key":"for_max"}

}

# 路由指明队列和routing_key

# routing_key认证所在的队列 用redis名称要一致(对于redis来说)

指定 CELERY_QUEUES 和 CELERY_ROUTES 选择要执行的任务,这个玩意在分布式任务上还是很方便的,下面说。

自定义Task

如果在Celery中想自定义 Task 基类,那就需要继承 Task 模块

# coding=utf-8

from Celery import app

from celery.schedules import crontab

from celery.utils.log import get_task_logger

from celery import Task

logger = get_task_logger(__name__)

class demotask(Task): # 这是三种运行的状态

def on_success(self, retval, task_id, args, kwargs): # 任务成功执行

logger.info('task id:{} , arg:{} , successful !'.format(task_id,args))

def on_failure(self, exc, task_id, args, kwargs, einfo): #任务失败执行

logger.info('task id:{} , arg:{} , failed ! error : {}' .format(task_id,args,exc))

def on_retry(self, exc, task_id, args, kwargs, einfo): #任务重试执行

logger.info('task id:{} , arg:{} , retry ! info: {}'.format(task_id, args, exc))

@app.task(base=demotask) # 需要继承这个基类

def func1(x,y):

try:

a=[]

a[10] =1

except Exception as e:

logger.info(e)

return x+y

@app.task(base=demotask)

def func2(name):

a=[]

a[10] =1

return 'hi {}'.format(name)

@app.task(base=demotask)

def func3(a,b):

return 'result = {} '.format(a+b)

这算是复写了 Task 模块,定义了几种状态,这个可以根据需求,只要在 task 中声明要继承的自定义类即可。

如果想要深入了解 Task 基类,可以查看 Celery 源码,这就不废话了。

PS:当使用多个装饰器装饰任务函数时,确保 task 装饰器最后应用(在python中,这意味它必须在第一个位置)

@app.task

@decorator2

@decorator1

def add(x, y):

return x + y

另外在Celery中还提供了自带的 logger 日志模块,可以这么用

from celery.utils.log import get_task_logger

logger = get_task_logger(__name__)

@app.task

def add(x, y):

logger.info('Adding {0} + {1}'.format(x, y))

return x + y

Celery的可视化监控

Celery Flower 是一款Celery官方推荐使用的监控工具

能够实时监控 celery 的 Worker Tasks Borker Result等服务

安装也是极其简单

pip install flower

运行服务

celery flower --broker=redis://localhost:6379 --address=127.0.0.1 --port=5555

或者

flower -A proj --broker=redis://localhost:6379

这样就可以访问 Flower Web 了,浏览器访问 http: //127.0.0.1:5555 查看运行的服务

这样一来,在 Celery部署爬虫(一)的百度百科的爬虫就可以重新编写了鬼子口音:Celery部署爬虫(一)​zhuanlan.zhihu.com

Config.py文件

# config.py

from __future__ import absolute_import

# broker

import datetime

BROKER_URL = 'redis://127.0.0.1:6379/0'# backen

CELERY_RESULT_BACKEND = 'mongodb://127.0.0.1:27017'# 导入任务,如tasks.py

CELERY_IMPORTS = ('task', )

# 列化任务载荷的默认的序列化方式

CELERY_TASK_SERIALIZER = 'json'

# 结果序列化方式

CELERY_RESULT_SERIALIZER = 'json'

CELERY_ACCEPT_CONTENT = ['json']

CELERY_TIMEZONE='Asia/Shanghai' # 指定时区,不指定默认为 'UTC'

# CELERY_TIMEZONE='UTC'

# CELERY_ENABLE_UTC = True

Celery.py文件

# Celery.py

# coding=utf-8

from __future__ import absolute_import

from celery import Celery

app = Celery("STQ")

# 加载配置模块

app.config_from_object('config')

if __name__ == '__main__':

app.start()

Task.py 文件

# coding=utf-8

from __future__ import absolute_import

import re

import requests

from lxml import etree

import urllib.request

from Celery import app

headers ={"User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36"}

def get_html(url):

r = urllib.request.Request(url,headers=headers)

res = urllib.request.urlopen(r)

return res.read().decode("utf-8")

@app.task

def parse(html):

ret = re.compile(r'

(.*?)')

title = re.findall(ret,html)

return title

Run_task.py 文件

from __future__ import absolute_import

from tasks import get_html,parse

with open("url.txt","r") as f:

for data in f.readlines():

url = data.strip('\n')

html = get_html(url)

result = parse.delay(html)

黑窗口键入

celery -A Celery worker -l info -P gevent -c 10

然后发布任务让它从消息队列中消费

python run_task.py

这样一来。所有的参数配置都可以在 config 文件中进行配置了

关于路由 队列的使用

CELERY_QUEUES 设置一个指定 routing_key 的队列

CELERY_QUEUES = (

Queue("default",Exchange("default"),routing_key="default"),

Queue("for_add",Exchange("for_add"),routing_key="for_add"),

)

CELERY_ROUTES 设置路由

通过 routing_key 来关联上面的 CELERY_QUEUES,所以这里的 routing_key 需要和上面参数的一致。

# 路由

CELERY_ROUTES = {

'tasks.add':{"queue":"for_add","routing_key":"for_add"},

}

tasks.add 表示在 tasks.py 的函数文件的 add 方法属于哪个路由,而这个路由关联着哪个队列。也就是说声明哪个任务放入哪个队列

如果开启了这个路由,那么此任务就会被执行,反之则不会。

那么如果没有指定队列的方法要怎么执行呢?

celery -A Celery worker -l info -n add -Q for_add -P gevent -c 10

可以在命令中去指定某个任务对应某个队列,所以,发布出去的任务会通过路由关联到指定队列,不同 worker 会从不同的队列来消费任务。

而且每个队列都是相互独立的,这样一来,每个任务之间就不会相互影响了,即时任务,定时任务就可以有明确的分工。

分布式集群

接下来就该说说 Celery 分布式,基本的架构就是通过中间件来共享消息队列。

事实上分布式架构的核心无非就是机器间的通信,而一般的分布式爬虫架构都会体现在共享数据库队列,Redis 和 RabbitMQ 就是典型的消息队列。

比如通过redis来配置共享中间件

redis://ip:6379/0

比如现在有 Master, Slave1, Slave2三台主机,使用Master编写主配置文件,celery主文件,任务和调度文件。

然后拷贝两份分别放到两台Slave里去,在黑窗口中分别键入

celery -A Celery worker -l info

可以看到,在终端中服务器之间已经相互连通

然后发布任务

python run_haha.py

本来监听就监听着 redis队列 的机器就会进行任务消费

需要知道的一点就是,运行队列里的任务的时候,每个机器真正调用的是自身任务文件里面的任务函数,只要该函数存在于队列之中。

然后就和一般的分布式没啥两样了。

好了,今天就这样了

但是,我在想,是不是应该来点刺激的

欢迎转载,但要声明出处,不然我顺着网线过去就是一拳。个人技术博客​www.gzky.live

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值