1、查看python當前工作目錄
import os
>>>os.getcwd()
2、更改當前工作目錄
os.chdir('要設置的目錄')//同樣要導入import模塊
第一個Scrapy項目:
1、創建項目:
進入您打算存儲代碼的目錄中,運行下列命令:
scrapy startproject tutorial
該命令將會創建包含下列目錄的tutorial目錄:
tutorial/
scrapy.cfg
tutorial/
__init__.py
items.py
pipelines.py
settings.py
spiders/
__init__.py
...
這些文件分別是:
- scrapy.cfg:項目的配置文件。
- tutorial/:該項目的python模塊。之後您將在此加入代碼。
- tutorial/items.py:項目中的item文件。
- tutorial/pipelines.py:項目中的pipelines文件。
- tutorial/settings.py:項目的設置文件。
- tutorial/spiders/:放置spider代碼的目錄。
2、定義Item
Item是保存爬取道德數據的容器,使用方法和python字典類似,並且提供了額外保護機制來避免拼寫錯誤導致的未定義字段錯誤。
類似在ORM中做的一樣,你可以通過創建一個scrapy.Item 類,並且定義類型爲scrapy.Field 的類屬性來定義一個Item。
首先根據需要從dmoz.org獲取到的數據對item進行建模。我們需要從dmoz中獲取名字,url,以及網站的描述。對此,在item中定義相應的字段。編輯第二個tutorial目錄中的items.py文件(添加下列代碼):
import scrapy
class DmozItem(scrapy.Item):
title=scrapy.Field()
link=scrapy.Field()
desc=scrapy.Field()
通過定義item,你可以很方便的使用scrapy的其他方法。而這些方法需要知道你的item的定義。
3、編寫第一個爬蟲
Spider是用戶編寫用於從單個網站(或者一些網站)爬取數據的類。
其包含了一個用於下載的初始URL,如何跟進網頁中的鏈接以及如何分析頁面中的內容,提取生成item的方法。
爲了創建一個Spider,你必須繼承scrapy.Spider類,且定義以下三個屬性:
- name:用於區別Spider。該名字必須是唯一的,你不可以爲不同的Spider設定相同的名字。
- strat_urls:包含了Spider在啓動時進行爬取的url列表。因此,第一個被獲取到頁面將是其中之一。後續的URL則從初始的URL獲取到的數據中提取。
- parse():是spider的一個方法。被調用時,每個初始URL完成下載後生成的Response對象將會作爲唯一的參數傳遞給該函數,該方法負責解析返回的數據(response data),提取數據(生成item)以及需要進一步處理的URL的Request對象。
以下爲我們的第一個Spider代碼,保存在tutorial/tutorial/spiders目錄下的dmoz_spider.py文件中:
from scrapy.spider import Spider
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):
filename = response.url.split("/")[-2]
with open(filename, 'wb') as f:
f.write(response.body)
4、爬取
進入項目的根目錄,執行下列命令啓動spider:
scrapy crawl dmoz
crawl dmoz啓動用於爬取dmoz.org的spider,你將得到類似的輸出:
可以看到,有兩條輸出的log中包含定義在start_urls中的初始URL,並且與spider中是一一對應的。在log中可以看到其沒有指向其他頁面(referer:None)。
除此之外,就像我們在parse方法中指定的那樣,有兩個包含url所對應的內容的文件被創建了:Book和Resources。
剛剛發生了什麼?
scrapy爲Spider的start_urls屬性中的每個URL創建了scrapy.Request對象,並將parse方法作爲回調函數(callback)賦值給了Request。
Request對象經過調度,執行生成scrapy.http.Request對象並送回給spider的parse()方法。
5、提取Item
Selector選擇器簡介
從網頁中提取數據有很多方法。Scrapy使用了一種基於XPath和CSS表達式機制:Scrapy Selectors。關於selector和其他提取機制的信息請參考Selector文檔。
這裏給出XPath表達式的例子及對應的含義:
- /html/head/title:選擇HTML文檔中< head >標籤內的< title >元素。
- /html/head/title/text():選擇上面提到的< title >元素的文字。
- //td:選擇所有的< td >元素。
- //div[@class=”mine”]:選擇所有具有class=”mine”屬性的div元素。
上面僅僅是幾個簡單的XPath例子,XPath實際上要比這遠遠強大的多。如果你想了解的更多,可以參考這篇XPath教程。
爲了配合XPath,Scrapy除了提供了Selector之外,還提供了方法來避免每次從response中提取數據時生成selector的麻煩。
Seletor有四個基本的方法(相應的方法可以看到詳細的API文檔):
- xpath():傳入xpath表達式,返回該表達式所對應的所有節點的selector list列表。
- css():傳入CSS表達式,返回該表達式所對應的所有節點的selector list列表。
- extract():序列化該節點爲unicode字符串並返回list。
- re():根據傳入的正則表達式對數據進行提取,返回unicode字符串list列表。
在Shell中嘗試Selector選擇器
爲了介紹Selector的使用方法,接下來我們將要使用內置的Scrapy shell。Scrapy Shell需要你預裝好IPython(一個擴展的Python終端)。
你需要進入項目的根目錄,執行下列命令來啓動shell:
scrapy shell "http://www.dmoz.org/Computers/Programming/Languages/Python/Books/"
注意:當你在終端運行Scrapy時,請一定記得給url地址加上引號,否則包含參數的url(例如&字符)會導致Scrapy運行失敗。
shell輸出類似:
當shell載入後,你將得到一個包含response數據的本地response變量。輸入response.body將輸出response的包體,輸出response.headers可以看到response的包頭。
更爲重要的是,當輸入response.selector時,你將獲取到一個可以用於查詢返回數據的selector(選擇器),以及映射到response.selector.xpath()、response.selector.css()的快捷方法(shortcut):response.xpath()和response.css()。
同時,shell根據response提前初始化了變量sel。該selector根據response的類型自動選擇最合適的分析規則(XML vs HTML)。
讓我們來試試:
提取數據
現在,我們來嘗試從頁面中提取有用的數據。
你可以在終端中輸入response.body來觀察HTML源碼並確定合適的XPath表達式。不過,這任務非常無聊且不易。你可以考慮使用Firefox的Firebug擴展來使得工作更爲輕鬆。
在查看了網頁的源碼後,你會發現網站的信息是被包含在第二個< 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()調用返回selector組成的list,因此我們可以拼接更多的.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
在我們的spider中加入這段代碼:
from scrapy.spider import Spider
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):
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
使用item
Item對象是自定義的python字典。你可以使用標準的字典語法來獲取到其每個字段的值。(字段即是我們之前用Field賦值的屬性):
>>>item = DmozItem()
>>>item['title']= 'Example title'
>>>item['title']
'Example title'
一般來說,Spider會將爬取到的數據以Item對象返回。所以爲了將爬取的數據返回,我們最終的代碼是:
from scrapy.spider import Spider
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):
for sel in response.xpath('//ul/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
現在對dmoz.org進行爬取將會產生DmozItem對象:
保存爬取到的數據
最簡單存儲爬取的數據的方式是使用Feed exports:
scrapy crawl dmoz -o items.json
該命令將採用JSON格式對爬取的數據進行序列化,生成items.json文件。
在類似本篇教程中這樣小規模的項目中,這種存儲方式已經足夠。如果需要對爬取到的item做更多更爲複雜的操作,你可以編寫Item Pipeline。類似於我們在創建項目時對Item做的,用於你編寫自己的tutorial/pipeline.py也被創建。不過如果你僅僅想要保存item,你不需要實現任何的pipeline。