簡體   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