抓取某些网址时无法停止我的脚本

时间:2019-04-22 09:19:13

标签: python python-3.x web-scraping scrapy

我已经创建了一个脚本,以解析start_urls中列出的不同站点的标题。该脚本可以完美地完成工作。

我现在想做的是,无论其中有多少个URL,在解析了两个URL之后,让我的脚本停止。

到目前为止,我已经尝试过:

import scrapy
from scrapy.crawler import CrawlerProcess

class TitleSpider(scrapy.Spider):
    name = "title_bot"
    start_urls = ["https://www.google.com/","https://www.yahoo.com/","https://www.bing.com/"]

    def parse(self, response):
        yield {'title':response.css('title::text').get()}

if __name__ == "__main__":
    c = CrawlerProcess({
        'USER_AGENT': 'Mozilla/5.0', 
    })
    c.crawl(TitleSpider)
    c.start()
  

当列出的两个网址被抓取时,如何停止脚本?

4 个答案:

答案 0 :(得分:1)

按照Gallaecio的建议,您可以添加一个计数器,但是这里的区别在于,您可以在if语句之后导出一个项目。这样,它将几乎总是最终导出2个项目。

import scrapy
from scrapy.crawler import CrawlerProcess
from scrapy.exceptions import CloseSpider


class TitleSpider(scrapy.Spider):
    name = "title_bot"
    start_urls = ["https://www.google.com/", "https://www.yahoo.com/", "https://www.bing.com/"]
    item_limit = 2

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.counter = 0

    def parse(self, response):
        self.counter += 1
        if self.counter > self.item_limit:
            raise CloseSpider

        yield {'title': response.css('title::text').get()}

为什么几乎总是?您可能会问。它与parse方法中的竞争条件有关。

想象一下,self.counter当前等于1,这意味着希望再导出一个项目。但是现在Scrapy同时接收到两个响应,并为它们两者调用parse方法。如果两个运行parse方法的线程将同时增加计数器,则它们两个都将具有等于self.counter的{​​{1}},因此都会引发3异常。

在这种情况下(这种情况不太可能发生,但仍然有可能发生),蜘蛛只会输出一项。

答案 1 :(得分:1)

目前,我看到了立即停止此脚本的唯一方法-使用<div class="media"> <video src="video.mov" autoplay loop muted></video>` </div> <div class="background"></div> <div class="contents"> <h1>Registration Page</h1> </div> <div class="slider"> <button class="slidercontact">Contact</button> <div class="slidercontent"> <a href="#">1</a> <a href="#">2</a> </div> </div>强制退出功能:

os._exit

我尝试过的另一件事。
但是我没有收到所需的结果(立即停止脚本,在import os import scrapy from scrapy.crawler import CrawlerProcess class TitleSpider(scrapy.Spider): name = "title_bot" start_urls = ["https://www.google.com/","https://www.yahoo.com/","https://www.bing.com/"] item_counter =0 def parse(self, response): yield {'title':response.css('title::text').get()} self.item_counter+=1 print(self.item_counter) if self.item_counter >=2: self.crawler.stats.close_spider(self,"2 items") os._exit(0) if __name__ == "__main__": c = CrawlerProcess({'USER_AGENT': 'Mozilla/5.0' }) c.crawl(TitleSpider) c.start() 中仅用 3个网址停止脚本中的2个已删除项目):

  1. start_urls实例转移到蜘蛛设置并调用 CrawlerProcess,(CrawlerProcess.stop)等。以及其他方法 来自reactor.stop方法。
  2. 使用parse扩展名docs source)并遵循以下CloseSpider定义:

    CrawlerProcess
  3. c = CrawlerProcess({ 'USER_AGENT': 'Mozilla/5.0', 'EXTENSIONS' : { 'scrapy.extensions.closespider.CloseSpider': 500, }, "CLOSESPIDER_ITEMCOUNT":2 }) 的设置减小为CONCURRENT_REQUESTS(使用1 raise CloseSpider方法中的条件)。
    当应用程序刮取2个项目并 到达带有parse的代码行-已经有第三个请求 在另一个线程中启动。
    如果使用常规停止方式 蜘蛛,应用程序将一直处于活动状态,直到之前处理过 请求并处理他们的响应,只有在此之后-它 关闭。

由于您的应用程序的start_urls中的URL数量相对较少,因此应用程序会在到达raise ClosesSpider之前很长时间开始处理所有URL。

答案 2 :(得分:0)

https://stackoverflow.com/a/38331733/939364之上进行构造,您可以在Spider的构造函数中定义一个计数器,并使用parse来增加它,并在CloseSpider达到2时提高它:

import scrapy
from scrapy.crawler import CrawlerProcess
from scrapy.exceptions import CloseSpider  # 1. Import CloseSpider

class TitleSpider(scrapy.Spider):
    name = "title_bot"
    start_urls = ["https://www.google.com/","https://www.yahoo.com/","https://www.bing.com/"]

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.counter = 0  # 2. Define a self.counter property

    def parse(self, response):
        yield {'title':response.css('title::text').get()}
        self.counter += 1  # 3. Increase the count on each parsed URL
        if self.counter >= 2:
            raise CloseSpider  # 4. Raise CloseSpider after 2 URLs are parsed

if __name__ == "__main__":
    c = CrawlerProcess({
        'USER_AGENT': 'Mozilla/5.0', 
    })
    c.crawl(TitleSpider)
    c.start()

我不确定100%会阻止第三个URL的解析,因为我认为CloseSpider会停止启动新请求,但会等待启动的请求结束。

如果要防止刮掉2个以上的项目,可以编辑parse以便在self.counter > 2时不产生项目。

答案 3 :(得分:-1)

枚举做好的工作。架构和

方面的一些变化
for cnt, url in enumerate(start_urls):
    if cnt > 1:
        break
    else:
        parse(url)