1. Scrapy簡介
Scrapy是一個為了爬取網站數據,提取結構性數據而編寫的應用框架。 可以應用在包括數據挖掘,信息處理或存儲歷史數據等一系列的程序中。
其最初是為了頁面抓取 (更確切來說, 網絡抓取 )所設計的, 也可以應用在獲取API所返回的數據(例如 Amazon Associates Web Services ) 或者通用的網絡爬蟲。Scrapy用途廣泛,可以用于數據挖掘、監測和自動化測試
Scrapy 使用了 Twisted異步網絡庫來處理網絡通訊。整體架構大致如下

Scrapy主要包括了以下組件:
(1)引擎(Scrapy): 用來處理整個系統的數據流處理, 觸發事務(框架核心)
(2)調度器(Scheduler): 用來接受引擎發過來的請求, 壓入隊列中, 并在引擎再次請求的時候返回. 可以想像成一個URL(抓取網頁的網址或者說是鏈接)的優先隊列, 由它來決定下一個要抓取的網址是什么, 同時去除重復的網址
(3)下載器(Downloader): 用于下載網頁內容, 并將網頁內容返回給蜘蛛(Scrapy下載器是建立在twisted這個高效的異步模型上的)
(4)爬蟲(Spiders): 爬蟲是主要干活的, 用于從特定的網頁中提取自己需要的信息, 即所謂的實體(Item)。用戶也可以從中提取出鏈接,讓Scrapy繼續抓取下一個頁面
項目管道(Pipeline): 負責處理爬蟲從網頁中抽取的實體,主要的功能是持久化實體、驗證實體的有效性、清除不需要的信息。當頁面被爬蟲解析后,將被發送到項目管道,并經過幾個特定的次序處理數據。
(5)下載器中間件(Downloader Middlewares): 位于Scrapy引擎和下載器之間的框架,主要是處理Scrapy引擎與下載器之間的請求及響應。
(6)爬蟲中間件(Spider Middlewares): 介于Scrapy引擎和爬蟲之間的框架,主要工作是處理蜘蛛的響應輸入和請求輸出。
(7)調度中間件(Scheduler Middewares): 介于Scrapy引擎和調度之間的中間件,從Scrapy引擎發送到調度的請求和響應。
Scrapy運行流程大概如下:
首先,引擎從調度器中取出一個鏈接(URL)用于接下來的抓取
引擎把URL封裝成一個請求(Request)傳給下載器,下載器把資源下載下來,并封裝成應答包(Response)
然后,爬蟲解析Response
若是解析出實體(Item),則交給實體管道進行進一步的處理。
若是解析出的是鏈接(URL),則把URL交給Scheduler等待抓取
2. 安裝Scrapy
使用以下命令:
sudo pip install virtualenv #安裝虛擬環境工具virtualenv ENV #創建一個虛擬環境目錄source ./ENV/bin/active #激活虛擬環境pip install Scrapy#驗證是否安裝成功pip list
#輸出如下cffi (0.8.6)cryptography (0.6.1)cssselect (0.9.1)lxml (3.4.1)pip (1.5.6)pycparser (2.10)pyOpenSSL (0.14)queuelib (1.2.2)Scrapy (0.24.4)setuptools (3.6)six (1.8.0)Twisted (14.0.2)w3lib (1.10.0)wsgiref (0.1.2)zope.interface (4.1.1)
更多虛擬環境的操作可以查看我的博文
3. Scrapy Tutorial
在抓取之前, 你需要新建一個Scrapy工程. 進入一個你想用來保存代碼的目錄,然后執行:
$ scrapy startproject tutorial
這個命令會在當前目錄下創建一個新目錄 tutorial, 它的結構如下:
.├── scrapy.cfg└── tutorial ├── __init__.py ├── items.py ├── pipelines.py ├── settings.py └── spiders └── __init__.py
這些文件主要是:
(1)scrapy.cfg: 項目配置文件
(2)tutorial/: 項目python模塊, 之后您將在此加入代碼
(3)tutorial/items.py: 項目items文件
(4)tutorial/pipelines.py: 項目管道文件
(5)tutorial/settings.py: 項目配置文件
(6)tutorial/spiders: 放置spider的目錄
3.1. 定義Item
Items是將要裝載抓取的數據的容器,它工作方式像 python 里面的字典,但它提供更多的保護,比如對未定義的字段填充以防止拼寫錯誤
通過創建scrapy.Item類, 并且定義類型為 scrapy.Field 的類屬性來聲明一個Item.
我們通過將需要的item模型化,來控制從 dmoz.org 獲得的站點數據,比如我們要獲得站點的名字,url 和網站描述,我們定義這三種屬性的域。在 tutorial 目錄下的 items.py 文件編輯
from scrapy.item import Item, Fieldclass DmozItem(Item): # define the fields for your item here like: name = Field() description = Field() url = Field()
3.2. 編寫Spider
Spider 是用戶編寫的類, 用于從一個域(或域組)中抓取信息, 定義了用于下載的URL的初步列表, 如何跟蹤鏈接,以及如何來解析這些網頁的內容用于提取items。
要建立一個 Spider,繼承 scrapy.Spider 基類,并確定三個主要的、強制的屬性:
name:爬蟲的識別名,它必須是唯一的,在不同的爬蟲中你必須定義不同的名字.
start_urls:包含了Spider在啟動時進行爬取的url列表。因此,第一個被獲取到的頁面將是其中之一。后續的URL則從初始的URL獲取到的數據中提取。我們可以利用正則表達式定義和過濾需要進行跟進的鏈接。
parse():是spider的一個方法。被調用時,每個初始URL完成下載后生成的 Response 對象將會作為唯一的參數傳遞給該函數。該方法負責解析返回的數據(response data),提取數據(生成item)以及生成需要進一步處理的URL的 Request 對象。
這個方法負責解析返回的數據、匹配抓取的數據(解析為 item )并跟蹤更多的 URL。
在 /tutorial/tutorial/spiders 目錄下創建 dmoz_spider.py
import scrapyclass DmozSpider(scrapy.Spider): name = "dmoz" allowed_domains = ["dmoz.org"] start_urls = [ "http://www.dmoz.org/Computers/Programming/Languages/Python/Books/", "http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/" ] def parse(self, response): filename = response.url.split("/")[-2] with open(filename, 'wb') as f: f.write(response.body)3.3. 爬取
當前項目結構
├── scrapy.cfg└── tutorial ├── __init__.py ├── items.py ├── pipelines.py ├── settings.py └── spiders ├── __init__.py └── dmoz_spider.py
到項目根目錄, 然后運行命令:
$ scrapy crawl dmoz
2014-12-15 09:30:59+0800 [scrapy] INFO: Scrapy 0.24.4 started (bot: tutorial)2014-12-15 09:30:59+0800 [scrapy] INFO: Optional features available: ssl, http112014-12-15 09:30:59+0800 [scrapy] INFO: Overridden settings: {'NEWSPIDER_MODULE': 'tutorial.spiders', 'SPIDER_MODULES': ['tutorial.spiders'], 'BOT_NAME': 'tutorial'}2014-12-15 09:30:59+0800 [scrapy] INFO: Enabled extensions: LogStats, TelnetConsole, CloseSpider, WebService, CoreStats, SpiderState2014-12-15 09:30:59+0800 [scrapy] INFO: Enabled downloader middlewares: HttpAuthMiddleware, DownloadTimeoutMiddleware, UserAgentMiddleware, RetryMiddleware, DefaultHeadersMiddleware, MetaRefreshMiddleware, HttpCompressionMiddleware, RedirectMiddleware, CookiesMiddleware, ChunkedTransferMiddleware, DownloaderStats2014-12-15 09:30:59+0800 [scrapy] INFO: Enabled spider middlewares: HttpErrorMiddleware, OffsiteMiddleware, RefererMiddleware, UrlLengthMiddleware, DepthMiddleware2014-12-15 09:30:59+0800 [scrapy] INFO: Enabled item pipelines:2014-12-15 09:30:59+0800 [dmoz] INFO: Spider opened2014-12-15 09:30:59+0800 [dmoz] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)2014-12-15 09:30:59+0800 [scrapy] DEBUG: Telnet console listening on 127.0.0.1:60232014-12-15 09:30:59+0800 [scrapy] DEBUG: Web service listening on 127.0.0.1:60802014-12-15 09:31:00+0800 [dmoz] DEBUG: Crawled (200) <GET http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/> (referer: None)2014-12-15 09:31:00+0800 [dmoz] DEBUG: Crawled (200) <GET http://www.dmoz.org/Computers/Programming/Languages/Python/Books/> (referer: None)2014-12-15 09:31:00+0800 [dmoz] INFO: Closing spider (finished)2014-12-15 09:31:00+0800 [dmoz] INFO: Dumping Scrapy stats: {'downloader/request_bytes': 516, 'downloader/request_count': 2, 'downloader/request_method_count/GET': 2, 'downloader/response_bytes': 16338, 'downloader/response_count': 2, 'downloader/response_status_count/200': 2, 'finish_reason': 'finished', 'finish_time': datetime.datetime(2014, 12, 15, 1, 31, 0, 666214), 'log_count/DEBUG': 4, 'log_count/INFO': 7, 'response_received_count': 2, 'scheduler/dequeued': 2, 'scheduler/dequeued/memory': 2, 'scheduler/enqueued': 2, 'scheduler/enqueued/memory': 2, 'start_time': datetime.datetime(2014, 12, 15, 1, 30, 59, 533207)}2014-12-15 09:31:00+0800 [dmoz] INFO: Spider closed (finished)3.4. 提取Items
3.4.1. 介紹Selector
從網頁中提取數據有很多方法。Scrapy使用了一種基于 XPath 或者 CSS 表達式機制: Scrapy Selectors
出XPath表達式的例子及對應的含義:
等多強大的功能使用可以查看XPath tutorial
為了方便使用 XPaths,Scrapy 提供 Selector 類, 有四種方法 :
3.4.2. 取出數據
在查看網站源碼后, 網站信息在第二個<ul>內
<ul class="directory-url" style="margin-left:0;"> <li><a class="listinglink">Core Python Programming</a> - By Wesley J. Chun; Prentice Hall PTR, 2001, ISBN 0130260363. For experienced developers to improve extant skills; professional level examples. Starts by introducing syntax, objects, error handling, functions, classes, built-ins. [Prentice Hall]<div class="flag"><a href="/public/flag?cat=Computers%2FProgramming%2FLanguages%2FPython%2FBooks&url=http%3A%2F%2Fwww.pearsonhighered.com%2Feducator%2Facademic%2Fproduct%2F0%2C%2C0130260363%2C00%252Ben-USS_01DBC.html"><img src="/img/flag.png" alt="[!]" title="report an issue with this listing"></a></div></li>...省略部分...</ul>
那么就可以通過一下方式進行提取數據
#通過如下命令選擇每個在網站中的 <li> 元素:sel.xpath('//ul/li')#網站描述:sel.xpath('//ul/li/text()').extract()#網站標題:sel.xpath('//ul/li/a/text()').extract()#網站鏈接:sel.xpath('//ul/li/a/@href').extract()如前所述,每個 xpath() 調用返回一個 selectors 列表,所以我們可以結合 xpath() 去挖掘更深的節點。我們將會用到這些特性,所以:
for sel in response.xpath('//ul/li') title = sel.xpath('a/text()').extract() link = sel.xpath('a/@href').extract() desc = sel.xpath('text()').extract() print title, link, desc在已有的爬蟲文件中修改代碼
import scrapyclass DmozSpider(scrapy.Spider): name = "dmoz" allowed_domains = ["dmoz.org"] start_urls = [ "http://www.dmoz.org/Computers/Programming/Languages/Python/Books/", "http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/" ] def parse(self, response): for sel in response.xpath('//ul/li'): title = sel.xpath('a/text()').extract() link = sel.xpath('a/@href').extract() desc = sel.xpath('text()').extract() print title, link, desc3.4.3. 使用item
Item對象是自定義的python字典,可以使用標準的字典語法來獲取到其每個字段的值(字段即是我們之前用Field賦值的屬性)
>>> item = DmozItem()>>> item['title'] = 'Example title'>>> item['title']'Example title'
一般來說,Spider將會將爬取到的數據以 Item 對象返回, 最后修改爬蟲類,使用 Item 來保存數據,代碼如下
from scrapy.spider import Spiderfrom scrapy.selector import Selectorfrom tutorial.items import DmozItemclass DmozSpider(Spider): name = "dmoz" allowed_domains = ["dmoz.org"] start_urls = [ "http://www.dmoz.org/Computers/Programming/Languages/Python/Books/", "http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/", ] def parse(self, response): sel = Selector(response) sites = sel.xpath('//ul[@class="directory-url"]/li') items = [] for site in sites: item = DmozItem() item['name'] = site.xpath('a/text()').extract() item['url'] = site.xpath('a/@href').extract() item['description'] = site.xpath('text()').re('-/s[^/n]*//r') items.append(item) return items3.5. 使用Item Pipeline
當Item在Spider中被收集之后,它將會被傳遞到Item Pipeline,一些組件會按照一定的順序執行對Item的處理。
每個item pipeline組件(有時稱之為ItemPipeline)是實現了簡單方法的Python類。他們接收到Item并通過它執行一些行為,同時也決定此Item是否繼續通過pipeline,或是被丟棄而不再進行處理。
以下是item pipeline的一些典型應用:
編寫你自己的item pipeline很簡單,每個item pipeline組件是一個獨立的Python類,同時必須實現以下方法:
(1)process_item(item, spider) #每個item pipeline組件都需要調用該方法,這個方法必須返回一個 Item (或任何繼承類)對象,或是拋出 DropItem異常,被丟棄的item將不會被之后的pipeline組件所處理。
#參數:
item: 由 parse 方法返回的 Item 對象(Item對象)
spider: 抓取到這個 Item 對象對應的爬蟲對象(Spider對象)
(2)open_spider(spider) #當spider被開啟時,這個方法被調用。
#參數:
spider : (Spider object) 主站蜘蛛池模板: 永仁县| 青河县| 民权县| 建湖县| 泽普县| 商河县| 新昌县| 黄梅县| 古蔺县| 石棉县| 绥江县| 杭州市| 友谊县| 栾城县| 于田县| 宾川县| 连州市| 偏关县| 泸西县| 云霄县| 凤台县| 五台县| 密云县| 凯里市| 延安市| 巴里| 广平县| 七台河市| 博罗县| 乐陵市| 林口县| 深泽县| 慈利县| 东阿县| 峨山| 元氏县| 嘉义市| 丰镇市| 鄂伦春自治旗| 蚌埠市| 朝阳市|