运行环境:
* Python 2.7.12
* Scrapy 1.2.2
* Mac OS X 10.10.3 Yosemite
继续爬取Scrapy 1.2.2文档提供的练习网址:
可以暂时不用考虑爬虫被封的情况,用于初级爬虫练习。
目标
爬取该网站所有页的名言(quote)、作者(author)以及标签(tag)。
增加内容
- response.urljoin():将相对网址拼接成绝对网址。
- scrapy.Request():发出请求。可以用参数(callback=),对返回的响应(response)进行解析。
步骤1:增加爬虫代码
继续使用极简爬虫中的代码,增加三行内容即可。但是更改了爬虫的名字(name),变成name = 'quotes_2_2'
,用以区分第一个爬虫。
next_page = response.css('li.next a::attr("href")').extract_first()
next_full_url = response.urljoin(next_page)
yield scrapy.Request(next_full_url, callback=self.parse)
完整代码如下:
import scrapy
class QuotesSpider(scrapy.Spider):
name = 'quotes_2_2'
start_urls = [
'http://quotes.toscrape.com',
]
allowed_domains = [
'toscrape.com',
]
def parse(self,response):
for quote in response.css('div.quote'):
yield{
'quote': 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()
next_full_url = response.urljoin(next_page)
yield scrapy.Request(next_full_url, callback=self.parse)
分析
首先,需要找到下一页的入口网址。使用Chrome或者firefox的firebug对网页进行分析,找到下一页的图标“next —>“的标签中,有下一页的网址。具体网页html片段如下:
<ul class="pager">
<li class="next">
<a href="/page/2/">Next <span aria-hidden="true">→</span></a>
</li>
</ul>
只需要通过Scrapy的CSS选择器定位到li.next a
位置即可,意思是类名是next的li标签,下面的a标签。
再把这个a标签中的网址提取出来。网址是其中href="/page/2/"
这一段,使用a::attr("href")
来提取。(注:如果是文本就是::attr(text)提取;如果是图片的src链接,就是::attr(src)来提取),然后赋值到next_page变量上。
next_page = response.css('li.next a::attr("href")').extract_first()
这里只能得到一个相对网址/page/2/。Scrapy并不能爬取相对网址,因此需要使用response.urljoin()来转化成相对网址。
next_full_url = response.urljoin(next_page)
最后,对这个下一页的网址,再发出一个请求,使用yield scrapy.Request(),但是在Request()的参数中,使用callback=self.parse,表示继续调用parse()函数进行解析,提取其中需要的内容
yield scrapy.Request(next_full_url, callback=self.parse)
步骤2:运行爬虫
使用运行命令scrapy crawl运行爬虫:
$ scrapy crawl quotes_2_2 -o results_2_2_01.json
最后可以得到100条名言。
改进
因为下一页可能并不存在,所以也可以加入一个判断语句,判断下一页存在的话才去爬取。
只需要在上面的代码增加一行判断语句的代码即可。
next_page = response.css('li.next a::attr("href")').extract_first()
if next_page is not None:
next_full_url = response.urljoin(next_page)
yield scrapy.Request(next_full_url, callback=self.parse)
如果“next_page”这个网址存在,才向服务器发请求。