【问题标题】:scrapy different spider for different type item为不同类型的项目刮擦不同的蜘蛛
【发布时间】:2016-03-23 16:08:25
【问题描述】:

我认为scrapy 的框架可能有点不灵活。而且我找不到适合我的问题的解决方案。

这是我现在面临的问题。

有一个网站,比如说,http://example.com/。我想从中删除一些信息。

它有许多是http://example.com/item/([0-9]+) 形式的网址,现在我拥有有效([0-9]+) 的列表,其中包含大约300 万 个索引ID ,完成整个网页的抓取工作似乎是一个简单的任务。

但是,这个任务的结构是这样的:

  • /item/的页面上有很多物品的数据。我想要这些信息,这很容易实现。
  • 有链接指向与项目相关的实体,例如链接路径为/owner/item owner,或链接路径为/collection/the collections the item belongs 等。我想要这些实体的所有独特信息,这很难实现。它们不应该是item 的嵌套项或被单蜘蛛报废,原因如下:
    • 单个 owner 拥有[1-n] 项。
    • 单个项有[1-n]owners
    • collection 相同。
  • 有链接指向与该项目相关的其他实体,例如链接路径为/comment/comment 或链接路径为/user/user。显然,明智的做法是将commentuser 信息与item 分开,并使用key 或index 来引用实体。这是单蜘蛛很难做到的。

所以,我更喜欢启动一个蜘蛛来处理http://example.com/item/([0-9]+)的列表,并使用其他类型的蜘蛛来分别处理item ownercollectioncommentuser

但是,问题是我没有item ownercollectioncommentuser 的列表。我只能通过迭代http://example.com/item/([0-9]+)的网页来遍历所有这些实体。

我搜索了很多,但没有找到适合我的问题的解决方案。请随时发表您的意见。

【问题讨论】:

    标签: python web web-crawler scrapy


    【解决方案1】:

    这是ItemSpider 的伪代码。

    from scrapy_redis.spiders import RedisSpider
    import redis
    class ItemSpider(RedisSpider):
        name = 'item'
        def parse(self, response):
            # process to get item info.
            r = redis.Redis(...)
            r.lpush('user:start_urls', user_link)
            return ...
    

    这是UserSpider 的伪代码。

    from scrapy_redis.spiders import RedisSpider
    class UserSpider(RedisSpider):
        name = 'user'
        def parse(self, response):
            # process to get user info.
            return ...
    

    然后将您的项目网址添加到 redis 中的item:start_urls 列表中。

    最后,

    scrapy crawl item
    scrapy crawl user
    

    应提前考虑更高级的概念,例如避免重复项目。至少上述解决方案已经将ItemSpiderUserSpider 的时间表分开了。

    由于here 的帮助,我进入了这个解决方案,感谢@lnxpgn。

    谁能提供更好的解决方案?或者提供更好的方案来避免重复爬取?

    【讨论】:

      【解决方案2】:

      您的大多数要求似乎都非常适合scrapy。您已经说过您可以简单地抓取项目列表,这是一个好的开始。我认为您是说每个项目都有指向所有者、评论、用户的链接。在这种情况下,您使用 response.xpath 获取 URL,然后以 yield Request(URL, callback=parse_owner) 为例。您将希望将不同的抓取数据链接在一起,在这种情况下,您可以将 meta={'id': identifier} 添加到 Request()。正如@kotrfa 所说,转储到数据库可能是最好的,因为这听起来像是存在一些数据交叉链接。

      根据您提供的信息,我只能做到这一点。更多信息将使我们更清楚地了解情况。

      【讨论】:

      • 感谢您的建议。我知道你描述的程序。我确实认为这基本上可以完成我的要求。如果有更好的解决方案,我会选择它。我期望更好的解决方案的原因是这种方法存在一些问题。 [1] 重复的页面爬取和数据库记录。(假设两个工作人员同时处理两个具有相同所有者的项目)。 [2] 工作计划(在您的解决方案中,owneruser 等的工作不会与item 分开,这可能涉及一些数据库锁,可以通过更好的模块化来避免)。无论如何,您的程序确实有效。
      • Scrapy默认只会访问一个页面一次,如果需要多次访问一个页面,它可以在本地缓存页面。在 settings.py 中,设置HTTPCACHE_ENABLED=True。如果你能给我们一些例子,你可能会得到更多的帮助。如果我的回答有帮助,请不要忘记接受/支持它;)
      • 感谢您的信息。我不熟悉这个细节。好的,我想我有更好的解决方案here。我已经大致快速地实现了它。比如只写ItemSpiderUserSpider,把redisscrapy-redis结合起来。在redis中将3M的url添加到ItemSpiderstart_urls中,当ItemSpider找到用户要抓取的链接时,将其url添加到UserSpider中的start_urls中雷迪斯。并在两个蜘蛛代码完成后,分别启动两个蜘蛛。然后就完成了。
      【解决方案3】:

      据我了解,您不是在寻找 multidomain 爬虫,因为您基本上是在报废一个域,对吗?您甚至不需要遵循许多不同且不可预测的链接,因为您已经知道要查找的内容。这是正确的吗?

      为此,我建议您使用selenium(可能与BeautifulSoup 一起使用)。 selenium 非常轻量级,可以使用 PhantomJS 无头运行,如果您知道要报废的页面的结构,那么与 Scrappy 相比,您可以放置​​更多的逻辑和控制(嗯,肯定更容易)。

      我没有看到最终数据的结构和类型,但它们似乎有些分层,并且它们之间存在关系。即使它们不是唯一的,我也会将数据存储在带有列表的 dict 中,然后将它们转储到例如MongoDB(使用 pymongo 超级简单,基本上 3 个命令来创建连接,然后一个命令将其放入数据库)。收集完这些后,我会关心关系、过滤和其他东西。稍后(使用用于此目的的工具,例如pandas)然后在报废期间通常要容易得多。

      对于您的特殊情况,我会在您希望废弃的范围 (3M) 上执行 for 循环,并且在每一步中,您将运行访问该 URL 的函数,如果不是 404,则为废弃信息,然后是废弃所有者,然后废品类...这些应该是单独的功能,选择器会根据结构而有所不同,尽可能使用适当的CSS或XPATH,否则可以使用find_elements然后根据文本或href过滤它们(例如@987654325 @ 在href 中的所有a)。

      【讨论】:

      • 感谢您的回复。但我宁愿不选择seleniumrequestsBeautifulSoup,因为可能还有一些我在帖子中没有提到的其他问题,例如performanceschedulermultiple proxies、@ 987654334@ 等等,因为这些问题与我发布的问题没有直接关系。但是使用手工脚本可能不是我想要的好选择。还是谢谢大家。
      猜你喜欢
      • 2018-02-11
      • 2012-01-12
      • 2013-10-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-18
      相关资源
      最近更新 更多