本文但願達到如下目標:css
初學
Scrapy
, 若有翻譯不當, 或者代碼錯誤, 請指出, 很是感謝html
Scrapy是一個爲了爬取網站數據,提取結構性數據而編寫的應用框架。 能夠應用在包括數據挖掘,信息處理或存儲歷史數據等一系列的程序中。
其最初是爲了頁面抓取 (更確切來講, 網絡抓取 )所設計的, 也能夠應用在獲取API所返回的數據(例如 Amazon Associates Web Services ) 或者通用的網絡爬蟲。Scrapy用途普遍,能夠用於數據挖掘、監測和自動化測試python
Scrapy
使用了 Twisted
異步網絡庫來處理網絡通信。總體架構大體以下正則表達式
Scrapy數據庫
Scrapy主要包括瞭如下組件:json
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)
在抓取以前, 你須要新建一個Scrapy
工程. 進入一個你想用來保存代碼的目錄,而後執行:app
$ scrapy startproject tutorial
這個命令會在當前目錄下建立一個新目錄 tutorial, 它的結構以下:
. ├── scrapy.cfg └── tutorial ├── __init__.py ├── items.py ├── pipelines.py ├── settings.py └── spiders └── __init__.py
這些文件主要是:
Items是將要裝載抓取的數據的容器,它工做方式像 python 裏面的字典,但它提供更多的保護,好比對未定義的字段填充以防止拼寫錯誤
經過建立scrapy.Item類
, 而且定義類型爲 scrapy.Field
的類屬性來聲明一個Item.
咱們經過將須要的item模型化,來控制從 dmoz.org
得到的站點數據,好比咱們要得到站點的名字,url 和網站描述,咱們定義這三種屬性的域。在 tutorial 目錄下的 items.py 文件編輯
from scrapy.item import Item, Field class DmozItem(Item): # define the fields for your item here like: name = Field() description = Field() url = Field()
Spider 是用戶編寫的類, 用於從一個域(或域組)中抓取信息, 定義了用於下載的URL的初步列表, 如何跟蹤連接,以及如何來解析這些網頁的內容用於提取items。
要創建一個 Spider,繼承 scrapy.Spider
基類,並肯定三個主要的、強制的屬性:
在 /tutorial/tutorial/spiders 目錄下建立 dmoz_spider.py
import scrapy class 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)
當前項目結構
├── 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, http11 2014-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, SpiderState 2014-12-15 09:30:59+0800 [scrapy] INFO: Enabled downloader middlewares: HttpAuthMiddleware, DownloadTimeoutMiddleware, UserAgentMiddleware, RetryMiddleware, DefaultHeadersMiddleware, MetaRefreshMiddleware, HttpCompressionMiddleware, RedirectMiddleware, CookiesMiddleware, ChunkedTransferMiddleware, DownloaderStats 2014-12-15 09:30:59+0800 [scrapy] INFO: Enabled spider middlewares: HttpErrorMiddleware, OffsiteMiddleware, RefererMiddleware, UrlLengthMiddleware, DepthMiddleware 2014-12-15 09:30:59+0800 [scrapy] INFO: Enabled item pipelines: 2014-12-15 09:30:59+0800 [dmoz] INFO: Spider opened 2014-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:6023 2014-12-15 09:30:59+0800 [scrapy] DEBUG: Web service listening on 127.0.0.1:6080 2014-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)
從網頁中提取數據有不少方法。Scrapy使用了一種基於 XPath
或者 CSS 表達式
機制: Scrapy Selectors
出XPath表達式的例子及對應的含義:
/html/head/title
: 選擇HTML文檔中 <head>
標籤內的 <title>
元素/html/head/title/text()
: 選擇 <title>
元素內的文本//td
: 選擇全部的 <td>
元素//div[@class="mine"]
: 選擇全部具備class="mine"
屬性的 div 元素等多強大的功能使用能夠查看XPath tutorial
爲了方便使用 XPaths,Scrapy 提供 Selector 類, 有四種方法 :
首先使用谷歌瀏覽器開發者工具, 查看網站源碼, 來看本身須要取出的數據形式(這種方法比較麻煩), 更簡單的方法是直接對感興趣的東西右鍵審查元素
, 能夠直接查看網站源碼
在查看網站源碼後, 網站信息在第二個<ul>
內
<ul class="directory-url" style="margin-left:0;"> <li><a href="http://www.pearsonhighered.com/educator/academic/product/0,,0130260363,00%2Ben-USS_01DBC.html" 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 scrapy class 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, desc
Item
對象是自定義的python字典,可使用標準的字典語法來獲取到其每一個字段的值(字段便是咱們以前用Field賦值的屬性)
>>> item = DmozItem() >>> item['title'] = 'Example title' >>> item['title'] 'Example title'
通常來講,Spider將會將爬取到的數據以 Item 對象返回, 最後修改爬蟲類,使用 Item 來保存數據,代碼以下
from scrapy.spider import Spider from scrapy.selector import Selector from tutorial.items import DmozItem class 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 items
當Item在Spider中被收集以後,它將會被傳遞到Item Pipeline,一些組件會按照必定的順序執行對Item的處理。
每一個item pipeline組件(有時稱之爲ItemPipeline
)是實現了簡單方法的Python類。他們接收到Item並經過它執行一些行爲,同時也決定此Item是否繼續經過pipeline,或是被丟棄而再也不進行處理。
如下是item pipeline的一些典型應用:
編寫你本身的item pipeline很簡單,每一個item pipeline組件是一個獨立的Python類,同時必須實現如下方法:
process_item(item, spider) #每一個item pipeline組件都須要調用該方法,這個方法必須返回一個 Item (或任何繼承類)對象,或是拋出 DropItem異常,被丟棄的item將不會被以後的pipeline組件所處理。 #參數: item: 由 parse 方法返回的 Item 對象(Item對象) spider: 抓取到這個 Item 對象對應的爬蟲對象(Spider對象) open_spider(spider) #當spider被開啓時,這個方法被調用。 #參數: spider : (Spider object) – 被開啓的spider close_spider(spider) #當spider被關閉時,這個方法被調用,能夠再爬蟲關閉後進行相應的數據處理。 #參數: spider : (Spider object) – 被關閉的spider
爲JSON文件編寫一個items
from scrapy.exceptions import DropItem class TutorialPipeline(object): # put all words in lowercase words_to_filter = ['politics', 'religion'] def process_item(self, item, spider): for word in self.words_to_filter: if word in unicode(item['description']).lower(): raise DropItem("Contains forbidden word: %s" % word) else: return item
在 settings.py 中設置ITEM_PIPELINES
激活item pipeline,其默認爲[]
ITEM_PIPELINES = {'tutorial.pipelines.FilterWordsPipeline': 1}
使用下面的命令存儲爲json
文件格式
scrapy crawl dmoz -o items.json
文/Andrew_liu(簡書做者) 原文連接:http://www.jianshu.com/p/078ad2067419 著做權歸做者全部,轉載請聯繫做者得到受權,並標註「簡書做者」。