建立一个Scrapy项目,并将其命名为“demo”css
scrapy startproject demo cd demo
稍等片刻后,Scrapy为咱们生成了一个目录结构:html
其中,咱们目前须要重点关注三个文件:python
项目已经建立完成了,为了指导接下来的开发,咱们必须明确Scrapy爬虫的四个步骤:web
因此,接下来咱们须要明确目标。json
以个人博客网站为例,爬取文章的关键信息(标题、摘要、上传时间、阅读数量)并发
打开 demo 目录下的 items.py。dom
Item 定义结构化数据字段,用来保存爬取到的数据,有点像 Python 中的 dict,可是提供了一些额外的保护来减小错误。scrapy
能够经过建立一个 scrapy.Item 类, 而且定义类型为 scrapy.Field 的类属性来定义一个 Item(能够理解成相似于 ORM 的映射关系)。ide
正以下面这样:post
import scrapy class DemoItem(scrapy.Item): # define the fields for your item here like: postTitle = scrapy.Field() postDate = scrapy.Field() postDesc = scrapy.Field() postNumber = scrapy.Field()
Scrapy提供了相关命令来帮助咱们快速生成爬虫结构,执行下面语句,来生成名为basic的爬虫:
scrapy genspider basic web
它的结构以下:
import scrapy class BasicSpider(scrapy.Spider): name = 'basic' allowed_domains = ['web'] start_urls = ['website'] def parse(self, response): pass
它肯定了三个强制属性和方法:
咱们在前面已经讲解了XPath的基本使用,此处不在赘述。
这一过程,咱们须要观察网页源代码。首先每一页的博客是根据日期能够分为几大块,而后每一块内依次排列这每一篇文章的各项信息。
根据抽象出的结构,咱们取出数据要爬出的数据:
# -*- coding: utf-8 -*- import scrapy import re from demo.items import DemoItem class BasicSpider(scrapy.Spider): name = 'basic' allowed_domains = ['www.cnblogs.com'] start_urls = ['https://www.cnblogs.com/MrSaver/default.html?page=2'] def parse(self, response): posts = response.xpath('//div[@class="day"]') # result = [] for each_day_post in posts: day_postTitles = each_day_post.xpath('./div[@class="postTitle"]/a[@class="postTitle2"]/text()').extract(); day_postDesc = each_day_post.xpath('./div[@class="postDesc"]/text()').extract(); if (len(day_postTitles) == 1): tmp = DemoItem() tmp['postTitle'] = ''.join(day_postTitles) tmp['postDesc'] = ''.join(day_postDesc) tmp['postNumber'] = getNumber(tmp['postDesc']) yield tmp else: for i in range(len(day_postTitles)): tmp = DemoItem() tmp['postTitle'] = day_postTitles[i] tmp['postDesc'] = day_postDesc[i] tmp['postNumber'] = getNumber(tmp['postDesc']) yield tmp #提取出分页器中所涉及的全部链接喂给爬虫 next_url2 = response.xpath('//div[@id="homepage_top_pager"]/div/a/@href').extract() if next_url2 is not None: for n_url in next_url2: yield response.follow(n_url,callback=self.parse)#scrapy.Request(next_url2, callback=self.parse) def getNumber(txt): pattern = re.compile(r'阅读\((\d+)\)'); m = pattern.search(txt) return m.group(1)
scrapy保存信息的最简单的方法主要有四种,-o 输出指定格式的文件,命令以下:
scrapy crawl basic -o items.json
json lines格式,默认为Unicode编码
scrapy crawl basic -o items.jsonl
csv 逗号表达式,可用Excel打开
scrapy crawl basic -o items.csv
xml格式
scrapy crawl basic -o items.xml
修改输出编码,在settings.py文件中,添加行
FEED_EXPORT_ENCODING = 'gbk'
一个典型的爬虫会向两个方向移动
在水平爬取过程当中,咱们须要取到下一页的地址,一个简单的Demo以下:
next_url = response.xpath('//div[@id="nav_next_page"]/a/@href').extract_first() if next_url is not None: print(next_url) next_url = response.urljoin(next_url) yield scrapy.Request(next_url, callback=self.parse)
在提取数据以后,parse()方法查找到下一页的连接,使用urljoin()方法构建完整的绝对URL(由于连接能够是相对的)并向下一页生成新请求,将自身注册为回调以处理下一页的数据提取并保持爬网遍历全部页面。
它建立了一种循环,跟随到下一页的全部连接,直到它找不到 ,可用于爬行博客,论坛和其余具备分页的网站。
做为建立Request对象的快捷方式,您可使用response.follow:
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.Request不一样,response.follow直接支持相对URL - 无需调用urljoin。请注意,response.follow只返回一个Request实例,你仍然须要yield这个实例。