【问题标题】:Force scrapy to crawl link in order they appear强制scrapy抓取链接以使其出现
【发布时间】:2012-07-25 05:30:24
【问题描述】:

我正在用scrapy写一个蜘蛛来抓取一个网站,索引页面是一个链接列表,比如 www.link1.com、www.link2.com、www.link3.com 并且该站点确实经常更新,因此我的爬虫是每个小时运行的进程的一部分,但我只想爬取我尚未爬取的新链接。 我的问题是,scrapy 在深入时随机化了它处理每个链接的方式。 是否可以强制 sracpy 按顺序爬行?像 1 然后 2 然后 3,这样我就可以保存我抓取的最后一个链接,并且在再次启动该过程时只需将链接 1 与以前的链接 1 进行比较?

希望这是可以理解的,对不起我的英语不好,

请回复,

谢谢

编辑:

class SymantecSpider(CrawlSpider):

    name = 'symantecSpider'
    allowed_domains = ['symantec.com']
    start_urls = [
        'http://www.symantec.com/security_response/landing/vulnerabilities.jsp'
        ]
    rules = [Rule(SgmlLinkExtractor(restrict_xpaths=('//div[@class="mrgnMD"]/following-sibling::table')), callback='parse_item')]

    def parse_item(self, response):
        open("test.t", "ab").write(response.url + "\n")

【问题讨论】:

  • 你为什么不把你抓取的链接保存在某个地方,然后再检查它们以确保你不会两次抓取同一个网站?
  • 嗯,因为我抓取的链接列表很长,而且我的机器人要运行很长时间,所以我可能必须保存大量链接,然后比较保存的链接几个月后链接和新建可能需要很长时间
  • 事实上,页面上实际上有 1400 个链接,所以我想做的是第一次抓取它们,但是当我的蜘蛛在 1 小时后被召回时,只需检查是否有一个新的链接,如果有就抓取它
  • 您可能会做的一件事是每次抓取页面时,获取内容的哈希码(链接列表)。然后一个小时后,再次读取内容,得到另一个哈希码,如果哈希码相同,则根本不刮。您可以做的另一件事是将所有刮取的值保存在 SQLite 数据库中,并在每次刮取时查询该数据库。对于仅 1400 个链接,这将比您想象的要快。这样,您还可以将有用的数据保存在数据库中,例如数据被抓取的时间,这样您就可以每周重新抓取一个链接。
  • 非常感谢您的回答,我会尝试一下,只是为了确定,没有办法强制scrapy按照它们在页面上出现的顺序处理链接?如果我能做到这一点,这将为我节省很多时间!这是我的起始网址 =symantec.com/security_response/landing/vulnerabilities.jsp,我希望 scrapy 抓取漏洞下方的链接并按照它们出现的顺序处理它们,但似乎我的 callback_method 不想这样做 =)

标签: python scrapy


【解决方案1】:

试试这个例子。
构建一个列表并将所有链接附加到它。
然后将它们一一弹出以按顺序获取您的请求。

我建议做类似@Hassan 提及的事情,并将您的内容通过管道传输到数据库。

from scrapy.spider import BaseSpider
from scrapy.selector import HtmlXPathSelector
from scrapy.http import Request
from scrapy import log


class SymantecSpider(BaseSpider):
    name = 'symantecSpider'
    allowed_domains = ['symantec.com']
    allLinks = []
    base_url = "http://www.symantec.com"

    def start_requests(self):
        return [Request('http://www.symantec.com/security_response/landing/vulnerabilities.jsp', callback=self.parseMgr)]

    def parseMgr(self, response):
        # This grabs all the links and append them to allLinks=[]
        self.allLinks.append(HtmlXPathSelector(response).select("//table[@class='defaultTableStyle tableFontMD tableNoBorder']/tbody/tr/td[2]/a/@href").extract())
        return Request(self.base_url + self.allLinks[0].pop(0), callback=self.pageParser)

    # Cycle through the allLinks[] in order
    def pageParser(self, response):
        log.msg('response: %s' % response.url, level=log.INFO)
        return Request(self.base_url + self.allLinks[0].pop(0), callback=self.pageParser)

【讨论】:

  • 您不必为每个链接在parseMgr 中返回Request 吗?
  • 好主意(我明白了)! parseMgr 仅管理第一个链接,然后由 pageParser 管理其余链接。
  • 应该只在pageParser 中为列表中的最后一个链接添加一个条件if not empty list
【解决方案2】:

SgmlLinkExtractor 将按照它们在页面上出现的相同顺序提取链接。

from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor
links = SgmlLinkExtractor(
    restrict_xpaths='//div[@class="mrgnMD"]/following-sibling::table',
        ).extract_links(response)

您可以在 CrawlSpider 的 rules 中使用它们:

class ThreatSpider(CrawlSpider):
    name = 'threats'
    start_urls = [
        'http://www.symantec.com/security_response/landing/vulnerabilities.jsp',
    ]
    rules = (Rule(SgmlLinkExtractor(
                restrict_xpaths='//div[@class="mrgnMD"]/following-sibling::table')
            callback='parse_threats'))

【讨论】:

  • 您好,谢谢您的回答,我已经尝试了您的代码,但似乎 url 的顺序仍然错误,我错过了什么吗?这是我正在使用的代码:
  • 我将用代码编辑我的问题,不知道如何在评论中发布代码:X
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-23
  • 2017-09-09
相关资源
最近更新 更多