做者:http://www.cnblogs.com/txw1958/
出處:http://www.cnblogs.com/txw1958/archive/2012/07/16/scrapy-tutorial.htmlhtml
在這篇入門教程中,咱們假定你已經安裝了Scrapy。若是你尚未安裝,那麼請參考安裝指南。python
咱們將使用開放目錄項目(dmoz)做爲抓取的例子。git
這篇入門教程將引導你完成以下任務:程序員
Scrapy是由Python編寫的。若是你是Python新手,你也許但願從瞭解Python開始,以期最好的使用Scrapy。若是你對其它編程語言熟悉,想快速的學習Python,這裏推薦 Dive Into Python。若是你對編程是新手,且想從Python開始學習編程,請看下面的對非程序員的Python資源列表。github
新建工程正則表達式
在抓取以前,你須要新建一個Scrapy工程。進入一個你想用來保存代碼的目錄,而後執行:shell
Microsoft Windows XP [Version 5.1.2600] (C) Copyright 1985-2001 Microsoft Corp. T:\>scrapy startproject tutorial T:\>
這個命令會在當前目錄下建立一個新目錄tutorial,它的結構以下:編程
T:\tutorial>tree /f Folder PATH listing Volume serial number is 0006EFCF C86A:7C52 T:. │ scrapy.cfg │ └─tutorial │ items.py │ pipelines.py │ settings.py │ __init__.py │ └─spiders __init__.py
這些文件主要是:json
定義Itemapi
Items是將要裝載抓取的數據的容器,它工做方式像python裏面的字典,但它提供更多的保護,好比對未定義的字段填充以防止拼寫錯誤。
它經過建立一個scrapy.item.Item類來聲明,定義它的屬性爲scrpy.item.Field對象,就像是一個對象關係映射(ORM).
咱們經過將須要的item模型化,來控制從dmoz.org得到的站點數據,好比咱們要得到站點的名字,url和網站描述,咱們定義這三種屬性的域。要作到這點,咱們編輯在tutorial目錄下的items.py文件,咱們的Item類將會是這樣
from scrapy.item import Item, Field class DmozItem(Item): title = Field() link = Field() desc = Field()
剛開始看起來可能會有些困惑,可是定義這些item能讓你用其餘Scrapy組件的時候知道你的 items究竟是什麼。
咱們的第一個爬蟲(Spider)
Spider是用戶編寫的類,用於從一個域(或域組)中抓取信息。
他們定義了用於下載的URL的初步列表,如何跟蹤連接,以及如何來解析這些網頁的內容用於提取items。
要創建一個Spider,你必須爲scrapy.spider.BaseSpider建立一個子類,並肯定三個主要的、強制的屬性:
這個方法負責解析返回的數據、匹配抓取的數據(解析爲item)並跟蹤更多的URL。
這是咱們的第一隻爬蟲的代碼,將其命名爲dmoz_spider.py並保存在tutorial\spiders目錄下。
from scrapy.spider import BaseSpider class DmozSpider(BaseSpider): 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] open(filename, 'wb').write(response.body)
爬爬爬
爲了讓咱們的爬蟲工做,咱們返回項目主目錄執行如下命令
T:\tutorial>scrapy crawl dmoz
crawl dmoz 命令從dmoz.org域啓動爬蟲。 你將會得到以下相似輸出
T:\tutorial>scrapy crawl dmoz 2012-07-13 19:14:45+0800 [scrapy] INFO: Scrapy 0.14.4 started (bot: tutorial) 2012-07-13 19:14:45+0800 [scrapy] DEBUG: Enabled extensions: LogStats, TelnetConsole, CloseSpider, WebService, CoreStats, SpiderState 2012-07-13 19:14:45+0800 [scrapy] DEBUG: Enabled downloader middlewares: HttpAuthMiddleware, DownloadTimeoutMiddleware, UserAgentMiddleware, RetryMiddleware, DefaultHeadersMiddleware, RedirectMiddleware, CookiesMiddleware, HttpCompressionMiddleware, ChunkedTransferMiddleware, DownloaderStats 2012-07-13 19:14:45+0800 [scrapy] DEBUG: Enabled spider middlewares: HttpErrorMiddleware, OffsiteMiddleware, RefererMiddleware, UrlLengthMiddleware, DepthMiddleware 2012-07-13 19:14:45+0800 [scrapy] DEBUG: Enabled item pipelines: 2012-07-13 19:14:45+0800 [dmoz] INFO: Spider opened 2012-07-13 19:14:45+0800 [dmoz] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min) 2012-07-13 19:14:45+0800 [scrapy] DEBUG: Telnet console listening on 0.0.0.0:6023 2012-07-13 19:14:45+0800 [scrapy] DEBUG: Web service listening on 0.0.0.0:6080 2012-07-13 19:14:46+0800 [dmoz] DEBUG: Crawled (200) <GET http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/> (referer: None) 2012-07-13 19:14:46+0800 [dmoz] DEBUG: Crawled (200) <GET http://www.dmoz.org/Computers/Programming/Languages/Python/Books/> (referer: None) 2012-07-13 19:14:46+0800 [dmoz] INFO: Closing spider (finished) 2012-07-13 19:14:46+0800 [dmoz] INFO: Dumping spider stats: {'downloader/request_bytes': 486, 'downloader/request_count': 2, 'downloader/request_method_count/GET': 2, 'downloader/response_bytes': 13063, 'downloader/response_count': 2, 'downloader/response_status_count/200': 2, 'finish_reason': 'finished', 'finish_time': datetime.datetime(2012, 7, 13, 11, 14, 46, 703000), 'scheduler/memory_enqueued': 2, 'start_time': datetime.datetime(2012, 7, 13, 11, 14, 45, 500000)} 2012-07-13 19:14:46+0800 [dmoz] INFO: Spider closed (finished) 2012-07-13 19:14:46+0800 [scrapy] INFO: Dumping global stats: {}
注意包含 [dmoz]的行 ,那對應着咱們的爬蟲。你能夠看到start_urls中定義的每一個URL都有日誌行。由於這些URL是起始頁面,因此他們沒有引用(referrers),因此在每行的末尾你會看到 (referer: <None>).
有趣的是,在咱們的 parse 方法的做用下,兩個文件被建立:分別是 Books 和 Resources,這兩個文件中有URL的頁面內容。
發生了什麼事情?
Scrapy爲爬蟲的 start_urls屬性中的每一個URL建立了一個 scrapy.http.Request 對象 ,並將爬蟲的parse 方法指定爲回調函數。
這些 Request首先被調度,而後被執行,以後經過parse()方法,scrapy.http.Response 對象被返回,結果也被反饋給爬蟲。
提取Item
選擇器介紹
咱們有不少方法從網站中提取數據。Scrapy 使用一種叫作 XPath selectors的機制,它基於 XPath表達式。若是你想了解更多selectors和其餘機制你能夠查閱資料http://doc.scrapy.org/topics/selectors.html#topics-selectors
這是一些XPath表達式的例子和他們的含義
這只是幾個使用XPath的簡單例子,可是實際上XPath很是強大。若是你想了解更多XPATH的內容,咱們向你推薦這個XPath教程http://www.w3schools.com/XPath/default.asp
爲了方便使用XPaths,Scrapy提供XPathSelector 類, 有兩種口味能夠選擇, HtmlXPathSelector (HTML數據解析) 和XmlXPathSelector (XML數據解析)。 爲了使用他們你必須經過一個 Response 對象對他們進行實例化操做。你會發現Selector對象展現了文檔的節點結構。所以,第一個實例化的selector必與根節點或者是整個目錄有關 。
Selectors 有三種方法
嘗試在shell中使用Selectors
爲了演示Selectors的用法,咱們將用到 內建的Scrapy shell,這須要系統已經安裝IPython (一個擴展python交互環境) 。
附IPython下載地址:http://pypi.python.org/pypi/ipython#downloads
要開始shell,首先進入項目頂層目錄,而後輸入
T:\tutorial>scrapy shell http://www.dmoz.org/Computers/Programming/Languages/Python/Books/
輸出結果相似這樣:
2012-07-16 10:58:13+0800 [scrapy] INFO: Scrapy 0.14.4 started (bot: tutorial) 2012-07-16 10:58:13+0800 [scrapy] DEBUG: Enabled extensions: TelnetConsole, CloseSpider, WebService, CoreStats, SpiderState 2012-07-16 10:58:13+0800 [scrapy] DEBUG: Enabled downloader middlewares: HttpAuthMiddleware, DownloadTimeoutMiddleware, UserAgentMiddleware, RetryMiddleware, DefaultHeadersMiddleware, RedirectMiddleware, CookiesMiddleware, HttpCompressionMiddleware, ChunkedTransferMiddleware, DownloaderStats 2012-07-16 10:58:13+0800 [scrapy] DEBUG: Enabled spider middlewares: HttpErrorMiddleware, OffsiteMiddleware, RefererMiddleware, UrlLengthMiddleware, DepthMiddleware 2012-07-16 10:58:13+0800 [scrapy] DEBUG: Enabled item pipelines: 2012-07-16 10:58:13+0800 [scrapy] DEBUG: Telnet console listening on 0.0.0.0:6023 2012-07-16 10:58:13+0800 [scrapy] DEBUG: Web service listening on 0.0.0.0:6080 2012-07-16 10:58:13+0800 [dmoz] INFO: Spider opened 2012-07-16 10:58:18+0800 [dmoz] DEBUG: Crawled (200) <GET http://www.dmoz.org/Computers/Programming/Languages/Python/Books/> (referer: None) [s] Available Scrapy objects: [s] hxs <HtmlXPathSelector xpath=None data=u'<html><head><meta http-equiv="Content-Ty'> [s] item {} [s] request <GET http://www.dmoz.org/Computers/Programming/Languages/Python/Books/> [s] response <200 http://www.dmoz.org/Computers/Programming/Languages/Python/Books/> [s] settings <CrawlerSettings module=<module 'tutorial.settings' from 'T:\tutorial\tutorial\settings.pyc'>> [s] spider <DmozSpider 'dmoz' at 0x1f68230> [s] Useful shortcuts: [s] shelp() Shell help (print this help) [s] fetch(req_or_url) Fetch request (or URL) and update local objects [s] view(response) View response in a browser WARNING: Readline services not available or not loaded.WARNING: Proper color support under MS Windows requires the pyreadline library. You can find it at: http://ipython.org/pyreadline.html Gary's readline needs the ctypes module, from: http://starship.python.net/crew/theller/ctypes (Note that ctypes is already part of Python versions 2.5 and newer). Defaulting color scheme to 'NoColor'Python 2.7.3 (default, Apr 10 2012, 23:31:26) [MSC v.1500 32 bit (Intel)] Type "copyright", "credits" or "license" for more information. IPython 0.13 -- An enhanced Interactive Python. ? -> Introduction and overview of IPython's features. %quickref -> Quick reference. help -> Python's own help system. object? -> Details about 'object', use 'object??' for extra details. In [1]:
Shell載入後,你將得到迴應,這些內容被存儲在本地變量 response 中,因此若是你輸入response.body 你將會看到response的body部分,或者輸入response.headers 來查看它的 header部分。
Shell也實例化了兩種selectors,一個是解析HTML的 hxs 變量,一個是解析 XML 的 xxs 變量。咱們來看看裏面有什麼:
In [1]: hxs.path('//title') Out[1]: [<HtmlXPathSelector xpath='//title' data=u'<title>Open Directory - Computers: Progr'>] In [2]: hxs.path('//title').extract() Out[2]: [u'<title>Open Directory - Computers: Programming: Languages: Python: Books</title>'] In [3]: hxs.path('//title/text()') Out[3]: [<HtmlXPathSelector xpath='//title/text()' data=u'Open Directory - Computers: Programming:'>] In [4]: hxs.path('//title/text()').extract() Out[4]: [u'Open Directory - Computers: Programming: Languages: Python: Books'] In [5]: hxs.path('//title/text()').re('(\w+):') Out[5]: [u'Computers', u'Programming', u'Languages', u'Python'] In [6]:
提取數據
如今咱們嘗試從網頁中提取數據。
你能夠在控制檯輸入 response.body, 檢查源代碼中的 XPaths 是否與預期相同。然而,檢查HTML源代碼是件很枯燥的事情。爲了使事情變得簡單,咱們使用Firefox的擴展插件Firebug。更多信息請查看Using Firebug for scraping和Using Firefox for scraping.
txw1958注:事實上我用的是Google Chrome的Inspect Element功能,並且能夠提取元素的XPath。
檢查源代碼後,你會發現咱們須要的數據在一個 <ul>元素中,並且是第二個<ul>。
咱們能夠經過以下命令選擇每一個在網站中的 <li> 元素:
hxs.path('//ul/li')
而後是網站描述:
hxs.path('//ul/li/text()').extract()
網站標題:
hxs.path('//ul/li/a/text()').extract()
網站連接:
hxs.path('//ul/li/a/@href').extract()
如前所述,每一個path()調用返回一個selectors列表,因此咱們能夠結合path()去挖掘更深的節點。咱們將會用到這些特性,因此:
sites = hxs.path('//ul/li') for site in sites: title = site.path('a/text()').extract() link = site.path('a/@href').extract() desc = site.path('text()').extract() print title, link, desc
Note
更多關於嵌套選擇器的內容,請閱讀Nesting selectors 和 Working with relative XPaths
將代碼添加到爬蟲中:
txw1958注:代碼有修改,綠色註釋掉的代碼爲原教程的,你懂的
from scrapy.spider import BaseSpider from scrapy.selector import HtmlXPathSelector class DmozSpider(BaseSpider): 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): hxs = HtmlXPathSelector(response) sites = hxs.path('//fieldset/ul/li') #sites = hxs.path('//ul/li') for site in sites: title = site.path('a/text()').extract() link = site.path('a/@href').extract() desc = site.path('text()').extract() #print title, link, desc print title, link
如今咱們再次抓取dmoz.org,你將看到站點在輸出中被打印 ,運行命令
T:\tutorial>scrapy crawl dmoz
使用條目(Item)
Item 對象是自定義的python字典,使用標準字典相似的語法,你能夠獲取某個字段(即以前定義的類的屬性)的值:
>>> item = DmozItem() >>> item['title'] = 'Example title' >>> item['title'] 'Example title'
Spiders但願將其抓取的數據存放到Item對象中。爲了返回咱們抓取數據,spider的最終代碼應當是這樣:
from scrapy.spider import BaseSpider from scrapy.selector import HtmlXPathSelector from tutorial.items import DmozItem class DmozSpider(BaseSpider): 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): hxs = HtmlXPathSelector(response) sites = hxs.path('//fieldset/ul/li') #sites = hxs.path('//ul/li') items = [] for site in sites: item = DmozItem() item['title'] = site.path('a/text()').extract() item['link'] = site.path('a/@href').extract() item['desc'] = site.path('text()').extract() items.append(item) return items
如今咱們再次抓取 :
2012-07-16 14:52:36+0800 [dmoz] DEBUG: Scraped from <200 http://www.dmoz.org/Computers/Programming/Languages/Python/Books/> {'desc': [u'\n\t\t\t\n\t', u' \n\t\t\t\n\t\t\t\t\t\n - Free Python books and tutorials.\n \n'], 'link': [u'http://www.techbooksforfree.com/perlpython.shtml'], 'title': [u'Free Python books']} 2012-07-16 14:52:36+0800 [dmoz] DEBUG: Scraped from <200 http://www.dmoz.org/Computers/Programming/Languages/Python/Books/> {'desc': [u'\n\t\t\t\n\t', u' \n\t\t\t\n\t\t\t\t\t\n - Annotated list of free online books on Python scripting language. Topics range from beginner to advanced.\n \n '], 'link': [u'http://www.freetechbooks.com/python-f6.html'], 'title': [u'FreeTechBooks: Python Scripting Language']} 2012-07-16 14:52:36+0800 [dmoz] DEBUG: Crawled (200) <GET http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/> (referer: None) 2012-07-16 14:52:36+0800 [dmoz] DEBUG: Scraped from <200 http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/> {'desc': [u'\n\t\t\t\n\t', u' \n\t\t\t\n\t\t\t\t\t\n - A directory of free Python and Zope hosting providers, with reviews and ratings.\n \n'], 'link': [u'http://www.oinko.net/freepython/'], 'title': [u'Free Python and Zope Hosting Directory']} 2012-07-16 14:52:36+0800 [dmoz] DEBUG: Scraped from <200 http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/> {'desc': [u'\n\t\t\t\n\t', u' \n\t\t\t\n\t\t\t\t\t\n - Features Python books, resources, news and articles.\n \n'], 'link': [u'http://oreilly.com/python/'], 'title': [u"O'Reilly Python Center"]} 2012-07-16 14:52:36+0800 [dmoz] DEBUG: Scraped from <200 http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/> {'desc': [u'\n\t\t\t\n\t', u' \n\t\t\t\n\t\t\t\t\t\n - Resources for reporting bugs, accessing the Python source tree with CVS and taking part in the development of Python.\n\n'], 'link': [u'http://www.python.org/dev/'], 'title': [u"Python Developer's Guide"]}
保存抓取的數據
保存信息的最簡單的方法是經過Feed exports,命令以下:
T:\tutorial>scrapy crawl dmoz -o items.json -t json
全部抓取的items將以JSON格式被保存在新生成的items.json 文件中
在像本教程同樣的小型項目中,這些已經足夠。然而,若是你想用抓取的items作更復雜的事情,你能夠寫一個 Item Pipeline(條目管道)。由於在項目建立的時候,一個專門用於條目管道的佔位符文件已經隨着items一塊兒被創建,目錄在tutorial/pipelines.py。若是你只須要存取這些抓取後的items的話,就不須要去實現任何的條目管道。
結束語
本教程簡要介紹了Scrapy的使用,可是許多其餘特性並無說起。
對於基本概念的瞭解,請訪問Basic concepts
咱們推薦你繼續學習Scrapy項目的例子dirbot,你將從中受益更深,該項目包含本教程中提到的dmoz爬蟲。
Dirbot項目位於https://github.com/scrapy/dirbot
項目包含一個README文件,它詳細描述了項目的內容。
若是你熟悉git,你能夠checkout它的源代碼。或者你能夠經過點擊Downloads下載tarball或zip格式的文件。
另外這有一個代碼片段共享網站,裏面共享內容包括爬蟲,中間件,擴展應用,腳本等。網站名字叫Scrapy snippets,有好的代碼要記得共享哦:-)
本教程的源代碼下載:http://files.cnblogs.com/txw1958/scrapy_tutorial.rar