精通Scrapy网络爬虫
上QQ阅读APP看书,第一时间看更新

3.2 Response内置Selector

在实际开发中,几乎不需要手动创建Selector对象,在第一次访问一个Response对象的selector属性时,Response对象内部会以自身为参数自动创建Selector对象,并将该Selector对象缓存,以便下次使用。Scrapy源码中的相关实现如下:

        class TextResponse(Response):
          def __init__(self, *args, **kwargs):
              ...
              self._cached_selector = None
              ...

          @property
          def selector(self):
              from scrapy.selector import Selector
              if self._cached_selector is None:
                self._cached_selector = Selector(self)
              return self._cached_selector
          ...

通常,我们直接使用Response对象内置的Selector对象即可:

        >>> from scrapy.http import HtmlResponse
        >>> body = '''
        ... <html>
        ...    <body>
        ...        <h1>Hello World</h1>
        ...        <h1>Hello Scrapy</h1>
        ...        <b>Hello python</b>
        ...        <ul>
        ...           <li>C++</li>
        ...           <li>Java</li>
        ...           <li>Python</li>
        ...        </ul>
        ...    </body>
        ... </html>
        ... '''
        ...
        >>> response = HtmlResponse(url='http://www.example.com', body=body, encoding='utf8')
        >>> response.selector
        <Selector xpath=None data='<html>\n       <body>\n          <h1>He'>

为了方便用户使用,Response对象还提供了xpath和css方法,它们在内部分别调用内置Selector对象的xpath和css方法。Scrapy源码中的相关实现如下:

        class TextResponse(Response):
          ...
          def xpath(self, query, **kwargs):
              return self.selector.xpath(query, **kwargs)
          def css(self, query):
              return self.selector.css(query)
          ...

使用这两个快捷方式可使代码更加简洁:

        >>> response.xpath('.//h1/text()').extract()
        ['Hello World', 'Hello Scrapy']
        >>> response.css('li::text').extract()
        ['C++', 'Java', 'Python']