Scrapy Tutorial 翻译1
2018-02-28 18:41
260 查看
以防睡着,开始翻译吧!
What just happened under the hood?
让我们看看背后究竟是如何处理的?
Scrapy通过调用Spider的start_requests方法,来安排scrapy.Request对象。对每一个请求,一旦获取返回信息,将通过调用callback所指定的parse方式来实例化返回结果并作为参数保存。
start_requests方法的快速实现方式:
直接使用start_urls类属性来定义url list即可。
上面代码并未对parse方法显示调用,但parse()仍会被执行,作为Scrapyd的默认回调函数。
提取数据:
最好的办法是使用Scrapy shell,来查看一些基本Scrapy selectors object。
备注:在命令行中运行scrapy shell时,url需要使用引号;windows下需要使用双引号。
执行后你将会看到:
此时,切换到了scrapy shell状态,可使用response对象的css方法来选择各种元素。
它的效果与使用Selector的SelectorList对象分析XML/HTML达到同样的效果;我们还可以进一步得到更精确的结果。如提取上面Selector对象中的title字段
现在请注意两点:
1. 添加::text到CSS查询内容中,表示了仅仅选择title元素的文本属性,不包含其tag;
2. 调用.extract()后返回的是一个List(这个list是SelectorList的一个实例),如果仅仅想得到第一个结果,则需要调用:
或写为:
建议最好使用extract_first(),在未查找到任何匹配内容时返回None,而不是IndexError;这样可以防止找不到数据时,程序停止执行。
除了extract()和extract_first()方法,也可使用re()方法及正则表达式,来提取数据。
为了找到最合适的CSS selectors,及css()中的内容,有时候需要在浏览器中view(response)查看源码。不同的浏览器,scraping的方式会不同。
Selector Gadget是一个好的可视化的工具,可以工作在不同的浏览器上,帮你快速找到CSS selectors。
XPath简要说明
除了css,Scrapy selectors也支持xPath表达式:
xPath表达式非常强大,是Scrapy selectors的基础。实际上,在后台,CSS会被转换为XPath selectors。如果你仔细阅读shell中的内容,你会看到。
虽然XPath没有CSS流行,但其实功能更强大,使用XPath,你可以处理类似“next page”等这样的链接,从而使Scrapy更加容易,强烈推荐使用XPath。
提取名言和作者
可以看到,http://quotes.toscrape.com HTML文件的内容大概如下:
打开scrapy shell:
使用quote selectors返回quote 要素列表:
我们先分析第一个quote selector,将第一个selector付给一个变量
使用quote对象提取title,author,tags等内容:
因为有很多的tag字符串,可使用.extract()方法状态tag列表。
对其它的quote selectors进行迭代,并将所有结果放回一个字典结构中。
使用spider提取数据
返回我们的spider代码,到目前为止,spider未做任何提取数据的操作,仅仅保存了HTML页面到本地。让我们将上述提取逻辑集中到spider的代码中。
Scrapy spider通常会返回大量数据,我们使用python的yield来迭代。
运行上述代码,在日志中可以看到:
存储爬取的数据
最简单的方式是利用Feed exports:
将生成一个quotes.json文件,包含所有爬取的数据,用JSON格式。
由于历史原因,对于给定文件,Scrapy会直接在后面添加内容,而不是重新写入。所以执行两遍,会损害其结构。
也可以存储为JSON Lines格式。
由于JSON Lines类似于stream,添加数据时,不会影响到其结构,要由于JSON。并且,每一条记录都会是单独的一行,处理大文件时,不需要一次昂将所有内容添加到内存中。可借助工具JQ来操作。
如果数据量较小,使用上述方式即可。但当需要处理大量复杂数据时,最好使用Item Pipeline。在创建工程中,该文件就已经被创建,你可以在工程目录下找到它。如果仅仅只是为了保存数据,我们可以不管它。
更多的链接
目前为止,我们只是从http://quotes.toscrape.com中爬取了两页的内容,让我们看看如何爬取更多链接下的更多内容。
首先,获取我们想要的链接。如HTML文件中,下页的表现方式为:
使用shell,可得到
获取href属性的内容:
将上述内容集成到spider的代码中:
可以看到,在Parser方法中,在获取数据后,因为这些链接地址都是相对的,可直接调用urljoin来创建完整的url地址,并对每个地址使用yeild来进行request迭代,并爬取每个页面的数据。
以上为Scrapy爬取的基本原理。
基于此,可以通过自定义规则来创建更复杂的爬虫,访问不同的内容,获取不同的数据。
import scrapy class QuotesSpider(scrapy.Spider): name = "quotes" def start_requests(self): urls = [ 'http://quotes.toscrape.com/page/1/', 'http://quotes.toscrape.com/page/2/', ] for url in urls: yield scrapy.Request(url=url, callback=self.parse) def parse(self, response): page = response.url.split("/")[-2] filename = 'quotes-%s.html' % page with open(filename, 'wb') as f: f.write(response.body) self.log('Saved file %s' % filename)
What just happened under the hood?
让我们看看背后究竟是如何处理的?
Scrapy通过调用Spider的start_requests方法,来安排scrapy.Request对象。对每一个请求,一旦获取返回信息,将通过调用callback所指定的parse方式来实例化返回结果并作为参数保存。
start_requests方法的快速实现方式:
直接使用start_urls类属性来定义url list即可。
import scrapy class QuotesSpider(scrapy.Spider): name = "quotes" start_urls = [ 'http://quotes.toscrape.com/page/1/', 'http://quotes.toscrape.com/page/2/', ] def parse(self, response): page = response.url.split("/")[-2] filename = 'quotes-%s.html' % page with open(filename, 'wb') as f: f.write(response.body)
上面代码并未对parse方法显示调用,但parse()仍会被执行,作为Scrapyd的默认回调函数。
提取数据:
最好的办法是使用Scrapy shell,来查看一些基本Scrapy selectors object。
scrapy shell 'http://quotes.toscrape.com/page/1/'
备注:在命令行中运行scrapy shell时,url需要使用引号;windows下需要使用双引号。
执行后你将会看到:
[ ... Scrapy log here ... ] 2016-09-19 12:09:27 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://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 0x7fa91d888c90> [s] item {} [s] request <GET http://quotes.toscrape.com/page/1/> [s] response <200 http://quotes.toscrape.com/page/1/> [s] settings <scrapy.settings.Settings object at 0x7fa91d888c10> [s] spider <DefaultSpider 'default' at 0x7fa91c8af990> [s] Useful shortcuts: [s] shelp() Shell help (print this help) [s] fetch(req_or_url) Fetch request (or URL) and update local objects [s] view(response) View response in a browser >>>
此时,切换到了scrapy shell状态,可使用response对象的css方法来选择各种元素。
>>> response.css('title') [<Selector xpath='descendant-or-self::title' data='<title>Quotes to Scrape</title>'>]
它的效果与使用Selector的SelectorList对象分析XML/HTML达到同样的效果;我们还可以进一步得到更精确的结果。如提取上面Selector对象中的title字段
>>> response.css('title::text').extract() ['Quotes to Scrape']
现在请注意两点:
1. 添加::text到CSS查询内容中,表示了仅仅选择title元素的文本属性,不包含其tag;
>>> response.css('title').extract() ['<title>Quotes to Scrape</title>']
2. 调用.extract()后返回的是一个List(这个list是SelectorList的一个实例),如果仅仅想得到第一个结果,则需要调用:
>>> response.css('title::text').extract_first() 'Quotes to Scrape'
或写为:
>>> response.css('title::text')[0].extract() 'Quotes to Scrape'
建议最好使用extract_first(),在未查找到任何匹配内容时返回None,而不是IndexError;这样可以防止找不到数据时,程序停止执行。
除了extract()和extract_first()方法,也可使用re()方法及正则表达式,来提取数据。
>>> 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']
为了找到最合适的CSS selectors,及css()中的内容,有时候需要在浏览器中view(response)查看源码。不同的浏览器,scraping的方式会不同。
Selector Gadget是一个好的可视化的工具,可以工作在不同的浏览器上,帮你快速找到CSS selectors。
XPath简要说明
除了css,Scrapy selectors也支持xPath表达式:
>>> response.xpath('//title') [<Selector xpath='//title' data='<title>Quotes to Scrape</title>'>] >>> response.xpath('//title/text()').extract_first() 'Quotes to Scrape'
xPath表达式非常强大,是Scrapy selectors的基础。实际上,在后台,CSS会被转换为XPath selectors。如果你仔细阅读shell中的内容,你会看到。
虽然XPath没有CSS流行,但其实功能更强大,使用XPath,你可以处理类似“next page”等这样的链接,从而使Scrapy更加容易,强烈推荐使用XPath。
提取名言和作者
可以看到,http://quotes.toscrape.com HTML文件的内容大概如下:
<div class="quote"> <span class="text">“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”</span> <span> by <small class="author">Albert Einstein</small> <a href="/author/Albert-Einstein">(about)</a> </span> <div class="tags"> Tags: <a class="tag" href="/tag/change/page/1/">change</a> <a class="tag" href="/tag/deep-thoughts/page/1/">deep-thoughts</a> <a class="tag" href="/tag/thinking/page/1/">thinking</a> <a class="tag" href="/tag/world/page/1/">world</a> </div> </div>
打开scrapy shell:
$ scrapy shell 'http://quotes.toscrape.com'
使用quote selectors返回quote 要素列表:
>>> response.css("div.quote")
我们先分析第一个quote selector,将第一个selector付给一个变量
quote = response.css("div.quote")[0]
使用quote对象提取title,author,tags等内容:
>>> title = quote.css("span.text::text").extract_first() >>> title '“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”' >>> author = quote.css("small.author::text").extract_first() >>> author 'Albert Einstein'
因为有很多的tag字符串,可使用.extract()方法状态tag列表。
>>> tags = quote.css("div.tags a.tag::text").extract() >>> tags ['change', 'deep-thoughts', 'thinking', 'world']
对其它的quote selectors进行迭代,并将所有结果放回一个字典结构中。
>>> for quote in response.css("div.quote"): ... text = quote.css("span.text::text").extract_first() ... author = quote.css("small.author::text").extract_first() ... tags = quote.css("div.tags a.tag::text").extract() ... print(dict(text=text, author=author, tags=tags)) {'tags': ['change', 'deep-thoughts', 'thinking', 'world'], 'author': 'Albert Einstein', 'text': '“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”'} {'tags': ['abilities', 'choices'], 'author': 'J.K. Rowling', 'text': '“It is our choices, Harry, that show what we truly are, far more than our abilities.”'} ... a few more of these, omitted for brevity >>>
使用spider提取数据
返回我们的spider代码,到目前为止,spider未做任何提取数据的操作,仅仅保存了HTML页面到本地。让我们将上述提取逻辑集中到spider的代码中。
Scrapy spider通常会返回大量数据,我们使用python的yield来迭代。
import scrapy class QuotesSpider(scrapy.Spider): name = "quotes" start_urls = [ 'http://quotes.toscrape.com/page/1/', 'http://quotes.toscrape.com/page/2/', ] def parse(self, response): for quote in response.css('div.quote'): yield { 'text': quote.css('span.text::text').extract_first(), 'author': quote.css('small.author::text').extract_first(), 'tags': quote.css('div.tags a.tag::text').extract(), }
运行上述代码,在日志中可以看到:
2016-09-19 18:57:19 [scrapy.core.scraper] DEBUG: Scraped from <200 http://quotes.toscrape.com/page/1/> {'tags': ['life', 'love'], 'author': 'André Gide', 'text': '“It is better to be hated for what you are than to be loved for what you are not.”'} 2016-09-19 18:57:19 [scrapy.core.scraper] DEBUG: Scraped from <200 http://quotes.toscrape.com/page/1/> {'tags': ['edison', 'failure', 'inspirational', 'paraphrased'], 'author': 'Thomas A. Edison', 'text': "“I have not failed. I've just found 10,000 ways that won't work.”"}
存储爬取的数据
最简单的方式是利用Feed exports:
scrapy crawl quotes -o quotes.json
将生成一个quotes.json文件,包含所有爬取的数据,用JSON格式。
由于历史原因,对于给定文件,Scrapy会直接在后面添加内容,而不是重新写入。所以执行两遍,会损害其结构。
也可以存储为JSON Lines格式。
scrapy crawl quotes -o quotes.jl
由于JSON Lines类似于stream,添加数据时,不会影响到其结构,要由于JSON。并且,每一条记录都会是单独的一行,处理大文件时,不需要一次昂将所有内容添加到内存中。可借助工具JQ来操作。
如果数据量较小,使用上述方式即可。但当需要处理大量复杂数据时,最好使用Item Pipeline。在创建工程中,该文件就已经被创建,你可以在工程目录下找到它。如果仅仅只是为了保存数据,我们可以不管它。
更多的链接
目前为止,我们只是从http://quotes.toscrape.com中爬取了两页的内容,让我们看看如何爬取更多链接下的更多内容。
首先,获取我们想要的链接。如HTML文件中,下页的表现方式为:
<ul class="pager"> <li class="next"> <a href="/page/2/">Next <span aria-hidden="true">→</span></a> </li> </ul>
使用shell,可得到
>>> response.css('li.next a').extract_first() '<a href="/page/2/">Next <span aria-hidden="true">→</span></a>'
获取href属性的内容:
>>> response.css('li.next a::attr(href)').extract_first() '/page/2/'
将上述内容集成到spider的代码中:
import scrapy class QuotesSpider(scrapy.Spider): name = "quotes" start_urls = [ 'http://quotes.toscrape.com/page/1/', ] def parse(self, response): for quote in response.css('div.quote'): yield { 'text': quote.css('span.text::text').extract_first(), 'author': quote.css('small.author::text').extract_first(), 'tags': quote.css('div.tags a.tag::text').extract(), } next_page = response.css('li.next a::attr(href)').extract_first() if next_page is not None: next_page = response.urljoin(next_page) yield scrapy.Request(next_page, callback=self.parse)
可以看到,在Parser方法中,在获取数据后,因为这些链接地址都是相对的,可直接调用urljoin来创建完整的url地址,并对每个地址使用yeild来进行request迭代,并爬取每个页面的数据。
以上为Scrapy爬取的基本原理。
基于此,可以通过自定义规则来创建更复杂的爬虫,访问不同的内容,获取不同的数据。
相关文章推荐
- module._init_() takes at most 2 arguments (3 given) (scrapy tutorial w/ xpath)
- [翻译] python Tutorial 之一
- Tutorial #Facebook Relay文档翻译#
- 泛型二——原类型(Java tutorial SE7 翻译)
- Cheat Engine Tutorial v3--翻译Cheat Engine 6.1 tutorial(3)
- The Java EE 6 Tutorial 中文版 (翻译) 第32章 JPA简介 (一) 实体
- Mercury QuickTest Professional Tutorial [翻译] (一)
- A Tutorial on Clustering Algorithms - Clustering Algorithms【翻译】
- Axure RP Pro - 翻译 - 5.5 Tutorial教程 - AXURE 101 Article 1: Introduction介绍 - Introduction to Axure RP - Axure RP介绍
- Axure RP Pro - 翻译 - 5.5 Tutorial教程 - AXURE 202 Article 5: Rich Functionality复杂功能 - Variables - 变量
- [翻译]Hive Tutorial-wiki
- Gatling官网教程翻译之Advanced Tutorial
- Core Text Tutorial for iOS : Making a Magazine App 翻译
- db4o Tutorial 中文翻译(七)
- caffe教程翻译:Alex’s CIFAR-10 tutorial, Caffe style
- Axure RP Pro - 翻译 - 5.5 Tutorial教程 - AXURE 101 Article 2: Introduction介绍 - Annotated Wireframes带标注的线框
- Django1.7官方文档中的tutorial——翻译
- Axure RP Pro - 翻译 - 5.5 Tutorial教程 - AXURE 202 Article 4: Rich Functionality复杂功能 - OnFocus and OnLostFocus Events - OnFocus和OnLo
- scrapy - tutorial
- [翻译] python Tutorial 之二