我使用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)
答案 0 :(得分:3)
干得好,这是一个很好的问题!两件小事:
a)使用集合而不是数组。这样你就不会有重复 b)场地结构将每月/每年更换一次。您可能会更频繁地抓取。把蜘蛛分成两个; 1.创建类别URL列表并按月运行的那个和2.以start_urls的形式获取由第一个生成的文件
现在,如果您真的想按照现在的方式进行操作,请挂钩spider_idle信号(请参阅此处:Scrapy: How to manually insert a request from a spider_idle event callback?)。当没有其他网址可以执行时,会调用此方法,并允许您注入更多内容。设置一个标志或重置你的列表,以便蜘蛛第二次空闲(在爬行所有东西之后),它不会重新注入相同的类别网址。
如果在您的情况下,您似乎不希望对网址进行一些奇特的处理,而只是在其他网址之前抓取类别,则这就是请求优先级属性(http://doc.scrapy.org/en/latest/topics/request-response.html#topics-request-response-ref-request-subclasses)。只需将其设置为例如1为您的类别URL,然后它将在处理任何非类别链接之前遵循这些链接。这样做效率更高,因为它不会像当前实现那样加载那些类别页面两次。
答案 1 :(得分:1)
这不是"递归"它是异步作业。你需要的是一个全局计数器(受一个锁保护),如果为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
注意:这会在最后一个调用作业的线程中完成。如果您想在特定线程中执行此操作,请使用Condition而不是Lock,并执行notify()
而不是调用。