【问题标题】:Scrapy do something before resumeScrapy 在恢复之前做一些事情
【发布时间】:2017-04-12 13:39:05
【问题描述】:

我正在使用 scrapy 抓取具有身份验证的网站。
我希望能够保存爬虫的状态并使用

scrapy crawl myspider -s JOBDIR=mydir

在我使用相同的命令恢复之后,我希望能够重新安排所有已保存的请求之前登录网站。

基本上,我想确保我的函数 login()after_login() 将在任何其他请求被安排和执行之前被调用。而且我不想使用 cookie,因为它们不允许我长时间暂停抓取。
我可以在start_requests() 中调用login(),但这仅在我第一次运行爬虫时有效。

class MyCrawlSpider(CrawlSpider):
    # ...

    START_URLS = ['someurl.com', 'someurl2.com']
    LOGIN_PAGE = u'https://login_page.php'

    def login(self):
        return Request(url=self.LOGIN_PAGE, callback=self.login_email,
                      dont_filter=True, priority=9999)    

    def login_form(self, response):
        return FormRequest.from_response(response,
                                          formdata={'Email': 'myemail',
                                                    'Passwd': 'mypasswd'},
                                          callback=self.after_login, 
                                          dont_filter=True,
                                          priority=9999)

    def after_login(self, response):
        if "authentication failed" in response.body:
            self.logger.error("Login failed")
            return
        else:
            print("Login Successful!!")
            self.is_logged_in = True
            for url in self.START_URLS:
                yield Request(url, callback=self.parse_artists_json, dont_filter=True)

底线:在重新安排以前的请求之前,当我使用-s JOBDIR=... 选项恢复抓取时,是否会始终调用任何回调?我会用它来调用login()方法。

【问题讨论】:

    标签: python web-scraping scrapy web-crawler


    【解决方案1】:

    您可以使用spider_opened 信号(more here

    此函数旨在为蜘蛛和其他初始化分配资源,因此它不希望您从那里产生 Request 对象。

    您可以通过一系列待处理请求来解决此问题。这是必需的,因为 scrapy 不允许您手动安排请求。

    然后,在蜘蛛恢复后,您可以将登录作为队列中的第一个请求进行排队:

    def spider_opened(self, spider):
        self.spider.requests.insert(0, self.spider.login())
    

    您还需要在您的蜘蛛中添加一个next_request 方法

    def next_request(self):
        if self.requests:
            yield self.requests.pop(0)
    

    然后通过将所有请求添加到requests 数组来排队,并调用next_request 添加每个方法的末尾:

    def after_login(self, response):
        if "authentication failed" in response.body:
            self.logger.error("Login failed")
            return
        else:
            print("Login Successful!!")
            self.is_logged_in = True
            if not self.requests:
                for url in self.START_URLS:
                    self.requests.append(Request(url, callback=self.parse_artists_json, dont_filter=True)
    
        yield self.next_request()
    

    【讨论】:

    • 谢谢,@VMRuiz,我有类似的解决方案。我检查了我还没有登录并且没有安排登录,然后我在我的解析方法中安排了登录请求。您的解决方案更干净,但它不能解决以下问题:在第一次调用 parse 方法的那一刻,调度程序已经有一个从文件恢复的请求队列。由于scrapy 是异步工作的,它会在发送登录之前发送几个请求。
    • 使用这个系统,只能同时调度一个请求。最坏的情况是调度程序将在尝试再次登录之前处理第一个挂起的请求。在这种情况下,您可以检查请求是否因为登录而失败并重新排队。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-10
    相关资源
    最近更新 更多