使用Scrapy爬取多个域名不交叉

2 投票
2 回答
1550 浏览
提问于 2025-04-18 10:26

我设置了一个爬虫,专门收集所有的外部链接(只从 start_urls 开始,爬取一定深度,比如 DEPTH_LIMIT = 2)。

class LinkNetworkSpider(CrawlSpider):

    name = "network"
    allowed_domains = ["exampleA.com"]

    start_urls = ["http://www.exampleA.com"]

    rules = (Rule(SgmlLinkExtractor(allow=()), callback='parse_item', follow=True),)

    def parse_start_url(self, response):
        return self.parse_item(response)

    def parse_item(self, response):

        hxs = HtmlXPathSelector(response)
        links = hxs.select('//a/@href').extract()

        outgoing_links = []

        for link in links:
            if ("http://" in link):
                base_url = urlparse(link).hostname
                base_url = base_url.split(':')[0]  # drop ports
                base_url = '.'.join(base_url.split('.')[-2:])  # remove subdomains
                url_hit = sum(1 for i in self.allowed_domains if base_url not in i)
                if url_hit != 0:
                    outgoing_links.append(link)

        if outgoing_links:
            item = LinkNetworkItem()
            item['internal_site'] = response.url
            item['out_links'] = outgoing_links
            return [item]
        else:
            return None

我想把这个功能扩展到多个域名(比如 exampleA.com、exampleB.com、exampleC.com 等等)。一开始,我以为只需要把我的域名列表添加到 start_urlsallowed_domains 中就可以了,但我觉得这样会出现以下问题:

  • 设置的 DEPTH_LIMIT 会对每个 start_urls/allowed_domain 都生效吗?
  • 更重要的是:如果这些网站之间有连接,爬虫会不会因为两个域名都在 allowed_domains 中而从 exampleA.com 跳到 exampleB.com?我需要避免这种交叉,因为我之后想统计每个网站的外部链接,以了解网站之间的关系!

那么,我该如何扩展更多的爬虫,而不遇到 交叉 的问题,并且能为每个网站使用不同的设置呢?

附加的图片展示了我想实现的效果: scrapy

2 个回答

1

你可能需要保持一个数据结构(比如说哈希表),用来记录爬虫已经访问过的链接。然后,只要在访问链接时把它们添加到哈希表里,如果链接已经在哈希表中,就不要再访问了(因为这意味着你已经去过这个链接了)。当然,还有一些更复杂的方法可以做到这一点,它们可能会让你的程序运行得更快,但实现起来也会更困难。

3

我现在已经不需要规则就能实现这个功能了。我给每个 start_url 加上了一个 meta 属性,然后自己检查这些链接是否属于原始域名,并相应地发送新的请求。

因此,我重写了 start_requests

def start_requests(self):
    return [Request(url, meta={'domain': domain}, callback=self.parse_item) for url, domain in zip(self.start_urls, self.start_domains)]

在后续的解析方法中,我们获取 meta 属性 domain = response.request.meta['domain'],然后把这个域名和提取出来的链接进行比较,自己发送新的请求。

撰写回答