建立一個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這個實例。