使用 Python + xxl-job 构建爬虫系统

本文详细描述了一种使用xxl-job框架构建的爬虫系统,包括任务管理系统(CRUD操作和任务调度)和数据爬取系统(PythonDjango实现),并通过定时任务管理爬虫执行,以及如何将数据爬取系统注册到xxl-job并上报任务状态。
摘要由CSDN通过智能技术生成

1 系统功能概述

爬虫系统包括爬虫任务管理系统数据爬取系统

爬虫任务管理系统包括爬虫任务的 crud、爬虫任务执行的启动和停止功能。

数据爬取系统用于数据的爬取和入库。

2 技术实现概述

使用 xxl-job 框架构建爬虫任务管理系统;

使用 Pyhon 的 django 框架构建数据爬取系统;

将数据爬取系统注册到 xxl-job 系统中,通过管理定时任务的方式来管理爬虫任务。

3 将数据爬取系统注册到 xxl-job 系统中

3.1 配置

配置xxl-job 服务端信息和 xxl-job 执行器信息。举例如下。

# xxl-job 服务端
# xxl-admin服务端暴露的restful接口url(如http://localhost:8080/xxl-job-admin/api/)
XXL_ADMIN_BASEURL: str = 'http://xxl-job-test.com/api/'
# 请求令牌
XXL_JOB_ACCESS_TOKEN: str = 'test_token'

# xxl-job 执行器信息
EXECUTOR_APP_NAME: str = 'test-spider-web'
EXECUTOR_PORT: int = 9999

3.2 代码

3.2.1 注册执行器到 xxl-job 服务端

数据爬取系统通过调用 xxl-job 的 registry 接口来注册执行器到 xxl-job 服务端。举例如下所示。

# 项目启动时,异步执行注册执行器到xxl-job服务端
register_async()

# 异步执行注册执行器到xxl-job服务端
def register_async():
    logger.info("register_async 注册执行器到xxl-job服务端")

    p = Pool(1)
    p.apply_async(register_node, ())

    logger.info("register_async 注册执行器到xxl-job服务端成功")


# 注册执行器到xxl-job服务端
def register_node():
    # 必须循环去注册,不然会显示为离线
    try:
        while True:
            registry()
            time.sleep(10)
    finally:
        logger.error("Register node is exit.")


# 注册
def registry():
    payload = {
        "registryGroup": "EXECUTOR",
        "registryKey": settings.EXECUTOR_APP_NAME,
        "registryValue": executor_baseurl()
    }
    try:
        headers = {"XXL-JOB-ACCESS-TOKEN": settings.XXL_JOB_ACCESS_TOKEN}
        response = post_simple(settings.XXL_ADMIN_BASEURL + "registry", payload, headers)
        if response.get("code") != 200:
            logger.error("registry error. {}".format(str(response)))
            return False
        return True
    except BaseException as e:
        logger.error("registry error. {}".format(str(e)))


def executor_baseurl() -> str:
    return "http://{host}:{port}".format(host=get_network_ip(), port=settings.EXECUTOR_PORT)


3.2.2 接口调用工具类

def post_simple(url, data, headers):
    times = 0
    while times < settings.REQUEST_RETRY_TIMES:
        try:
            response = requests.post(url, json=data, headers=headers)
            if response.status_code != 200:
                logger.error("post 请求失败. url:{}, data:{}. response:{}".format(url, data, response.text))
                raise BusinessError("请求失败")
            else:
                return response.json()

        except BaseException as e:
            times += 1
            logger.warning(
                "post 请求连接失败. times:{}, retry after:{}, url:{}. data:{}.error:{}"
                .format(times, settings.REQUEST_RETRY_INTERVAL, url, str(data), str(e))
            )
            time.sleep(settings.REQUEST_RETRY_INTERVAL)

    logger.error("post 请求连接失败. url:{}, data:{}".format(url, data))
    raise BusinessError("请求连接失败")


def get_network_ip() -> str:
    """获取本机地址,会获取首个网络地址"""
    _, _, ipaddrlist = socket.gethostbyname_ex(socket.gethostname())
    return ipaddrlist[0]

4 定时任务执行

4.1 定时任务的执行流程

XXL-JOB调度中心通过HTTP的方式,调用执行器的任务。具体流程如下:

  • 调度中心将任务调度信息推送给执行器。这些任务调度信息主要包括:任务ID、本次调度日志id、本次调度日志时间、任务参数等。
  • 执行器在收到调度信息后,启动任务的执行。这一过程在执行器的机器上进行。
  • 任务执行完毕后,执行器将执行结果返回给调度中心。这些执行结果主要包括:执行成功或失败、执行日志等。

4.2 触发任务执行

4.2.1 数据爬取系统暴露名称为“run” 的 http 接口

如 http://localhost:9999/run 。 爬取逻辑全部放在 run 接口中。举例如下。

# (1)接口暴露 urls.py 文件
urlpatterns = [
    path('run', spider.run, name='run'),
]


# (2)run 接口 spider.py 文件
@api_view(['POST'])
def run(request):
    """
    爬虫执行入口
    """
    logger.info("============ run 执行定时任务 start")

    # 入参
    request_data = JSONParser().parse(request)
    executor_handler = request_data['executorHandler']
    executor_params = request_data['executorParams']
    executor_params_dict = json.loads(executor_params)

    # 任务异步执行
    if executor_handler == 'task01':
        submit_task(TaskService01.doXxlJobTask, (executor_params_dict, request_data))
    if executor_handler == 'task02':
        submit_task(TaskService02.doXxlJobTask, (executor_params_dict, request_data))


    logger.info("============ run 执行定时任务 finish")
    return HttpResponse(json.dumps(dict(code=200, msg='成功')))
    

# (3)线程池工具类 thread_pool_util.py 文件

import logging
from multiprocessing.dummy import Pool
# 通用线程池
pool = Pool(10000)
logger = logging.getLogger(__name__)


# 异步执行任务
def submit_task(func, args) -> None:
    try:
        pool.apply_async(func, args)
    except BaseException as e:
        logger.error("submit_task:执行失败. error:{}".format(str(e)))

4.2.2 xxl-job 定时调用上述 “run” 接口

xxl-job 调度中心通过HTTP的方式,调用执行器的任务。

具体来说是指 xxl-job 通过调用执行器的 “run” 接口来执行定时任务。

4.3 任务状态上报

任务执行完成后,数据爬取系统通过调用 xxl-job 的 callback 接口来进行定时任务执行状态上报。

# 任务状态上报. code:200-表示任务执行正常,500-表示失败,100-执行中
def callback(log_id, timestamp, code):
    if log_id is None or timestamp is None:
        return False

    payload = [
        {
            "logId": log_id,          # 本次调度日志id
            "logDateTim": timestamp,  # 本次调度时间  
            "handleCode": code        # 任务状态
        }
    ]

    try:
        headers = {"XXL-JOB-ACCESS-TOKEN": settings.XXL_JOB_ACCESS_TOKEN}
        response = post_simple(settings.XXL_ADMIN_BASEURL + "callback", payload, headers)
        if response.get("code") != 200:
            logger.error("callback error.log_id:{}.response{}".format(log_id, str(response)))
            return False
        return True
    except BaseException as e:
        logger.error("callback error. {}".format(str(e)))

5 参考文献

(1)分布式任务调度平台XXL-JOB 官方文档
 

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
xxl-job是一个分布式任务调度平台,可以用于Java和Python等多种语言的任务调度。下面我将分别介绍Java和Python如何调用xxl-job。 Java调用xxl-job的步骤如下: 1. 在Java项目中引入xxl-job的依赖。可以通过Maven或者Gradle等构建工具添加以下依赖: ```xml <dependency> <groupId>com.xuxueli</groupId> <artifactId>xxl-job-core</artifactId> <version>2.3.0</version> </dependency> ``` 2. 在Java代码中编写任务执行逻辑。需要实现xxl-job提供的`IJobHandler`接口,并重写`execute`方法,该方法即为任务的执行逻辑。 ```java public class MyJobHandler extends IJobHandler { @Override public ReturnT<String> execute(String param) throws Exception { // 任务执行逻辑 // ... return ReturnT.SUCCESS; } } ``` 3. 在xxl-job管理后台配置任务。登录xxl-job管理后台,创建一个任务,并配置任务的执行器为Java任务,同时指定任务的执行类为上一步编写的`MyJobHandler`。 4. 启动xxl-job的执行器。在Java项目中添加一个启动类,通过调用`XxlJobExecutor`的`init`方法来启动执行器。 ```java public class XxlJobExecutorSample { public static void main(String[] args) { XxlJobExecutor.init(); } } ``` 5. 启动Java项目,执行器会自动注册到xxl-job的调度中心,等待调度中心分配任务并执行。 Python调用xxl-job的步骤如下: 1. 安装xxl-jobPython客户端。可以通过pip安装: ``` pip install xxl-job-client ``` 2. 在Python代码中编写任务执行逻辑。需要导入xxl-jobPython客户端,并使用`@job_handler`装饰器来标记任务执行函数。 ```python from xxl_job import job_handler @job_handler def my_job_handler(param): # 任务执行逻辑 # ... return "SUCCESS" ``` 3. 在xxl-job管理后台配置任务。登录xxl-job管理后台,创建一个任务,并配置任务的执行器为Python任务,同时指定任务的执行函数为上一步编写的`my_job_handler`。 4. 启动Python脚本,执行器会自动注册到xxl-job的调度中心,等待调度中心分配任务并执行。 希望以上步骤可以帮助到你,如果有任何问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值