2

免责声明这个问题很难直接回答,需要对scrapy和程序排序有很好的了解才能回答。我很难将问题缩小为更容易直接回答的问题。

AFAIK 无法从项目管道处理程序返回请求。我正在尝试解析论坛中某个类别的所有帖子。我遍历论坛的策略如下:

  1. 建立一个类别中所有页面的列表,并将它们发送给下载器进行检索。
  2. 检索每个页面中的所有主题并将它们发送到项目管道。
  3. 等待所有页面项目被处理(插入到关系数据库中),然后开始遍历每个主题。

我无法弄清楚如何对第 3 步进行排序。我正在使用以下两个对象(最后列出)来协助排序逻辑。category::process_page是用于遍历主题页面的请求处理程序。

在类别类中:

阶段 1 的结束表示已收到所有主题页面。第 2 阶段的结束意味着项目管道已经处理了所有主题的基础工作。

主题类,代表特定主题列表页面中的所有主题,阶段 1 的结束表示页面中的所有主题已发送到数据库。一旦页面中的每个主题都被添加到数据库中,页面就会从类别中删除 - 一旦所有页面都完成,爬虫应该继续下载所有主题。

那么,如何通过在项目管道中运行的逻辑阻止下载器,以便它可以等待类别阶段 2 结束?是否有一些机器可以解决这个问题?也许我可以从项目管道中重新启动下载器逻辑?

可能有很多方法可以做到这一点,但我是 Python 新手和 C++/C 系统程序员。

注意我最初的设计是在 3-4 种不同的蜘蛛中完成的。第一个检索论坛层次结构,第二个下载所有主题,第三个检索所有帖子,第四个标记需要更新的主题。但是,这个问题肯定有更自然的解决方案,我想将最后 3 只蜘蛛合二为一。

我会接受一个答案,即勺子提供逻辑以启动蜘蛛而不诉诸 bash(能够从 gui 驱动蜘蛛会很好),然后我可以构建一个驱动程序并坚持我的初始设计。

###############################################################################
class TopicPageItemBundle:
  def __init__(self,topic_page_url,category_item_bundle):
    self.url = topic_page_url
    self.topics = set()
    self.topics_phase1 = set()
    self.category_item_bundle = category_item_bundle

  def add_topic(self, topic_url):
    self.topics.add(topic_url)
    self.topics_phase1.add(topic_url)

  def topic_phase1_done(self, topic_url):
    self.topics.remove(topic_url)
    if len(self.topics_phase1) == 0:
      return true
    else:
      return false
###############################################################################
class CategoryItemBundle:
  def __init__(self,forum_id):
    self.topic_pages = {}
    self.topic_pages_phase1 = set()
    self.forum_id = forum_id

  def add_topic_page(self,topic_page_url):
    tpib = TopicPageItemBundle(topic_page_url,self)
    self.topic_pages[topic_page_url] = tpib 
    self.topic_pages_phase1.add(topic_page_url)
    self.topic_pages_phase2.add(topic_page_url)

  def process_page(self, response):
    return_items = []
    tp = TopicPage(response,self)
    pagenav = tp.nav()
    log.msg("received " + pagenav.make_nav_info(), log.INFO)

    page_bundle = self.topic_pages[response.url]

    posts = tp.extract_posts(self.forum_id)
    for post in posts:
      if post != None:
        page_bundle.add_topic(post["url"])
        post["page_topic_bundle"] = page_bundle
    return return_items

  # phase 1 represents finishing the retrieval of all topic pages in a forum
  def topic_page_phase1_done(self, topic_page_url):
    self.topic_pages_phase1.remove(topic_page_url)
    if len(self.topic_pages_phase1) == 0:
      return true
    else:
      return false

  def topic_page_phase2_done(self,topic_page_url)
    self.topic_pages_phase2.remove(topic_page_url)
    if len(self.topic_pages_phase2) == 0:
      return true
    else:
      return true
###############################################################################
4

2 回答 2

2

只有在获得所有主题的列表并将它们保存到数据库后才开始抓取每个主题,有什么原因吗?

因为我的scrapy流程通常是这样的:获取包含主题列表的页面;查找每个主题的链接,并为每个主题生成一个请求,并带有用于抓取主题的回调;找到指向列表下一页的链接并为相同的回调产生一个回调;等等。

AFAIK,如果您首先从回调中产生一个主题项目然后是一个请求,您的管道将立即使用产生的项目执行,因为在 scrapy 中,一切都是同步的,只有资源是使用扭曲的异步下载的。

于 2012-06-25T04:01:30.637 回答
0

解决该问题的一种方法是将项目管道中用于主题处理的代码合并到请求处理程序中。本质上消除了项目管道和下载器之间的鸿沟,这样你就只有一个阶段,这个阶段表示所有主题都已插入数据库,没有同步。

然而,这似乎有点不自然,因为你绕过了scrapy中的“事情应该完成的方式”。当您开始为帖子抓取主题时,您可以继续使用项目管道,因为这不需要同步。

于 2012-06-23T17:44:01.723 回答