我想将Celery用作Url抓取器。
我有一个Url列表,我必须对每个URL执行HTTP请求,并将结果写入文件(整个列表的文件相同)。
我的第一个想法是在Celery调用的任务中使这个代码击败每个 n 分钟:
@app.task
def get_urls(self):
results = [get_url_content.si(
url=url
) for url in urls]
ch = chain(
group(*results),
write_result_on_disk.s()
)
return ch()
此代码运行良好,但有一个问题:我有一千个要抓取的URL,如果其中一个get_url_content失败,则不会调用write_result_on_disk,我们会丢失之前抓取的所有内容。
我想要做的是通过拆分URL来获取 chunk 任务,获取结果并将其写入磁盘。例如,20个URL的内容写在磁盘上。
请问您有什么想法吗?我尝试了chunks()
函数,但没有得到真正有用的结果。
答案 0 :(得分:2)
使用CeleryBeat进行类似cron的任务是一个好主意。
我会尝试在get_url_content
微任务中捕获异常。当你抓住它们时,只需返回别的东西。这样,您可以在summarize_task中评估(例如计数,列表,检查)。
如何将块和块链用于其他任务:
第1步:将块转换为组:
如http://docs.celeryproject.org/en/latest/userguide/canvas.html#chunks中所述,.group()
将类型celery.canvas.chunks
的对象转换为一个组,这是Celery中更常见的类型。
第2步:将群组和任务联系起来
http://docs.celeryproject.org/en/latest/userguide/canvas.html#the-primitives提到的“通过合并打击你的想法”一节:
将一个组与另一个任务链接在一起会自动升级 它是一个和弦
以下是一些代码,包含两个任务以及我通常如何调用它们:
@app.task
def solve_micro_task(arg: str) -> dict:
...
@app.task
def summarize(items: List[List[dict]]):
flat_list = [item for sublist in items for item in sublist]
for report in flat_list:
...
chunk_tasks = solve_micro_task.chunks(<your iterator, e.g., a list>), 10) # type: celery.canvas.chunks
summarize_task = summarize.s()
chain(chunk_tasks.group(), summarize_task)()