【问题标题】:How to call a function after finishing recursive asynchronous jobs in Python?在 Python 中完成递归异步作业后如何调用函数?
【发布时间】:2016-09-05 15:07:12
【问题描述】:

我使用 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)

【问题讨论】:

  • 你试过“这个”,结果如何?它与您的预期有何不同?
  • 完全,你的意思是什么时候刮完?从您的代码示例中看起来像这样。您可以尝试连接到 spider_close 信号,请参阅此处的文档doc.scrapy.org/en/latest/topics/signals.html#spider-closed。你能详细解释一下你在分页程序中做了什么吗?
  • 在这个链接[link]amazon.fr/s/…我们有一个17页的类别,我们有像Repas这样的子类别,我想做的是把这个页面的url +他的子类别的 url,例如 Repas 在一个数组中,并使用分页功能获得该类别的 17 页
  • @Steve 完全,我的意思是我们完成了获取所有类别的所有子类别的 url(一些子类别也有子类别)但是 Scrape 还没有完成
  • 我编辑了我的问题并添加了更多信息

标签: python-2.7 recursion web-scraping scrapy web-crawler


【解决方案1】:

干得好,这是个好问题!两件小事:

a) 使用集合而不是数组。这样你就不会有重复 b) 站点结构将每月/每年更改一次。您可能会更频繁地爬行。将蜘蛛一分为二; 1. 创建类别 url 列表并每月运行的那个和 2. 以 start_urls 获取第一个生成的文件的那个

现在,如果您真的想按照现在的方式进行操作,请挂钩 spider_idle 信号(参见此处:Scrapy: How to manually insert a request from a spider_idle event callback?)。当没有更多的 url 可做并允许您注入更多时,它会被调用。在此时设置一个标志或重置您的列表,以便蜘蛛第二次空闲时(在它抓取所有内容之后),它不会永远重新注入相同的类别网址。

如果在您的情况下,您不想对 url 进行一些花哨的处理,而只想在其他 URL 之前抓取类别,这就是请求优先级属性的用途 (http://doc.scrapy.org/en/latest/topics/request-response.html#topics-request-response-ref-request-subclasses)。只需将其设置为例如1 用于您的类别 URL,然后它会在处理任何非类别链接之前跟踪这些链接。这更有效,因为它不会像您当前的实现那样两次加载这些类别页面。

【讨论】:

  • 很好的答案,这是我现在对scrapy了解的两个新东西,谢谢。
【解决方案2】:

这不是“递归”,而是异步作业。您需要的是一个全局计数器(受锁保护),如果为 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() 而不是调用。

【讨论】:

  • 不确定你是否需要用 Scrapy 锁 :-) 它大部分是 Twisted/单线程的。
猜你喜欢
  • 1970-01-01
  • 2017-03-12
  • 2019-02-20
  • 1970-01-01
  • 1970-01-01
  • 2016-09-21
  • 2019-11-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多