更適合Python爬蟲的MongoDB
MongoDB是一個(gè)基于分布式文件存儲(chǔ)的數(shù)據(jù)庫(kù),由C++語(yǔ)言編寫,旨在為Web應(yīng)用提供可擴(kuò)展的高性能數(shù)據(jù)存儲(chǔ)解決方案。和MySQL不同的,MongoDB是一個(gè)介于關(guān)系數(shù)據(jù)庫(kù)和非關(guān)系數(shù)據(jù)庫(kù)之間的產(chǎn)品,屬于非關(guān)系數(shù)據(jù)庫(kù),但是非常像關(guān)系型數(shù)據(jù)庫(kù)。
MongoDB功能比較豐富,非常適合在爬蟲開發(fā)中用作大規(guī)模數(shù)據(jù)的存儲(chǔ)。
安裝MongoDB
接下來(lái)開始進(jìn)行MongoDB的安裝,以Ubuntu和Windows為例。
1.Ubuntu下安裝和配置MongoDB
MongoDB提供了Linux平臺(tái)上32位和64位的安裝包,可以在官網(wǎng)進(jìn)行下載。下載地址:http://www.mongodb.org/downloads,如圖8-13
所示。
圖8-13 下載頁(yè)面
下載壓縮包,并解壓到新建的mongodb目錄下:
·mkdir mongodb·curl-O https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu1404-3.2.11.tgz·tar-zxvf mongodb-linux-x86_64-ubuntu1404-3.2.11.tgz·mv mongodb-linux-x86_64-ubuntu1404-3.2.11/mongodb/
MongoDB的可執(zhí)行文件位于mongodb-linux-x86_64-ubuntu1404-3.2.11文件夾下的bin目錄下,將bin目錄所在路徑添加到環(huán)境變量中。本人Ubuntu系統(tǒng)所使用的bin目錄路徑為/home/ubuntu/mongodb/mongodb-linux-x86_64-ubuntu1404-3.2.11/bin。
export PATH=/home/ubuntu/mongodb/mongodb-linux-x86_64-ubuntu1404-3.2.11/bin:$PATH
接著需要?jiǎng)?chuàng)建數(shù)據(jù)庫(kù)路徑,MongoDB的數(shù)據(jù)存儲(chǔ)默認(rèn)在data目錄的db目錄下。
mkdir -p /data/db
這個(gè)時(shí)候,進(jìn)入bin目錄,運(yùn)行mongod服務(wù),效果如圖8-14所示。
sudo ./mongod
圖8-14 啟動(dòng)mongodb服務(wù)
如果你創(chuàng)建數(shù)據(jù)庫(kù)的目錄不是在根目錄下,可以使用--dbpath參數(shù)指定。示例如下:
sudo ./mongod --dbpath /home/data/db
2.Windows下安裝和配置MongoDB
下載Windows下的安裝包,雙擊開始安裝,設(shè)置安裝路徑為D:\Program Files\MongoDB\Server\3.3\,安裝效果如圖8-15所示。
圖8-15 安裝mongoDB
安裝完mongoDB,將mongodb下的bin目錄添加到PATH環(huán)境變量中。最后配置mongoDB的存儲(chǔ)路徑,例如在D盤下建立D:\mongodb\data\db目錄結(jié)構(gòu)。
當(dāng)以上的工作都完成后,就可以在命令行中啟動(dòng)mongoDB服務(wù),輸入:mongod--dbpath D:\mongodb\data\db,運(yùn)行效果如圖8-16所示。
圖8-16 啟動(dòng)mongoDB
大家可以將這mongod--dbpath D:\mongodb\data\db做成一個(gè)批處理文件,方便使用。
除了在命令行中啟動(dòng),還可以將mongoDB注冊(cè)成一個(gè)服務(wù),在系統(tǒng)啟動(dòng)時(shí)自動(dòng)運(yùn)行。命令格式如下:
mongod --bind_ip yourIPadress --logpath <logpath> --logappend --dbpath <
dbpath> --port yourPortNumber --serviceName "YourServiceName" --
serviceDisplayName "YourServiceName" --install
mongoDB啟動(dòng)的參數(shù)說(shuō)明如表8-10所示。
表8-10 mongoDB啟動(dòng)的參數(shù)說(shuō)明
例如先將命令行窗口以管理員權(quán)限啟動(dòng),并輸入命令:
mongod--logpath“D:\mongodb\log.txt”--dbpath“D:\mongodb\data\db”--install。注冊(cè)完成后,接著輸入net start mongodb就可以啟動(dòng)服務(wù),效果如圖8-17所示。
圖8-17 注冊(cè)MongoDB服務(wù)
如果想連接MongoDB進(jìn)行數(shù)據(jù)庫(kù)操作,只需要在命令行中輸入
mongo,就可以進(jìn)入shell操作界面,如圖8-18所示。
圖8-18 MongoDB shell界面
MongoDB基礎(chǔ)
MongoDB屬于NoSQL數(shù)據(jù)庫(kù),里面的一些概念和MySQL等關(guān)系型數(shù)據(jù)庫(kù)大不相同。MongoDB中基本的概念是文檔、集合、數(shù)據(jù)庫(kù),下面通過(guò)表8-11將SQL概念和MongoDB中的概念進(jìn)行對(duì)比。
表8-11 SQL概念和MongoDB中的概念進(jìn)行對(duì)比
1.MongoDB中文檔、集合、數(shù)據(jù)庫(kù)的概念
文檔:文檔是MongoDB中數(shù)據(jù)的基本單元(即BSON),類似關(guān)系型數(shù)據(jù)庫(kù)中的行。文檔有唯一的標(biāo)識(shí)“_id”,數(shù)據(jù)庫(kù)可自動(dòng)生成。
文檔以key/value的方式,比如{“name”:“qiye”,“age”:20},可類比數(shù)據(jù)表的列名,以及列對(duì)應(yīng)的值。下面通過(guò)三個(gè)不同的文檔來(lái)說(shuō)明文檔的特性。
·文檔1:
·{“name”:“qiye”,“age”:24,“email”:[“qq_email”,“163_email”,
“gmail”],“chat”:{“qq”:“11111”,“weixin”:“11111”}}·文檔2:
·{“Name”:“qiye”,“Age”:24,“email”:[“qq_email”,“163_email”,
“gmail”],“chat”:{“qq”:“11111”,“weixin”:“11111”}}·文檔3:
·{“name”:“qiye”,“email”:[“qq_email”,“163_email”,“gmail”],
“age”:24,“chat”:{“qq”:“11111”,“weixin”:“11111”}}
主要說(shuō)明三個(gè)文檔的特性:
·文檔的鍵值對(duì)是有序的,順序不同文檔亦不同。
·文檔的值可以使字符串、整數(shù)、數(shù)組以及文檔等類型。
·文檔的鍵是用雙引號(hào)標(biāo)識(shí)的字符串(常見的);除個(gè)別例外,可用任務(wù)UTF-8字符。要求如下:鍵不能含有“\0”(空字符),這個(gè)字符用來(lái)標(biāo)識(shí)鍵的結(jié)尾;“.”和“$”被保留,存在特別含義,最好不要用來(lái)命名鍵名;以“_”開頭的鍵是保留的,建議不要使用。
·文檔區(qū)分大小寫以及值類型,比如:{“name”:“qiye”,“age”:24}和{“name”:“qiye”,“age”:“·24”},{“Name”:“qiye”,“Age”:24}和{“name”:“qiye”,“age”:“24”}都是不同的。
集合:集合在MongoDB中是一組文檔,類似關(guān)系型數(shù)據(jù)庫(kù)中的數(shù)據(jù)表。集合存在于數(shù)據(jù)庫(kù)中,集合沒(méi)有固定的結(jié)構(gòu),這意味著你在集合中可以插入不同格式和類型的數(shù)據(jù),比如{“name”:“qiye”,“age”:19}、{“name”:“admin”,“age”:22,“sex”:“1”},可以存在同一個(gè)集合當(dāng)中。合法的集合名為:
·集合名不能是空字符串。
·集合名不能含有“\0”字符(空字符),這個(gè)字符表示集合名的結(jié)尾。
·集合名不能以“system.”開頭,這是為系統(tǒng)集合保留的前綴。
·用戶創(chuàng)建的集合名字不能含有保留字符。有些驅(qū)動(dòng)程序的確支持在集合名里面包含保留字符,這是因?yàn)槟承┫到y(tǒng)生成的集合中包含該字符。除非你要訪問(wèn)這種系統(tǒng)創(chuàng)建的集合,否則千萬(wàn)不要在名字里出現(xiàn)“$”。
數(shù)據(jù)庫(kù):一個(gè)MongoDB中可以建立多個(gè)數(shù)據(jù)庫(kù),默認(rèn)數(shù)據(jù)庫(kù)為“db”,該數(shù)據(jù)庫(kù)存儲(chǔ)在data目錄中,這就是我們當(dāng)時(shí)為什么在data目錄下創(chuàng)建db文件夾。MongoDB的單個(gè)實(shí)例可以容納多個(gè)獨(dú)立的數(shù)據(jù)庫(kù),每一個(gè)都有自己的集合和權(quán)限,不同的數(shù)據(jù)庫(kù)也放置在不同的文件中。在MongoDB的shell窗口中,使用show dbs命令可以查看所有的數(shù)據(jù)庫(kù),使用db命令可以看當(dāng)前的數(shù)據(jù)庫(kù)。
2.MongoDB常見數(shù)據(jù)類型
MongoDB中常用的幾種數(shù)據(jù)類型如表8-12所示。
表8-12 MongoDB中常用的幾種數(shù)據(jù)類型
3.創(chuàng)建/刪除數(shù)據(jù)庫(kù)
MongoDB創(chuàng)建數(shù)據(jù)庫(kù)的語(yǔ)法格式如下:use DATABASE_NAME。如果數(shù)據(jù)庫(kù)不存在,則創(chuàng)建數(shù)據(jù)庫(kù),否則切換到指定數(shù)據(jù)庫(kù)。如果你想查看所有數(shù)據(jù)庫(kù),可以使用show dbs命令,但是數(shù)據(jù)庫(kù)中如果沒(méi)有數(shù)據(jù),就顯示不出來(lái)。
MongoDB刪除數(shù)據(jù)庫(kù)的語(yǔ)法格式如下:db.dropDatabase()。此語(yǔ)句可以刪除當(dāng)前數(shù)據(jù)庫(kù),你可以使用db命令查看當(dāng)前數(shù)據(jù)庫(kù)名。
下面在MongoDB的shell中新建一個(gè)名稱為pythonSpider的數(shù)據(jù)庫(kù),接著再刪除,如圖8-19所示。
圖8-19 創(chuàng)建/刪除數(shù)據(jù)庫(kù)
4.集合中文檔的增刪改查
上面我們已經(jīng)創(chuàng)建了一個(gè)pythonSpider數(shù)據(jù)庫(kù),以下均是在這個(gè)數(shù)據(jù)庫(kù)中進(jìn)行操作。文檔的數(shù)據(jù)結(jié)構(gòu)和JSON基本一樣,所有存儲(chǔ)在
集合中的數(shù)據(jù)都是BSON格式,BSON是類JSON的一種二進(jìn)制形式的存儲(chǔ)格式。
插入文檔。MongoDB使用insert()或save()方法向集合中插入文檔,語(yǔ)法如下:
db.COLLECTION_NAME.insert(document)
示例如下:
>db.python.insert({title: 'python', description: '動(dòng)態(tài)語(yǔ)言', url: 'http://www.python.org', tags: ['動(dòng)態(tài)', '編程', '腳本'], likes: 100 })
以上示例中python是我們的集合名稱,如果該集合不在該數(shù)據(jù)庫(kù)中,MongoDB會(huì)自動(dòng)創(chuàng)建該集合并插入文檔。插入的數(shù)據(jù)必須符合JSON格式。
查詢文檔。MongoDB使用find()方法從集合中查詢文檔。查詢數(shù)據(jù)的語(yǔ)法格式如下:
db.COLLECTION_NAME.find()
如果你需要以易讀的方式來(lái)讀取數(shù)據(jù),可以使用pretty()方法,語(yǔ)法格式如下:
db.COLLECTION_NAME.find().pretty()
示例如下:
> db.python.find()
上面的代碼用于查出python集合中的所有的文檔,相當(dāng)于select*ftom table。如果我們想進(jìn)行條件操作,就需要了解一下MongoDB中的條件語(yǔ)句和操作符,如表8-13所示。
表8-13 MongoDB中的條件語(yǔ)句和操作符
表中的例子都是單條件操作,下面說(shuō)一下條件組合,類似于and和or的功能。
MongoDB的find()方法可以傳入多個(gè)鍵(key),每個(gè)鍵以逗號(hào)隔開,來(lái)實(shí)現(xiàn)AND條件。語(yǔ)法格式如下:
>db. COLLECTION_NAME.find({key1:value1, key2:value2}).pretty()
查找python集合中l(wèi)ikes大于等于100且title等于python的文檔,示例如下:
>db.python.find({"likes": {$gte:100}, "title":"python"}).pretty()
運(yùn)行效果為:
{ "_id" : ObjectId("5833f31a386f0b6ffa7aedf4"), "title" : "python", "description" : "動(dòng)態(tài)語(yǔ)言", "url" : "http://www.python.org", "tags" : [ "動(dòng)態(tài)", "編程", "腳本"],"likes" : 100 }
MongoDB OR條件語(yǔ)句使用了關(guān)鍵字“$or”,語(yǔ)法格式如下:
>db.COLLECTION_NAME.find( { $or: [ {key1: value1}, {key2:value2} ] } ).pretty()
查找python集合中l(wèi)ikes大于等于100或者title等于python的文檔,示例如下:
> db. python.find( { $or: [ {"likes": {$gte:100}}, {"title":"python"} ] } ).pretty()
MongoDB AND和OR條件可以聯(lián)合使用,示例如下:
>db.python.find({"likes": {$gt:50}, $or: [{"description ": "動(dòng)態(tài)語(yǔ)言"},{"title": "python"}]}).pretty()
更新文檔。MongoDB使用update()和save()方法來(lái)更新集合中的文檔。首先看一下update()方法,用于更新已經(jīng)存在的文檔,方法原型如下:
db.collection.update( query, update, { upsert: boolean
multi: boolean
writeConcern: document
} )
參數(shù)分析:
·query:update的查詢條件,類似where子句。
·update:update的對(duì)象和一些更新的操作符等,類似于set后面的內(nèi)容。
·upsert:可選,這個(gè)參數(shù)的意思是如果不存在update的記錄,是否插入新的文檔,true為插入,默認(rèn)是false。
·multi:可選,mongodb默認(rèn)是false,只更新找到的第一條記錄,如果這個(gè)參數(shù)為true,就把按條件查出來(lái)多條記錄全部更新。
·writeConcern:可選,拋出異常的級(jí)別。
我們將title為python的文檔修改為title為“python”爬蟲,示例如下:
>db.python.update({'title':'python'},{$set:{'title':'python爬蟲'}})
以上語(yǔ)句只會(huì)修改第一條發(fā)現(xiàn)的文檔,如果你要修改多條相同的文檔,則需要設(shè)置multi參數(shù)為true。示例如下:
>db.python.update({'title':'python'},{$set:{'title':'python爬蟲'}},{multi:true})
save()方法通過(guò)傳入的文檔來(lái)替換已有文檔。方法原型如下:
db.collection.save( document, { writeConcern: document} )
參數(shù)說(shuō)明:
·document:文檔數(shù)據(jù)。
·writeConcern:可選,拋出異常的級(jí)別。
我們替換一下_id為5833f31a386f0b6ffa7aedf4的文檔數(shù)據(jù),示例如下:
>db.python.save( { "_id" : ObjectId("5833f31a386f0b6ffa7aedf4"), "title" : "Mongodb", "description" : "數(shù)據(jù)庫(kù)", "url" : "http://www.python.org", "tags" : [ "分布式", "mongo"
], "likes" : 100 } )
刪除文檔。MongoDB提供了remove()方法來(lái)刪除文檔,函數(shù)原型如下:
db.collection.remove( query, { justOne: boolean, writeConcern: document
} )
參數(shù)說(shuō)明:
·query:可選,刪除的文檔的條件。
·justOne:可選,如果設(shè)為true或1,則只刪除一個(gè)文檔。
·writeConcern:可選,拋出異常的級(jí)別。
將剛才更新的文檔刪除,也就是刪除title等于MongoDB的文檔,示例如下:
>db.python.remove({'title':'Mongodb'})
如果沒(méi)有query條件,意味著刪除所有文檔。
Python操作MongoDB
1.導(dǎo)入pymongo數(shù)據(jù)庫(kù)模塊
在導(dǎo)入pymongo之前,需要安裝pymongo模塊。使用pip安裝,
命令如下:
pip install pymongo
安裝成功后,導(dǎo)入pymongo模塊:
import pymongo
2.建立連接
pymongo模塊使用MongoClient對(duì)象來(lái)描述一個(gè)數(shù)據(jù)庫(kù)客戶端,創(chuàng)建對(duì)象所需的參數(shù)主要是host和port。常見的有三種形式:
·client=pymongo.MongoClient()
·client=pymongo.MongoClient(’localhost,‘27017)
·client=pymongo.MongoClient(’mongodb://localhost:27017/‘)第一種方式是連接默認(rèn)的主機(jī)IP和端口,第二種顯式指定IP和端口,第三種是采用URL格式進(jìn)行連接。
3.獲取數(shù)據(jù)庫(kù)
一個(gè)MongoDB實(shí)例可以支持多個(gè)獨(dú)立的數(shù)據(jù)庫(kù)。使用pymongo
時(shí),可以通過(guò)訪問(wèn)MongoClient的屬性的方式來(lái)訪問(wèn)數(shù)據(jù)庫(kù):
db = client.papers
如果數(shù)據(jù)庫(kù)名字導(dǎo)致屬性訪問(wèn)方式不能用(比如pa-pers),可以通過(guò)字典的方式訪問(wèn)數(shù)據(jù)庫(kù):
db = client['pa-pers']
4.獲取一個(gè)集合
一個(gè)collection指一組存在于MongoDB中的文檔,獲取Collection
方法與獲取數(shù)據(jù)庫(kù)方法一致:
collection = db.books
或者使用字典方式:
collection = db['books']
需要強(qiáng)調(diào)的一點(diǎn)是,MongoDB里的collection和數(shù)據(jù)庫(kù)都是惰性創(chuàng)建的,之前我們提到的所有命令實(shí)際并沒(méi)有對(duì)MongoDB Server進(jìn)行任何操作。直到第一個(gè)文檔插入后,才會(huì)創(chuàng)建,這就是為什么在不插入文檔之前,使用show dbs查看不到之前創(chuàng)建的數(shù)據(jù)庫(kù)。
5.插入文檔
數(shù)據(jù)在MongoDB中是以JSON類文件的形式保存起來(lái)的。在
PyMongo中用字典來(lái)代表文檔,使用insert()方法插入文檔,示例如下:
book = {"author": "Mike", "text": "My first book!", "tags": ["爬蟲", "python", "網(wǎng)絡(luò)"], "date": datetime.datetime.utcnow()} book_id= collection .insert(book)
文件被插入之后,如果文件內(nèi)沒(méi)有_id這個(gè)鍵值,那么系統(tǒng)自動(dòng)添加一個(gè)到文件里。這是一個(gè)特殊鍵值,它的值在整個(gè)collection里是唯一的。insert()返回這個(gè)文件的_id值。
除了單個(gè)文件插入,也可以通過(guò)給insert()方法傳入可迭代的對(duì)象作為第一個(gè)參數(shù),進(jìn)行批量插入操作。這將會(huì)把迭代表中的每個(gè)文件插入,而且只向Server發(fā)送一條命令:
books = [{"author": "Mike", "text": "My first book!", "tags": ["爬蟲", "python", "網(wǎng)絡(luò)"], "date": datetime.datetime.utcnow()},{"author": "qiye", "text": "My sec book!",
這個(gè)常用于Web應(yīng)用,可以從URL抽取id,從數(shù)據(jù)庫(kù)中進(jìn)行查詢。
如果想獲取多個(gè)文檔,可以使用find()方法。find()返回一個(gè)Cursor實(shí)例,通過(guò)它我們可以獲取每個(gè)符合查詢條件的文檔。示例如下:
for book in collection.find():
print book
與使用find_one()時(shí)候相同,可以傳入條件來(lái)限制查詢結(jié)果。
比如查詢所有作者是qiye的書:
for book in collection.find({"author": "qiye"}):
print book
如果只想知道符合查詢條件的文件有多少,可以用count()操作,而不必進(jìn)行完整的查詢。示例如下:
collection.find({"author": "qiye"}).count()
7.修改文檔
MongoDB可以使用update()和save()方法來(lái)更新文檔,和之前在MongoDB shell中的操作類似。示例如下:
collection.update({"author": "qiye"},{"$set":{"text":"python book"}})
8.刪除文檔
MongoDB使用remove()方法來(lái)刪除文檔。示例如下:
collection.remove({"author": "qiye"})
小結(jié)
本章講解了三種數(shù)據(jù)庫(kù)的基礎(chǔ)操作和Python調(diào)用方式,相對(duì)比較簡(jiǎn)單。熟練掌握數(shù)據(jù)庫(kù)的操作,對(duì)之后的大數(shù)據(jù)存儲(chǔ)非常有益。但是本章的知識(shí)只適合初級(jí)者的需要,對(duì)于億萬(wàn)級(jí)數(shù)據(jù)的存儲(chǔ)和搜索優(yōu)化,需要大家更多的努力。
如對(duì)本文有疑問(wèn),請(qǐng)?zhí)峤坏浇涣髡搲?,廣大熱心網(wǎng)友會(huì)為你解答!! 點(diǎn)擊進(jìn)入論壇