Python抓取框架Scrapy入門教程
我們將使用開放目錄項(xiàng)目(dmoz)作為抓取的例子。
這篇入門教程將引導(dǎo)你完成如下任務(wù):
創(chuàng)建一個(gè)新的Scrapy項(xiàng)目
定義提取的Item
寫一個(gè)Spider用來爬行站點(diǎn),并提取Items
寫一個(gè)Item Pipeline用來存儲提取出的Items
Scrapy是由Python編寫的。如果你是Python新手,你也許希望從了解Python開始,以期***的使用Scrapy。如果你對其它編程語言熟悉,想快速的學(xué)習(xí)Python,這里推薦 Dive Into Python。如果你對編程是新手,且想從Python開始學(xué)習(xí)編程,請看下面的對非程序員的Python資源列表。
新建工程
在抓取之前,你需要新建一個(gè)Scrapy工程。進(jìn)入一個(gè)你想用來保存代碼的目錄,然后執(zhí)行:
- Microsoft Windows XP [Version 5.1.2600]
- (C) Copyright 1985-2001 Microsoft Corp.
- T:\>scrapy startproject tutorial
- T:\>
這個(gè)命令會在當(dāng)前目錄下創(chuàng)建一個(gè)新目錄tutorial,它的結(jié)構(gòu)如下:
- 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
這些文件主要是:
scrapy.cfg: 項(xiàng)目配置文件
tutorial/: 項(xiàng)目python模塊, 呆會代碼將從這里導(dǎo)入
tutorial/items.py: 項(xiàng)目items文件
tutorial/pipelines.py: 項(xiàng)目管道文件
tutorial/settings.py: 項(xiàng)目配置文件
tutorial/spiders: 放置spider的目錄
定義Item
Items是將要裝載抓取的數(shù)據(jù)的容器,它工作方式像python里面的字典,但它提供更多的保護(hù),比如對未定義的字段填充以防止拼寫錯(cuò)誤。
它通過創(chuàng)建一個(gè)scrapy.item.Item類來聲明,定義它的屬性為scrpiy.item.Field對象,就像是一個(gè)對象關(guān)系映射(ORM).
我們通過將需要的item模型化,來控制從dmoz.org獲得的站點(diǎn)數(shù)據(jù),比如我們要獲得站點(diǎn)的名字,url和網(wǎng)站描述,我們定義這三種屬性的域。要做到這點(diǎn),我們編輯在tutorial目錄下的items.py文件,我們的Item類將會是這樣
- from scrapy.item import Item, Field
- class DmozItem(Item):
- title = Field()
- link = Field()
- desc = Field()
剛開始看起來可能會有些困惑,但是定義這些item能讓你用其他Scrapy組件的時(shí)候知道你的 items到底是什么。
我們的***個(gè)爬蟲(Spider)
Spider是用戶編寫的類,用于從一個(gè)域(或域組)中抓取信息。
他們定義了用于下載的URL的初步列表,如何跟蹤鏈接,以及如何來解析這些網(wǎng)頁的內(nèi)容用于提取items。
要建立一個(gè)Spider,你必須為scrapy.spider.BaseSpider創(chuàng)建一個(gè)子類,并確定三個(gè)主要的、強(qiáng)制的屬性:
name:爬蟲的識別名,它必須是唯一的,在不同的爬蟲中你必須定義不同的名字.
start_urls:爬蟲開始爬的一個(gè)URL列表。爬蟲從這里開始抓取數(shù)據(jù),所以,***次下載的數(shù)據(jù)將會從這些URLS開始。其他子URL將會從這些起始URL中繼承性生成。
parse():爬蟲的方法,調(diào)用時(shí)候傳入從每一個(gè)URL傳回的Response對象作為參數(shù),response將會是parse方法的唯一的一個(gè)參數(shù),
這個(gè)方法負(fù)責(zé)解析返回的數(shù)據(jù)、匹配抓取的數(shù)據(jù)(解析為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)
爬爬爬
為了讓我們的爬蟲工作,我們返回項(xiàng)目主目錄執(zhí)行以下命令
T:\tutorial>scrapy crawl dmoz
crawl dmoz 命令從dmoz.org域啟動(dòng)爬蟲。 你將會獲得如下類似輸出
- 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]的行 ,那對應(yīng)著我們的爬蟲。你可以看到start_urls中定義的每個(gè)URL都有日志行。因?yàn)檫@些URL是起始頁面,所以他們沒有引用(referrers),所以在每行的末尾你會看到 (referer: <None>).
有趣的是,在我們的 parse 方法的作用下,兩個(gè)文件被創(chuàng)建:分別是 Books 和 Resources,這兩個(gè)文件中有URL的頁面內(nèi)容。
發(fā)生了什么事情?
Scrapy為爬蟲的 start_urls屬性中的每個(gè)URL創(chuàng)建了一個(gè) scrapy.http.Request 對象 ,并將爬蟲的parse 方法指定為回調(diào)函數(shù)。
這些 Request首先被調(diào)度,然后被執(zhí)行,之后通過parse()方法,scrapy.http.Response 對象被返回,結(jié)果也被反饋給爬蟲。
提取Item
選擇器介紹
我們有很多方法從網(wǎng)站中提取數(shù)據(jù)。Scrapy 使用一種叫做 XPath selectors的機(jī)制,它基于 XPath表達(dá)式。如果你想了解更多selectors和其他機(jī)制你可以查閱資料http://doc.scrapy.org/topics/selectors.html#topics-selectors
這是一些XPath表達(dá)式的例子和他們的含義
/html/head/title: 選擇HTML文檔<head>元素下面的<title> 標(biāo)簽。
/html/head/title/text(): 選擇前面提到的<title> 元素下面的文本內(nèi)容
//td: 選擇所有 <td> 元素
//div[@class="mine"]: 選擇所有包含 class="mine" 屬性的div 標(biāo)簽元素
這只是幾個(gè)使用XPath的簡單例子,但是實(shí)際上XPath非常強(qiáng)大。如果你想了解更多XPATH的內(nèi)容,我們向你推薦這個(gè)XPath教程http://www.w3schools.com/XPath/default.asp
為了方便使用XPaths,Scrapy提供XPathSelector 類, 有兩種口味可以選擇, HtmlXPathSelector (HTML數(shù)據(jù)解析) 和XmlXPathSelector (XML數(shù)據(jù)解析)。 為了使用他們你必須通過一個(gè) Response 對象對他們進(jìn)行實(shí)例化操作。你會發(fā)現(xiàn)Selector對象展示了文檔的節(jié)點(diǎn)結(jié)構(gòu)。因此,***個(gè)實(shí)例化的selector必與根節(jié)點(diǎn)或者是整個(gè)目錄有關(guān) 。
Selectors 有三種方法
select():返回selectors列表, 每一個(gè)select表示一個(gè)xpath參數(shù)表達(dá)式選擇的節(jié)點(diǎn).
extract():返回一個(gè)unicode字符串,該字符串為XPath選擇器返回的數(shù)據(jù)
re(): 返回unicode字符串列表,字符串作為參數(shù)由正則表達(dá)式提取出來
嘗試在shell中使用Selectors
為了演示Selectors的用法,我們將用到 內(nèi)建的Scrapy shell,這需要系統(tǒng)已經(jīng)安裝IPython (一個(gè)擴(kuò)展python交互環(huán)境) 。
附IPython下載地址:http://pypi.python.org/pypi/ipython#downloads
要開始shell,首先進(jìn)入項(xiàng)目頂層目錄,然后輸入
T:\tutorial>scrapy shell http://www.dmoz.org/Computers/Programming/Languages/Python/Books/
輸出結(jié)果類似這樣:
- 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載入后,你將獲得回應(yīng),這些內(nèi)容被存儲在本地變量 response 中,所以如果你輸入response.body 你將會看到response的body部分,或者輸入response.headers 來查看它的 header部分。
Shell也實(shí)例化了兩種selectors,一個(gè)是解析HTML的 hxs 變量,一個(gè)是解析 XML 的 xxs 變量。我們來看看里面有什么:
- In [1]: hxs.select('//title')
- Out[1]: [<HtmlXPathSelector xpath='//title' data=u'<title>Open Directory - Computers: Progr'>]
- In [2]: hxs.select('//title').extract()
- Out[2]: [u'<title>Open Directory - Computers: Programming: Languages: Python: Books</title>']
- In [3]: hxs.select('//title/text()')
- Out[3]: [<HtmlXPathSelector xpath='//title/text()' data=u'Open Directory - Computers: Programming:'>]
- In [4]: hxs.select('//title/text()').extract()
- Out[4]: [u'Open Directory - Computers: Programming: Languages: Python: Books']
- In [5]: hxs.select('//title/text()').re('(\w+):')
- Out[5]: [u'Computers', u'Programming', u'Languages', u'Python']
- In [6]:
提取數(shù)據(jù)
現(xiàn)在我們嘗試從網(wǎng)頁中提取數(shù)據(jù)。
你可以在控制臺輸入 response.body, 檢查源代碼中的 XPaths 是否與預(yù)期相同。然而,檢查HTML源代碼是件很枯燥的事情。為了使事情變得簡單,我們使用Firefox的擴(kuò)展插件Firebug。更多信息請查看Using Firebug for scraping 和Using Firefox for scraping.
txw1958注:事實(shí)上我用的是Google Chrome的Inspect Element功能,而且可以提取元素的XPath。
檢查源代碼后,你會發(fā)現(xiàn)我們需要的數(shù)據(jù)在一個(gè) <ul>元素中,而且是第二個(gè)<ul>。
我們可以通過如下命令選擇每個(gè)在網(wǎng)站中的 <li> 元素:
hxs.select('//ul/li')
然后是網(wǎng)站描述:
hxs.select('//ul/li/text()').extract()
網(wǎng)站標(biāo)題:
hxs.select('//ul/li/a/text()').extract()
網(wǎng)站鏈接:
hxs.select('//ul/li/a/@href').extract()
如前所述,每個(gè)select()調(diào)用返回一個(gè)selectors列表,所以我們可以結(jié)合select()去挖掘更深的節(jié)點(diǎn)。我們將會用到這些特性,所以:
- sites = hxs.select('//ul/li')
- for site in sites:
- title = site.select('a/text()').extract()
- link = site.select('a/@href').extract()
- desc = site.select('text()').extract()
- print title, link, desc
Note
更多關(guān)于嵌套選擇器的內(nèi)容,請閱讀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.select('//fieldset/ul/li')
- #sites = hxs.select('//ul/li')
- for site in sites:
- title = site.select('a/text()').extract()
- link = site.select('a/@href').extract()
- desc = site.select('text()').extract()
- #print title, link, desc
- print title, link
現(xiàn)在我們再次抓取dmoz.org,你將看到站點(diǎn)在輸出中被打印 ,運(yùn)行命令
T:\tutorial>scrapy crawl dmoz
使用條目(Item)
Item 對象是自定義的python字典,使用標(biāo)準(zhǔn)字典類似的語法,你可以獲取某個(gè)字段(即之前定義的類的屬性)的值:
>>> item = DmozItem()
>>> item['title'] = 'Example title'
>>> item['title']
'Example title'
Spiders希望將其抓取的數(shù)據(jù)存放到Item對象中。為了返回我們抓取數(shù)據(jù),spider的最終代碼應(yīng)當(dāng)是這樣:
- 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.select('//fieldset/ul/li')
- #sites = hxs.select('//ul/li')
- items = []
- for site in sites:
- item = DmozItem()
- item['title'] = site.select('a/text()').extract()
- item['link'] = site.select('a/@href').extract()
- item['desc'] = site.select('text()').extract()
- items.append(item)
- return items
現(xiàn)在我們再次抓取 :
- 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"]}
保存抓取的數(shù)據(jù)
保存信息的最簡單的方法是通過Feed exports,命令如下:
T:\tutorial>scrapy crawl dmoz -o items.json -t json
所有抓取的items將以JSON格式被保存在新生成的items.json 文件中
在像本教程一樣的小型項(xiàng)目中,這些已經(jīng)足夠。然而,如果你想用抓取的items做更復(fù)雜的事情,你可以寫一個(gè) Item Pipeline(條目管道)。因?yàn)樵陧?xiàng)目創(chuàng)建的時(shí)候,一個(gè)專門用于條目管道的占位符文件已經(jīng)隨著items一起被建立,目錄在tutorial/pipelines.py。如果你只需要存取這些抓取后的items的話,就不需要去實(shí)現(xiàn)任何的條目管道。
結(jié)束語
本教程簡要介紹了Scrapy的使用,但是許多其他特性并沒有提及。
對于基本概念的了解,請?jiān)L問Basic concepts
我們推薦你繼續(xù)學(xué)習(xí)Scrapy項(xiàng)目的例子dirbot,你將從中受益更深,該項(xiàng)目包含本教程中提到的dmoz爬蟲。
Dirbot項(xiàng)目位于https://github.com/scrapy/dirbot
項(xiàng)目包含一個(gè)README文件,它詳細(xì)描述了項(xiàng)目的內(nèi)容。
如果你熟悉git,你可以checkout它的源代碼?;蛘吣憧梢酝ㄟ^點(diǎn)擊Downloads下載tarball或zip格式的文件。
另外這有一個(gè)代碼片斷共享網(wǎng)站,里面共享內(nèi)容包括爬蟲,中間件,擴(kuò)展應(yīng)用,腳本等。網(wǎng)站名字叫Scrapy snippets,有好的代碼要記得共享哦:-)
原文鏈接:http://www.cnblogs.com/txw1958/archive/2012/07/16/scrapy-tutorial.html
【編輯推薦】