如何阻止scrapy对重复记录的页面进行分页?

xtupzzrd  于 2022-11-09  发布在  其他
关注(0)|答案(1)|浏览(127)

我试着抓取一个用scrapy分页的网站,结果还不错!但是,随着这个网站的更新和新帖子的加入,我每天都需要运行我的代码,所以每次我运行代码,它都会抓取所有的页面。幸运的是,我使用的是django,在我的django模型中,我使用了
唯一=真
因此,在我的数据库中没有重复的记录,但我想在分页爬行发现重复记录时立即停止它。我应该如何做到这一点?下面是我的蜘蛛代码片段:

class NewsSpider(scrapy.Spider):
    name = 'news'
    allowed_domains = ['....']
    start_urls = ['....']
    duplicate_record_flag = False

    def parse(self, response,**kwargs):
        next_page = response.xpath('//a[@class="next page-numbers"]/@href').get()

        news_links = response.xpath('//div[@class="content-column"]/div/article/div/div[1]/a/@href').getall()

        for link in news_links:
            if self.duplicate_record_flag:
                print("Closing Spider ...")
                raise CloseSpider('Duplicate records found')
            yield scrapy.Request(url=link, callback=self.parse_item)

        if next_page and not self.duplicate_record_flag:
            yield scrapy.Request(url=next_page, callback=self.parse)

    def parse_item(self, response):
        item = CryptocurrencyNewsItem()
        ...
        try:
            CryptocurrencyNews.objects.get(title=item['title'])
            self.duplicate_record_flag = True           
            return
        except CryptocurrencyNews.DoesNotExist:         
            item.save()
            return item

我使用了一个类变量(duplicate_record_flag)来在所有函数中访问它,并且在遇到重复记录时也知道这一点。问题是,当发现第一个重复记录时,蜘蛛不会真实的停止!在解析函数的for迭代中,如果我们有10个news_links,并且在第一次迭代中我们发现了一个重复记录,那么我们的标志在那一刻不会改变,如果我们在for循环中打印该标志,它将为每次迭代打印10个“False”值!!!而在第一次迭代中它应该被更改为“True”!
换句话说,爬虫会在每次解析时抓取每个页面中的所有链接!2我该如何防止这种情况?

myzjeezk

myzjeezk1#

如果您想在满足特定条件后停止蜘蛛,您可以引发CloseSpider

if some_logic_to_check_duplicates:
        raise CloseSpider('Duplicate records found') 
        # This message shows up in the logs

如果您只想跳过重复的项,可以从管道中引发DropItem异常。Scrapy docs中的示例代码:

class DuplicatesPipeline:

    def __init__(self):
        self.ids_seen = set()

    def process_item(self, item, spider):
        adapter = ItemAdapter(item)
        if adapter['id'] in self.ids_seen:
            raise DropItem(f"Duplicate item found: {item!r}")
        else:
            self.ids_seen.add(adapter['id'])
            return item

相关问题