1. 程式人生 > >python之scrapy

python之scrapy

Scrapy框架的使用

一、 Scrapy框架的介紹

Scrapy是一個基於 Twisted 非同步處理的框架,是一個純python的網路爬蟲框架,是一個為了爬取網站資料,提取結構性資料而編寫的應用框架。 其可以應用在資料探勘,資訊處理或儲存歷史資料等一系列的程式中。其最初是為了頁面抓取 (更確切來說, 網路抓取 )所設計的, 也可以應用在獲取API所返回的資料或者通用的網路爬蟲。

Scrapy用途廣泛,可以用於資料探勘、監測和自動化測試。

1.1 框架介紹

Scrapy基於事件驅動網路框架 Twisted 編寫。因此,Scrapy基於併發性考慮由非阻塞(即非同步)的實現我們先看看Scrapy的框架的架構圖:

主要有以下元件:

  • Scrapy Engine引擎負責控制資料流在系統中所有元件中流動,並在相應動作發生時觸發事件。 詳細內容檢視下面的資料流(Data Flow)部分。

  • Scheduler排程器從引擎接受request並將他們入隊,以便之後引擎請求他們時提供給引擎。

  • Downloader下載器負責獲取頁面資料並提供給引擎,而後提供給spider。

  • SpidersSpider是Scrapy使用者編寫用於分析response並提取item(即獲取到的item)或額外跟進的URL的類。 每個spider負責處理一個特定(或一些)網站。

  • Item Pipeline

    Item Pipeline負責處理被spider提取出來的item。典型的處理有清理、 驗證及持久化(例如存取到資料庫中)。

  • Downloader middlewares下載器中介軟體是在引擎及下載器之間的特定鉤子,處理Downloader傳遞給引擎的response。 其提供了一個簡便的機制,通過插入自定義程式碼來擴充套件Scrapy功能

1.2 資料流

Scrapy中的資料流由執行引擎控制,其過程如下:

  1. 引擎開啟一個網站(open a domain),找到處理該網站的Spider並向該spider請求第一個要爬取的URL(s)。

  2. 引擎從Spider中獲取到第一個要爬取的URL並在排程器(Scheduler)以Request排程。

  3. 引擎向排程器請求下一個要爬取的URL。

  4. 排程器返回下一個要爬取的URL給引擎,引擎將URL通過下載中介軟體(請求(request)方向)轉發給下載器(Downloader)。

  5. 一旦頁面下載完畢,下載器生成一個該頁面的Response,並將其通過下載中介軟體(返回(response)方向)傳送給引擎。

  6. 引擎從下載器中接收到Response並通過Spider中介軟體(輸入方向)傳送給Spider處理。

  7. Spider處理Response並返回爬取到的Item及(跟進的)新的Request給引擎。

  8. 引擎將(Spider返回的)爬取到的Item給Item Pipeline,將(Spider返回的)Request給排程器。

  9. 重複第2到第8步,直到排程器(Scheduler)中沒有更多地request,引擎關閉該網站。

二、Scrapy的安裝

Scrapy是一個十分強大的爬蟲框架,依賴的庫比較多,至少需要依賴的庫有Twisted 14.0、lxml 3.4和pyOpenSSL 0.14。在不同的平臺環境下,它所依賴的庫也各不相同,所以在安裝之前,最好確保把一些基本庫安裝好

2.1 Windows環境

如果你的Python不是使用Anaconda安裝的,可以參考如下方式來一步步安裝Scrapy。

1、安裝wheel

pip install wheel

2、安裝lxml

3、安裝pyopenssl

4、安裝Twisted

5、安裝pywin32

6、安裝scrapy

pip install scrapy

2.2 Ubuntu環境

在Ubuntu平臺下,首先確保一些依賴庫已經安裝,執行如下命令:

sudo apt-get install build-essential python3-dev libssl-dev libffi-dev libxml2 libxml2-dev libxslt1-dev zlib1g-dev

然後利用pip安裝Scrapy即可:

pip3 install Scrapy

三、Scrapy入門

這節我們主要介紹一個簡單的專案,完整的看一遍專案流程。可以對Scrapy的基本用法和原理有大體瞭解。

在專案開始之前,需要保證已經安裝好了Scrapy框架、MongoDB和pymongo庫。

這裡我們主要來爬取官方文件

3.1 建立專案

可以切換到相對應的檔案路徑下面(也可以通過路徑來建立),通過命令來建立:

scrapy startproject tutorial

通過這個命令,會建立一個tutorial資料夾,資料夾內包含以下內容:

tutorial/

scrapy.cfg# Scrapy部署時的配置檔案

tutorial/# 專案的模組,需要從這裡引入

__init__.py

items.py# Items的定義,定義爬取的資料結構

middlewares.py# Middlewares的定義,定義爬取時的中介軟體

pipelines.py# Pipelines的定義,定義資料管道

settings.py# 配置檔案

spiders/# 放置Spiders的資料夾

__init__.py

3.2 建立Spider

Spider是一個自己定義的類,可以從一個網站(或者一組網站)上抓取資訊。不過自定義的這個類必須繼承Scrapy提供的scrapy.Spider,還要定義Spider的名稱和起始請求,以及怎麼獲得響應的方法。

cd tutorial

scrapy genspider quotes quotes.toscrape.com

通過scrapy genspider命令來執行,第一個引數為spider的名稱,第二個引數是網站域名。這樣在spiders檔案會多了一個quotes.py檔案,內容如下:

import scrapy

class QuotesSpider(scrapy.Spider):

name = 'quotes' #每個專案有唯一的名字,用來區分不同的spider

allowed_domains = ['quotes.toscrape.com'] #允許爬取的域名,如果請求不在該域名下,會被過濾

start_urls = ['http://quotes.toscrape.com/']#包含了Spider啟動時的url列表,初始請求由他定義

#parse()在預設情況下呼叫start_urls請求完成後返回的響應作為他的一個引數,主要負責解析和進一步請求

def parse(self, response):

pass

3.3 建立Item

Item時儲存資料的容器,使用方法類似於字典,不過有額外的保護。在item.py檔案中進行如下修改:

from scrapy import Item, Field

class QuoteItem(Item):

# define the fields for your item here like:

# name = scrapy.Field()

text = Field()

author = Field()

tags = Field()

這裡主要定義了三個欄位,在接下來的解析Response中會用到這三個欄位。

3.4 解析Response

parse()方法中,可以直接對response變數包含的內容進行解析。我們可以直接檢視原始碼:

同時,還需要考慮到翻頁問題:

我們可以通過css選擇器或者xpath選擇,對我們想要的資訊進行提取,parse()方法改寫如下:

def parse(self, response):

quotes = response.css('.quote')

for quote in quotes:

item = QuoteItem()

item['text'] =quote.css('.text::text').extract_first()

item['author'] = quote.css('.author::text').extract_first()

item['tags'] = quote.css('.tags .tag::text').extract()

yield item

next_page = response.css('.pager .next a::attr(href)').extract_first()

url = response.urljoin(next_page)

yield scrapy.Request(url=url,callback=self.parse)

可以通過在命令列,執行以下命令進行執行:

scrapy crawl quotes

3.5 使用Item Pipeline

如果想將資料儲存到MongoDB,或者篩選某些有用的Item,就可以通過定義Item Pipeline來定義。

接下來我們主要想實現篩選text長度大於50的Item,並將結果儲存到MongoDB:

import pymongo

from scrapy.exceptions import DropItem

class TextPipeline(object):

def __init__(self):

self.limit = 50

def process_item(self,item,spider):

if item['text']:

if len(item['text']) > self.limit:

item['text'] = item['text'][0:self.limit].rstrip() + '...'

return item

else:

return DropItem('沒有文字資料!')

class MongoPipeline(object):

def __init__(self,mongo_url,mongo_db):

self.mongo_url = mongo_url

self.mongo_db = mongo_db

@classmethod

def from_crawler(cls,crawler):

return cls(

mongo_url=crawler.settings.get('MONGO_URL'),

mongo_db = crawler.settings.get('MONGO_DB')

)

def open_spider(self,spider):

self.client = pymongo.MongoClient(self.mongo_url)

self.db = self.client[self.mongo_db]

def close_spider(self,spider):

self.client.close()

def process_item(self, item, spider):

name = item.__class__.__name__

self.db[name].insert(dict(item))

return item

我們需要將定義好的TextPipeline和MongoPipeline兩個類在settings.py檔案,進行配置:

ITEM_PIPELINES = {

'toscrape.pipelines.MongoPipeline': 400,

'toscrape.pipelines.MongoPipeline': 300,

}

MONGO_URL = 'localhost'

MONGO_DB = 'ToScape'

再次執行就可以將獲取和處理的資料儲存到MongoDB裡面。