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
元素的信息,并返回一个选择器列表,这些选择器含有xpath
和data
参数,允许进一步操作。可以获取其文本数据,getall()
会遍历选择器列表返回一个内容列表:
>>> response.css('title::text').getall()
['Quotes to Scrape']
这里需要注意::text
和getall()
。
-
::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选择器
,学习了获取数据的方法。