拼凑的回调函数可以指向产生请求的同一函数吗

时间:2019-02-16 10:56:16

标签: python scrapy

我正在使用Scrapy爬网。

我有类似的代码:

class mySpider(scrapy.Spider):
    def start_requests(self):
        yield SplashRequest(url=example_url,  
                                callback=self.parse,
                                cookies={'store_language':'en'},
                                endpoint='render.html',
                                args={'wait': 5}, 
                            )  

    def parse(self, response):
        try:
            self.extract_data_from_page(response)

            if (next_link_still_on_page(response):
                next_url = grok_next_url(response)

                yield SplashRequest(url=next_url, 
                                callback=self.parse,
                                cookies={'store_language':'en'},
                                endpoint='render.html',
                                args={'wait': 5}, 
                            )  

        except Exception:
            pass


    def extract_data_from_page(self, response):
        pass


    def next_link_still_on_page(self,response):
        pass


    def grok_next_url(self, response):
        pass

parse()方法中,回调函数parse()会被忽略(例如,导致潜在的堆栈溢出的逻辑错误?)。

1 个答案:

答案 0 :(得分:0)

可以使用相同的回调。从技术角度来看,这不是问题。尤其是如果产生的请求与当前请求具有相同的性质,那么理想情况下它应该重用相同的逻辑。

但是,从必须阅读源代码的人的角度来看,最好为不同任务或页面使用单独的解析器类型(整体单一责任原则)。


让我举例说明。假设您有一个列表网站(工作,产品或其他),并且有两个主要的URL类:

  • 搜索结果页面:.../search?q=something&page=2
  • 项目页面:.../item/abc

搜索结果页面包含分页链接项目。这样的页面会产生两种请求:

  1. 解析下一页
  2. 解析项目

“项目”页面将不会产生其他请求。

因此,现在您 可以将所有这些填充到同一解析器中,并用于每个请求:

def parse(self, response):
    if 'search' in response.url:
        for item in response.css('.item'):
            # ...
            yield Request(item_url, callback=self.parse)

        # ...
        yield Request(next_url, callback=self.parse)

    if 'item' in response.url:
        yield {
            'title': response.css('...'),
            # ...
        }

这显然是一个非常简洁的例子,但是随着它的增长,它将变得更加难以遵循。

相反,请分解不同的页面解析器:

def parse_search(self, response):
    for item in response.css('.items'):
        yield Request(item_url, callback=self.parse_item)

    next_url = response.css('...').get()
    yield Request(next_url, callback=self.parse_search)


def parse_item(self, response):
    yield {
        'title': response.css('...'),
        # ...
    }

因此,基本上,如果是“另一种相同类型的页面”的问题,那么使用相同的回调以便重用相同的逻辑是正常的。如果下一个请求需要另一种类型的解析,请创建一个单独的解析器。