Scrapy提取数据

此节将会独立于刚新建的项目,学习Scrapy shell,掌握获取数据的基本方法

何为数据

在开发过程中,我们需要获取站点的信息,这些信息包括站点url、响应状态码、header、body……在Scrapy中,Response 相当于一个数据字典,包含着站点的大部分信息,在请求后将 Response 作为参数传给了 parse 回调函数。

获取数据

CSS 选择器

quotes-1.html 和 quotes-2.html 文件只是将站点页面保存了下来,实际开发并不会这样做,而是会在此基础上提取我们想要的数据。学习Scrapy最有效的方法其实是使用其提供的 Scrapy shell。通过使用shell,我们可以更好地理解Scrapy爬取数据的原理和机制,并且快速掌握提取数据的方法。还是使用https://quotes.toscrape.com做演示。

scrapy shell 'https://quotes.toscrape.com/page/1/'
2022-09-16 23:13:13 [scrapy.utils.log] INFO: Scrapy 2.6.2 started (bot: jd)
2022-09-16 23:13:13 [scrapy.utils.log] INFO: Versions: lxml 4.9.1.0, libxml2 2.9.12, cssselect 1.1.0, parsel 1.6.0, w3lib 2.0.1, Twisted 22.8.0, Python 3.9.12 (tags/v3.9.12:b28265d, Mar 23 2022, 23:52:46) [MSC v.1929 64 bit (AMD64)], pyOpenSSL 22.0.0 (OpenSSL 3.0.5 5 Jul 2022), cryptography 38.0.1, Platform Windows-10-10.0.25201-SP0
2022-09-16 23:13:13 [scrapy.crawler] INFO: Overridden settings:
{'BOT_NAME': 'jd',
 'DUPEFILTER_CLASS': 'scrapy.dupefilters.BaseDupeFilter',
 'LOGSTATS_INTERVAL': 0,
 'NEWSPIDER_MODULE': 'jd.spiders',
 'ROBOTSTXT_OBEY': True,
 'SPIDER_MODULES': ['jd.spiders']}
2022-09-16 23:13:13 [scrapy.utils.log] DEBUG: Using reactor: twisted.internet.selectreactor.SelectReactor
2022-09-16 23:13:13 [scrapy.extensions.telnet] INFO: Telnet Password: 5740caa42eea4fff
2022-09-16 23:13:13 [scrapy.middleware] INFO: Enabled extensions:
['scrapy.extensions.corestats.CoreStats',
 'scrapy.extensions.telnet.TelnetConsole']
2022-09-16 23:13:13 [scrapy.middleware] INFO: Enabled downloader middlewares:
['scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware',
 'scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware',
 'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware',
 'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware',
 'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware',
 'scrapy.downloadermiddlewares.retry.RetryMiddleware',
 'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware',
 'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware',
 'scrapy.downloadermiddlewares.redirect.RedirectMiddleware',
 'scrapy.downloadermiddlewares.cookies.CookiesMiddleware',
 'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware',
 'scrapy.downloadermiddlewares.stats.DownloaderStats']
2022-09-16 23:13:13 [scrapy.middleware] INFO: Enabled spider middlewares:
['scrapy.spidermiddlewares.httperror.HttpErrorMiddleware',
 'scrapy.spidermiddlewares.offsite.OffsiteMiddleware',
 'scrapy.spidermiddlewares.referer.RefererMiddleware',
 'scrapy.spidermiddlewares.urllength.UrlLengthMiddleware',
 'scrapy.spidermiddlewares.depth.DepthMiddleware']
2022-09-16 23:13:13 [scrapy.middleware] INFO: Enabled item pipelines:
[]
2022-09-16 23:13:13 [scrapy.extensions.telnet] INFO: Telnet console listening on 127.0.0.1:6023
2022-09-16 23:13:13 [scrapy.core.engine] INFO: Spider opened
2022-09-16 23:13:15 [scrapy.core.engine] DEBUG: Crawled (404) <GET https://quotes.toscrape.com/robots.txt> (referer: None)
2022-09-16 23:13:15 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://quotes.toscrape.com/page/1/> (referer: None)
[s] Available Scrapy objects:
[s]   scrapy     scrapy module (contains scrapy.Request, scrapy.Selector, etc)
[s]   crawler    <scrapy.crawler.Crawler object at 0x000001BEF5750490>
[s]   item       {}
[s]   request    <GET https://quotes.toscrape.com/page/1/>
[s]   response   <200 https://quotes.toscrape.com/page/1/>
[s]   settings   <scrapy.settings.Settings object at 0x000001BEF5750760>
[s]   spider     <DefaultSpider 'default' at 0x1bef5b711c0>
[s] Useful shortcuts:
[s]   fetch(url[, redirect=True]) Fetch URL and update local objects (by default, redirects are followed)
[s]   fetch(req)                  Fetch a scrapy.Request and update local objects
[s]   shelp()           Shell help (print this help)
[s]   view(response)    View response in a browser 
>>>

通过此命令其实已经完成了爬取的过程。并启动了shell模式,光标闪烁接收我们的输出,我们在response中获取到想要的数据,比如:

>>> response.css('title')
[<Selector xpath='descendant-or-self::title' data='<title>Quotes to Scrape</title>'>]

获取名为title元素的信息,并返回一个选择器列表,这些选择器含有xpathdata参数,允许进一步操作。可以获取其文本数据,getall()会遍历选择器列表返回一个内容列表:

>>> response.css('title::text').getall()
['Quotes to Scrape']

这里需要注意::textgetall()

  • ::text

    在 CSS 选择器中添加此查询条件,这就意味着我们想要获取title标签的文本元素,如果不添加此查询条件,将会返回整个标签元素。

    >>> response.css('title').getall()
    ['<title>Quotes to Scrape</title>']
    
  • getall()

    顾名思义,这个函数会遍历选择器列表并返回一个列表结果。如果只想要第一个结果,可以使用get()函数:

    >>> response.css('title::text').get()
    'Quotes to Scrape'
    

    除了getall()get()函数,还可以利用正则匹配获取数据。

    >>> response.css('title::text').re(r'Quotes.*')
    ['Quotes to Scrape']
    >>> response.css('title::text').re(r'Q\w+') 
    ['Quotes']
    >>> response.css('title::text').re(r'(\w+) to (\w+)') 
    ['Quotes', 'Scrape']
    

XPath 选择器

Scrapy还支持了 XPath 选择器来获取数据。

>>> response.xpath('//title')
[<Selector xpath='//title' data='<title>Quotes to Scrape</title>'>]
>>> response.xpath('//title/text()').get()
'Quotes to Scrape'

XPath 表达式十分强大,奠定了 Scrapy 选择器的基础。事实上,CSS 选择器在执行时 Scrapy会将其转换为 XPath 选择器。仔细看 CSS 选择器的返回值你就会发现这一点。

虽然 XPath 表达式可能没有 CSS 选择器那么流行,但它提供了更强大的功能,因为除了导航结构之外,它还可以查看内容。使用 XPath,可以选择以下内容:选择包含文本“下一页”的链接。这使得 XPath 非常适合于抓取任务,即使我们已经知道如何构造 CSS 选择器,XPath 也将使抓取更容易。

大展身手

介绍了两个利器,让我们回到爬虫。直到现在,shell 环境下并没有提取指定的数据,仅仅只是在保存的页面文件中获取数据。可以将这些逻辑代码集成到新建的爬虫文件中。

import scrapy


class QuotesSpider(scrapy.Spider):
    name = "quotes"
    start_urls = [
        'https://quotes.toscrape.com/page/1/',
        'https://quotes.toscrape.com/page/2/',
    ]

    def parse(self, response):
        for quote in response.css('div.quote'):
            yield {
                'text': quote.css('span.text::text').get(),
                'author': quote.css('small.author::text').get(),
                'tags': quote.css('div.tags a.tag::text').getall(),
            }

是不是很熟悉,这就是第一节中的代码逻辑,不再赘述。

页面跳转

在实际开发过程中,往往需要在爬虫中跳转页面。当然将网站链接写到start_urls列表中固然可以,但是对于大量的页面跳转,将每个链接都写入其中就会变得很麻烦,缺乏执行性。Scrapy中的 response 提供了 urljoin()follow()方法来应对这种问题。

  • urljoin()

    在 parse 中拼接 url,并再次发出递归请求:

    next_page = response.css('li.next a::attr(href)').get()
    if next_page is not None:
        next_page = response.urljoin(next_page)
        yield scrapy.Request(next_page, callback=self.parse)
    
  • follow()

    follow 是上面写法的简写形式,会完成 url 拼接和请求两个工作:

    next_page = response.css('li.next a::attr(href)').get()
    if next_page is not None:
        yield response.follow(next_page, callback=self.parse)
    

总结

熟悉了 Scrapy 的两种选择器:CSS选择器XPath选择器,学习了获取数据的方法。

posted @ 2022-09-17 14:59  Flipped1121  阅读(163)  评论(0编辑  收藏  举报