在 Python 中完成递归异步作业后如何调用函数?
How to call a function after finishing recursive asynchronous jobs in Python?
我用 scrapy 抓取这个 site。
我想把所有的子分类保存在一个数组中,然后得到对应的页面(分页)
第一步我有
def start_requests(self):
yield Request(start_urls[i], callback=self.get_sous_cat)
get_sous_cat 是一个函数,它获取站点的所有子类别,然后异步启动作业以递归地探索子类别。
def get_sous_cat(self,response):
#Put all the categgories in a array
catList = response.css('div.categoryRefinementsSection')
if (catList):
for category in catList.css('a::attr(href)').extract():
category = 'https://www.amazon.fr' + category
print category
self.arrayCategories.append(category)
yield Request(category, callback=self.get_sous_cat)
当所有相应的请求都发送完毕后,我需要调用这个终止函数:
def pagination(self,response):
for i in range(0, len(self.arrayCategories[i])):
#DO something with each sub-category
我试过了
def start_requests(self):
yield Request(start_urls[i], callback=self.get_sous_cat)
for subCat in range(0,len(self.arrayCategories)):
yield Request(self.arrayCategories[subCat], callback=self.pagination)
这不是 "recursion",它是异步作业。您需要的是一个全局计数器(受锁保护),如果为 0,请完成:
from threading import Lock
class JobCounter(object):
def __init__(self, completion_callback, *args, **kwargs):
self.c = 0
self.l = Lock()
self.completion = (completion_callback, args, kwargs)
def __iadd__(self, n):
b = false
with self.l:
self.c += n
if self.c <= 0:
b = true
if b:
f, args, kwargs = self.completion
f(*args, **kwargs)
def __isub__(self, n):
self.__iadd__(-n)
每次启动作业时,请执行 counter += 1
每次作业完成时,执行 counter -= 1
注意:这会在最后一个调用作业的线程中完成。如果您想在特定线程中执行此操作,请使用条件而不是锁,并执行 notify()
而不是调用。
干得好,这是个好问题!两件小事:
a) 使用集合而不是数组。这样你就不会重复
b) 站点结构将更改一次month/year。您可能会更频繁地爬行。把蜘蛛一分为二; 1. 创建类别 url 列表并每月运行的那个和 2. 获得 start_urls 第一个
生成的文件的那个
现在,如果您真的想按照现在的方式进行操作,请勾选 spider_idle 信号(参见此处:Scrapy: How to manually insert a request from a spider_idle event callback?)。当没有进一步的 url 可执行并允许您注入更多时,将调用此方法。在那个时候设置一个标志或重置您的列表,以便蜘蛛第二次空闲时(在它抓取所有内容之后),它不会永远重新注入相同的类别 url。
如果在您的情况下,您不想对网址做一些花哨的处理,而只是在其他网址之前抓取类别,这就是请求优先级 属性 的用途(http://doc.scrapy.org/en/latest/topics/request-response.html#topics-request-response-ref-request-subclasses).只需将其设置为例如1 用于您的类别 URL,然后它将在处理任何非类别链接之前跟踪这些链接。这样效率更高,因为它不会像您当前的实现那样加载这些类别页面两次。
我用 scrapy 抓取这个 site。
我想把所有的子分类保存在一个数组中,然后得到对应的页面(分页)
第一步我有
def start_requests(self):
yield Request(start_urls[i], callback=self.get_sous_cat)
get_sous_cat 是一个函数,它获取站点的所有子类别,然后异步启动作业以递归地探索子类别。
def get_sous_cat(self,response):
#Put all the categgories in a array
catList = response.css('div.categoryRefinementsSection')
if (catList):
for category in catList.css('a::attr(href)').extract():
category = 'https://www.amazon.fr' + category
print category
self.arrayCategories.append(category)
yield Request(category, callback=self.get_sous_cat)
当所有相应的请求都发送完毕后,我需要调用这个终止函数:
def pagination(self,response):
for i in range(0, len(self.arrayCategories[i])):
#DO something with each sub-category
我试过了
def start_requests(self):
yield Request(start_urls[i], callback=self.get_sous_cat)
for subCat in range(0,len(self.arrayCategories)):
yield Request(self.arrayCategories[subCat], callback=self.pagination)
这不是 "recursion",它是异步作业。您需要的是一个全局计数器(受锁保护),如果为 0,请完成:
from threading import Lock
class JobCounter(object):
def __init__(self, completion_callback, *args, **kwargs):
self.c = 0
self.l = Lock()
self.completion = (completion_callback, args, kwargs)
def __iadd__(self, n):
b = false
with self.l:
self.c += n
if self.c <= 0:
b = true
if b:
f, args, kwargs = self.completion
f(*args, **kwargs)
def __isub__(self, n):
self.__iadd__(-n)
每次启动作业时,请执行 counter += 1
每次作业完成时,执行 counter -= 1
注意:这会在最后一个调用作业的线程中完成。如果您想在特定线程中执行此操作,请使用条件而不是锁,并执行 notify()
而不是调用。
干得好,这是个好问题!两件小事:
a) 使用集合而不是数组。这样你就不会重复 b) 站点结构将更改一次month/year。您可能会更频繁地爬行。把蜘蛛一分为二; 1. 创建类别 url 列表并每月运行的那个和 2. 获得 start_urls 第一个
生成的文件的那个现在,如果您真的想按照现在的方式进行操作,请勾选 spider_idle 信号(参见此处:Scrapy: How to manually insert a request from a spider_idle event callback?)。当没有进一步的 url 可执行并允许您注入更多时,将调用此方法。在那个时候设置一个标志或重置您的列表,以便蜘蛛第二次空闲时(在它抓取所有内容之后),它不会永远重新注入相同的类别 url。
如果在您的情况下,您不想对网址做一些花哨的处理,而只是在其他网址之前抓取类别,这就是请求优先级 属性 的用途(http://doc.scrapy.org/en/latest/topics/request-response.html#topics-request-response-ref-request-subclasses).只需将其设置为例如1 用于您的类别 URL,然后它将在处理任何非类别链接之前跟踪这些链接。这样效率更高,因为它不会像您当前的实现那样加载这些类别页面两次。