繁体   English   中英

当新文件到达S3时,触发luigi任务

[英]When a new file arrives in S3, trigger luigi task

我有一个带有新对象的存储桶,其中会根据它们的创建时间随机添加键。 例如:

's3://my-bucket/mass/%s/%s/%s/%s/%s_%s.csv' % (time.strftime('%Y'), time.strftime('%m'), time.strftime('%d'), time.strftime('%H'), name, the_time)

实际上,这些是Scrapy爬网的输出。 我想触发一个将这些爬网与我拥有的主.csv产品目录文件(称为“ product_catalog.csv”)匹配的任务,该文件也会定期更新。

现在,我有一些用全局变量编写的Python脚本,每次运行此过程时都会填写这些变量。 这些需要成为导入的属性。

所以这是需要发生的事情:

1)新的csv文件会根据抓取完成的时间显示在“ s3:// my-bucket / mass / ...”中,并具有唯一的键名称。 路易吉(Luigi)看到了这一点,开始了。
2)luigi在新文件上运行“ cleaning.py”,因此需要在运行时向其提供“ cleaning.py”(在S3中显示的文件)参数。 除了传递到下一步之外,结果还保存在S3中。
3)从数据库中获取“ product_catalog.csv”的最新版本,并使用“ matching.py”中的“ cleaning.py”结果

我意识到这可能并不完整。 我将根据需要提供编辑内容,以使其更加清晰。

编辑

根据最初的答案,我将其配置为拉操作,从而节省了执行过程中的步骤。 但是现在我很迷茫。 应该注意的是,这是我第一次将Python项目绑定在一起,因此我在学习诸如init .py之类的东西时会学习到。 与往常一样,成功是一条坎from的激动之路,紧接着又是下一个障碍。

这是我的问题:
1)我不清楚如何从Scrapy导入蜘蛛。 我大约有十二个,目标是让luigi管理所有这些对象的crawl> clean> match的过程。 Scrapy文档说包括:

class MySpider(scrapy.Spider):
    # Your spider definition

这意味着什么? 在控制蜘蛛的脚本中重新编写蜘蛛? 那没有道理,他们的例子也无济于事。

2)我已经配置了Scrapy管道以导出到S3,但是luigi似乎也可以通过output()来做到这一点。 我应该使用哪个?如何使它们一起玩?

3)Luigi说CrawlTask​​()成功运行了,但是这是错误的,因为它可以在几秒钟内完成,并且爬网通常需要几分钟。 也没有对应于成功的输出文件。

4)我在哪里提供S3的凭据?

这是我的代码。 我已经注释掉了无法代替我认为更好的东西。 但是我的感觉是,我想做的事情有一个宏伟的架构,我只是还不了解。

import luigi
from luigi.s3 import S3Target, S3Client
import my_matching
from datetime import datetime
import os
import scrapy
from twisted.internet import reactor
from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings
from my_crawlers.my_crawlers.spiders import my_spider

class CrawlTask(luigi.Task):
    crawltime = datetime.now()
    spider = luigi.Parameter()
    #vertical = luigi.Parameter()

    def requires(self):
        pass

    def output(self):
        return luigi.LocalTarget("actual_data_staging/crawl_luigi_test_{}.csv".format(self.crawltime))
        #return S3Target("s3://my-bucket/mass/crawl_luigi_test_{}.csv".format(self.crawltime))

    def run(self):
        os.system("scrapy crawl %s" % self.spider)
        #process = CrawlerProcess(get_project_settings())
        #process.crawl("%s" % self.spider)
        #process.start()

class FetchPC(luigi.Task):
    vertical = luigi.Parameter()

    def output(self):
        if self.vertical == "product1":
            return "actual_data_staging/product1_catalog.csv"
        elif self.vertical == "product2":
            return "actual_data_staging/product2_catalog.csv"

class MatchTask(luigi.Task):
    crawltime = CrawlTask.crawltime
    vertical = luigi.Parameter()
    spider = luigi.Parameter()

    def requires(self):
        return CrawlTask(spider=self.spider)
        return FetchPC(vertical=self.vertical)

    def output(self):
        return luigi.LocalTarget("actual_data_staging/crawl_luigi_test_matched_{}.csv".format(self.crawltime))
        #return S3Target("s3://my-bucket/mass/crawl_luigi_test_matched_{}.csv".format(CrawlTask.crawltime))

    def run(self):
        if self.vertical == 'product1':
            switch_board(requires.CrawlTask(), requires.FetchPC())

MatchTask指的是我编写的Python脚本,该脚本将报废的产品与我的产品目录进行比较。 看起来像这样:

def create_search(value):
...
def clean_column(column):
...
def color_false_positive():
...
def switch_board(scrape, product_catalog):
# this function coordinates the whole script

下面是它看起来的非常粗略的轮廓。 我认为与luigi作为拉动系统的工作方式之间的主要区别在于,您首先指定所需的输出,然后触发该输出所依赖的其他任务。 因此,与其在爬网结束时命名事物,不如以一开始就知道的东西来命名事物。 可以用另一种方式来做,只是很多不必要的复杂性。

class CrawlTask(luigi.Task):
    crawltime = luigi.DateParameter()

    def requires(self):
        pass

    def get_filename(self):
        return "s3://my-bucket/crawl_{}.csv".format(self.crawltime)

    def output(self):
        return S3Target(self.get_filename())

    def run(self):
        perform_crawl(s3_filename=self.get_filename())


class CleanTask(luigi.Task):
    crawltime = luigi.DateParameter()

    def requires(self):
        return CrawlTask(crawltime=self.crawltime)

    def get_filename(self):
        return "s3://my-bucket/clean_crawl_{}.csv".format(self.crawltime)

    def output(self):
        return S3Target(self.get_filename())

    def run(self):
        perform_clean(input_file=self.input().path, output_filename=self.get_filename())


class MatchTask(luigi.Task):
    crawltime = luigi.DateParameter()

    def requires(self):
        return CleanTask(crawltime=self.crawltime)

    def output(self):
        return ##?? whatever output of this task is

    def run(self):
        perform_match(input_file=self.input().path)

您可以做的是创建一个同时包含爬网和处理功能的大型系统。 这样,您就不必检查s3中是否有新对象。 我以前没有使用过luigi,但是也许您可以将您的拼凑工作变成一项任务,完成后再执行您的处理任务。 无论如何,我认为“检查” s3中的新内容不是一个好主意,因为1.您将不得不使用大量API调用,并且2.您将需要编写一堆代码来检查是否有“新内容”还是不可以,这可能会变得毛茸茸。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM