Scrapy爬虫入门系列2 示例教程
本來想爬下http://www.alexa.com/topsites/countries/CN?總排名的,但是收費了
只爬了50條數據:
我們使用dmoz分類目錄作為抓取例子。 本教程將引導你完成如下任務:
目錄?[隱藏]?
|
新建工程
進入你想保存代碼的目錄,然后執行:
scrapy startproject tutorial其中,tutorial為項目名稱。
這個命令會在當前目錄下創建一個新目錄tutorial,內容如下:
- scrapy.cfg: 項目配置文件
- tutorial/: 項目python模塊, 待會代碼將從這里導入
- tutorial/items.py: 項目items文件
- tutorial/pipelines.py: 項目管道文件
- tutorial/settings.py: 項目設置文件
- tutorial/spiders: 放置spider的目錄
定義Item
Items是裝載抓取數據的容器。
通過創建一個scrapy.item的類來聲明,用scrpy.Field對象定義它的屬性.
比如我們要獲得站點的名字,url和網站描述,我們定義這三種屬性的域。
編輯items.py文件:
import scrapy ? class DmozItem(scrapy.Item): # define the fields for your item here like:# name = scrapy.Field() title = scrapy.Field() link = scrapy.Field() desc = scrapy.Field()定義這些item能讓你用其他Scrapy組件的時候知道你的 items到底是什么。
我們的第一個爬蟲(Spider)
首先要獲取整個網頁的所有內容,然后再取出其中有用的部分。
定義用于下載的URL初步列表,如何跟蹤鏈接,以及如何解析這些網頁的內容來提取items。
要建立一個Spider,你必須為scrapy.spider創建一個子類,并確定三個主要的屬性:
- name:爬蟲的名字,它必須是唯一的,不同的爬蟲必須定義不同的名字.
- start_urls:爬蟲開始爬的一個URL列表。爬蟲從這里開始抓取數據,所以,第一次下載的數據將會從這些URLS開始。其他子URL將會從這些起始URL中生成。
- parse():爬蟲的方法,調用時,傳入每一個URL返回的Response對象作為參數,response是parse方法的唯一的一個參數。
這個方法負責解析返回的數據、匹配抓取的數據(解析為item)并跟蹤更多的URL。
下面是我們的第一只爬蟲代碼,將其命名為dmoz_spider.py并保存在tutorial\spiders目錄下。
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)allow_domains規定爬蟲只爬取這個域名下的網頁。
從parse函數可以看出,兩個文件被創建:分別是 Books 和 Resources(因為split分割后最后2個元素是'Books',?'',L[-2]表示反向讀取;讀取倒數第二個元素),保存的是網頁的源代碼
爬爬爬
為了讓我們的爬蟲工作,我們返回項目根目錄執行以下命令:
scrapy crawl dmozexceptions.ImportError:?No?module?named?_sqlite3解決:yum?-y?install?sqlite-devel??find?/?-name?_sqlite3.so/usr/lib64/python2.6/lib-dynload/_sqlite3.sowhereis?pythoncp?/usr/lib64/python2.6/lib-dynload/_sqlite3.so?/usr/local/lib/python2.7/lib-dynload/輸入python命令后,
crawl dmoz 命令從dmoz.org域啟動爬蟲。 你將會獲得如下類似輸出
2014-06-2318:13:07-0400 [scrapy] INFO: Scrapy started (bot: tutorial)2014-06-2318:13:07-0400 [scrapy] INFO: Optional features available: ...2014-06-2318:13:07-0400 [scrapy] INFO: Overridden settings: {}2014-06-2318:13:07-0400 [scrapy] INFO: Enabled extensions: ...2014-06-2318:13:07-0400 [scrapy] INFO: Enabled downloader middlewares: ...2014-06-2318:13:07-0400 [scrapy] INFO: Enabled spider middlewares: ...2014-06-2318:13:07-0400 [scrapy] INFO: Enabled item pipelines: ...2014-06-2318:13:07-0400 [dmoz] INFO: Spider opened2014-06-2318:13:08-0400 [dmoz] DEBUG: Crawled (200)<GET http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/>(referer: None)2014-06-2318:13:09-0400 [dmoz] DEBUG: Crawled (200)<GET http://www.dmoz.org/Computers/Programming/Languages/Python/Books/>(referer: None)2014-06-2318:13:09-0400 [dmoz] INFO: Closing spider (finished)最后一句INFO: Closing spider (finished)表明爬蟲已經成功運行并且自行關閉了。
注意包含?[dmoz]的行 ,那對應著我們的爬蟲運行的結果。你可以看到start_urls中定義的每個URL都有日志行。因為這些URL是起始頁面,所以他們沒有引用(referrers),所以在每行的末尾你會看到 (referer: <None>).
在parse方法的作用下,兩個文件被創建:分別是 Books 和 Resources。
發生了什么
那么在剛才的電閃雷鳴之中到底發生了什么呢?
Scrapy為爬蟲start_urls屬性中的每個URL創建了一個 scrapy.Request 對象, 并將爬蟲的parse 方法指定為回調函數。
然后這些 Request被調度并執行,之后通過parse()方法返回scrapy.http.Response 對象,并反饋給爬蟲。
[編輯]提取Item
[編輯]選擇器介紹
有多種方法從網頁中提取數據。
Scrapy 使用基于?XPath的機制,或稱為Scrapy Selectors的CSS表達式。
如果你想了解更多selectors和其他機制,請參見:http://doc.scrapy.org/en/latest/topics/selectors.html#topics-selectors
下面是一些XPath表達式的例子及他們的含義
- /html/head/title: 選擇HTML文檔<head>元素下面的<title> 標簽。
- /html/head/title/text(): 選擇前面提到的<title> 元素下面的文本內容
- //td: 選擇所有 <td> 元素
- //div[@class="mine"]: 選擇所有包含 class="mine" 屬性的div 標簽元素
這只是幾個使用XPath的簡單例子,實際上XPath非常強大。
如果你想了解更多XPATH的內容,參見:http://www.w3schools.com/XPath/default.asp?或http://www.w3school.com.cn/xpath/
為了方便使用XPaths,Scrapy提供了一個 Selector class and convenient shortcuts to avoid instantiating selectors yourself everytime you need to select something from a response.
You can see selectors as objects that represent nodes in the document structure. So, the first instantiated selectors are associated with the root node, or the entire document.
Selectors擁有4個 basic methods:
- xpath():返回一系列的selectors,xpath參數表達式選擇的節點
- css():返回一系列的selectors,css參數表達式選擇的節點
- extract(): returns a unicode string with the selected data. 返回一個unicode字符串,為選中的數據
- re():返回一串unicode字符串,為使用正則表達式抓取出來的內容
[編輯]嘗試在shell中使用Selectors
為了演示Selectors的用法,我們將用到 內建的Scrapy shell,這需要系統已經安裝IPython (一個擴展的python交互環境) 。
進入項目根目錄,然后輸入:
scrapy shell "http://www.dmoz.org/Computers/Programming/Languages/Python/Books/"注意url要用雙引號括起來。單引號也可以
Shell載入后,你將獲得response回應,存儲在本地變量 response 中,所以如果你輸入response.body 你將會看到response的body部分,也就是抓取到的頁面內容源代碼,或者輸入response.headers 來查看它的 header部分。
response.headers ? {'Cteonnt-Length': ['33758'], 'Content-Language': ['en'], 'Set-Cookie': ['JSESSIONID=D3A77F68542FFABB68E306C30D69FD4B; Path=/'], 'Server': ['Apache'], 'Date': ['Sun, 13 Jul 2014 04:21:20 GMT'], 'Content-Type': ['text/html;charset=UTF-8']}現在就像是一大堆沙子握在手里,里面藏著我們想要的金子,所以下一步,就是用篩子搖兩下,把雜質篩出去,選出關鍵的內容。
selector就是這樣一個篩子。
現在的Shell為我們準備好的selector對象是sel,可以根據返回的數據類型自動選擇最佳的解析方案(XML or HTML)。
More important, if you type response.selector you will access a selector object you can use to query the response, and convenient shortcuts like response.xpath() and response.css() mapping to response.selector.xpath() and response.selector.css()
In [1]: response.xpath('//title') Out[1]: [<Selector xpath='//title'data=u'<title>Open Directory - Computers: Progr'>] ? In [2]: response.xpath('//title').extract() Out[2]: [u'<title>Open Directory - Computers: Programming: Languages: Python: Books</title>'] ? In [3]: response.xpath('//title/text()') Out[3]: [<Selector xpath='//title/text()'data=u'Open Directory - Computers: Programming:'>] ? In [4]: response.xpath('//title/text()').extract() Out[4]: [u'Open Directory - Computers: Programming: Languages: Python: Books'] ? In [5]: response.xpath('//title/text()').re('(\w+):') //匹配單詞后面是冒號的 Out[5]: [u'Computers', u'Programming', u'Languages', u'Python']從上面可以看出,加了text()后再extract() ,會沒有html的標簽:<title>
使用response.xpath('//title')就能把這個標簽取出來,用extract()和text()還可以進一步做處理。
下面列出了最有用的路徑表達式:
- nodename 選取此節點的所有子節點。
- / 從根節點選取。
- // 從匹配選擇的當前節點選擇文檔中的節點,而不考慮它們的位置。
- . 選取當前節點。
- .. 選取當前節點的父節點。
- @ 選取屬性。
[編輯]提取數據
現在我們嘗試從網頁中提取一些數據。
你可以在控制臺輸入 response.body, 檢查源代碼中的 XPaths 是否與預期相同。然而,檢查HTML源代碼是件很枯燥的事情。
為了使事情變得簡單,我們使用Firefox的擴展插件Firebug。更多信息請查看http://doc.scrapy.org/en/latest/topics/firebug.html#topics-firebug?和http://doc.scrapy.org/en/latest/topics/firefox.html#topics-firefox
檢查源代碼后,你會發現我們需要的數據在一個<ul>元素中,我們可以通過如下命令來抓取這個<li>標簽:sel.xpath('//ul/li') //選取所有ul,而不管他們的位置然后是網站描述:
sel.xpath('//ul/li/text()').extract()網站標題:
sel.xpath('//ul/li/a/text()').extract()網站鏈接:
sel.xpath('//ul/li/a/@href').extract()如:
>>>response.xpath('//ul/li[1]/text()').extract() >>>response.xpath('//ul/li[1]/a/text()').extract()輸出如下:
[u'Top', u'Computers: Programming: Languages: Python: Resources', u'German', u'Core Python Programming']為所有ul下第一個li的a標簽文字,一個文檔源文件中可能有多個ul,
輸入Ctrl+D退出
response.xpath('//ul/li[1]/a/@href').extract() [u'/', u'/Computers/Programming/Languages/Python/Resources/', u'/World/Deutsch/Computer/Programmieren/Sprachen/Python/B%C3%BCcher/', u'http://www.pearsonhighered.com/educator/academic/product/0,,0130260363,00%2Ben-USS_01DBC.html']如前所述,每個path()調用返回一個selectors列表,所以我們可以結合path()去挖掘更深的節點:
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更多關于嵌套選擇器的內容,請閱讀?Nesting selectors?和Working with relative XPaths
我們用shell做了這么久的實戰,最后我們可以把前面學習到的內容應用到dmoz_spider這個爬蟲中。
將代碼添加到爬蟲中:
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再次抓取dmoz.org,你將看到輸出,運行命令:
scrapy crawl dmoz為了查看方便,可以只print title
成功的抓到了所有的標題。但是好像不太對啊,怎么Top,Python這種導航欄也抓取出來了呢?
我們只需要紅圈中的內容:
看來是我們的xpath語句有點問題,沒有把我們需要的項目名稱抓取出來。 ? 因為有多個ul
審查網頁源代碼元素發現我們需要的<ul>具有class='directory-url'的屬性,那么只要把xpath語句改成sel.xpath('//ul[@class="directory-url"]/li')即可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[@class="directory-url"]/li'): title = sel.xpath('a/text()').extract() link = sel.xpath('a/@href').extract() desc = sel.xpath('text()').extract()print title成功抓出了所有的標題:
使用Item
Item對象是自定義的python字典,可以使用標準字典語法獲取某個屬性的值:
>>> item = DmozItem()>>> item['title'] = 'Example title'>>> item['title']'Example title'作為一只爬蟲,Spiders希望能將其抓取的數據存放到Item對象中。為了返回我們抓取到的數據,spider的最終代碼應當是這樣:
import scrapy ? from tutorial.items import DmozItem ? 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[@class="directory-url"]/li'): item = DmozItem() item['title']= sel.xpath('a/text()').extract() item['link']= sel.xpath('a/@href').extract() item['desc']= sel.xpath('text()').extract()yield item重新運行scrapy crawl dmoz即可看到和上面一樣的效果。
[編輯]保存抓取的數據
保存信息的最簡單的方法是通過Feed exports,命令如下:
scrapy crawl dmoz -o items.json -t json-o 后面是導出文件名,-t 后面是導出類型。
所有抓取的items將以JSON格式被保存在新生成的items.json 文件中。(為了方便顯示,在item中刪去了除了title之外的屬性)
像本教程這樣的小型項目,這些已經足夠。然而,如果你想用抓取的items做更復雜的事情,你可以寫一個 Item Pipeline(條目管道)。
因為在項目創建的時候,一個專門用于條目管道的占位符文件已經隨著items一起被建立,目錄在tutorial/pipelines.py。
如果你只需要存取這些抓取后的items的話,就不需要去實現任何的條目管道。
[編輯]結束語
本教程簡要介紹了Scrapy的使用,但是許多其他特性并沒有提及。
我們將在后面的系列中一一舉例說明。
[編輯]藝搜參考
http://doc.scrapy.org/en/latest/intro/tutorial.html#intro-tutorial
http://www.cnblogs.com/txw1958/archive/2012/07/16/scrapy-tutorial.html
http://blog.csdn.net/pleasecallmewhy/article/details/19642329
總結
以上是生活随笔為你收集整理的Scrapy爬虫入门系列2 示例教程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 像这样玩C#
- 下一篇: Linux基础优化之SElinux和ip