python之scrapy(一)基礎和入門
Scrapy框架的使用
一、 Scrapy框架的介紹
Scrapy是一個基於 Twisted 非同步處理的框架,是一個純python的網路爬蟲框架,是一個為了爬取網站資料,提取結構性資料而編寫的應用框架。 其可以應用在資料探勘,資訊處理或儲存歷史資料等一系列的程式中。其最初是為了頁面抓取 (更確切來說, 網路抓取 )所設計的, 也可以應用在獲取API所返回的資料或者通用的網路爬蟲。
Scrapy用途廣泛,可以用於資料探勘、監測和自動化測試。
1.1 框架介紹
Scrapy基於事件驅動網路框架 Twisted 編寫。因此,Scrapy基於併發性考慮由非阻塞(即非同步)的實現。
主要有以下元件:
-
Scrapy Engine:引擎負責控制資料流在系統中所有元件中流動,並在相應動作發生時觸發事件。 詳細內容檢視下面的資料流(Data Flow)部分。
-
Scheduler:排程器從引擎接受request並將他們入隊,以便之後引擎請求他們時提供給引擎。
-
Downloader:下載器負責獲取頁面資料並提供給引擎,而後提供給spider。
-
Spiders:Spider是Scrapy使用者編寫用於分析response並提取item(即獲取到的item)或額外跟進的URL的類。 每個spider負責處理一個特定(或一些)網站。
-
Item Pipeline:Item Pipeline負責處理被spider提取出來的item。典型的處理有清理、 驗證及持久化(例如存取到資料庫中)。
-
Downloader middlewares:下載器中介軟體是在引擎及下載器之間的特定鉤子,處理Downloader傳遞給引擎的response。 其提供了一個簡便的機制,通過插入自定義程式碼來擴充套件Scrapy功能。
1.2 資料流
Scrapy中的資料流由執行引擎控制,其過程如下:
-
引擎開啟一個網站(open a domain),找到處理該網站的Spider並向該spider請求第一個要爬取的URL(s)。
-
引擎從Spider中獲取到第一個要爬取的URL並在排程器(Scheduler)以Request排程。
-
引擎向排程器請求下一個要爬取的URL。
-
排程器返回下一個要爬取的URL給引擎,引擎將URL通過下載中介軟體(請求(request)方向)轉發給下載器(Downloader)。
-
一旦頁面下載完畢,下載器生成一個該頁面的Response,並將其通過下載中介軟體(返回(response)方向)傳送給引擎。
-
引擎從下載器中接收到Response並通過Spider中介軟體(輸入方向)傳送給Spider處理。
-
Spider處理Response並返回爬取到的Item及(跟進的)新的Request給引擎。
-
引擎將(Spider返回的)爬取到的Item給Item Pipeline,將(Spider返回的)Request給排程器。
-
重複第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
https://pypi.python.org/pypi/lxml/4.1.0
3、安裝pyopenssl
https://pypi.python.org/pypi/pyOpenSSL/17.5.0
4、安裝Twisted
https://www.lfd.uci.edu/~gohlke/pythonlibs/
5、安裝pywin32
https://sourceforge.net/projects/pywin32/files/
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的名稱和起始請求,以及怎麼獲得響應的方法。
通過請求http://quotes.toscrape.com,來建立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裡面。