爬蟲——實戰完整版
mongodb操作
1 import pymongo 2 3 #連線資料庫例項(連線資料庫)---》獲取相應資料庫---》獲取相應collection集合(表) 4 client = pymongo.MongoClient(host='localhost',port=27017) 5 6 db = client.test#也可用字典形式操作,如下 7 # db = client["test"] 8 9 collection= db.students#也可用字典形式操作,如下 10 # collection = db["students"] 11 12 student1 = { 13'id':'001', 14'name':'haha', 15'age':20, 16'gender':'male' 17 } 18 student2 = { 19'id': '002', 20'name': 'Mike', 21'age': 41, 22'gender': 'male' 23 } 24 #-------------------------------------------------------------------------- 25#插入 insert into students(...) values('002',...) 26#若不指定 _id 欄位,系統預設會生成一個ObjectId 27#可插入一條或多條資料(列表形式),python3不推薦使用insert 28 # collection.insert([student1,student2]) 29 # collection.insert(student1) 30 31#官方推薦,分開使用,返回值不是ObjectId,而是InsertOneResult物件,我們可以呼叫其inserted_id屬性獲取_id。 32 # result = collection.insert_one(student2) 33 # print(result) 34 # print(result.inserted_id) 35 36 # result = collection.insert_many([student1,student2]) 37 # print(result) 38 # print(result.inserted_ids) 39 40 #------------------------------------------------------------------ 41#查詢 select * from students where id=002 42#查詢條件使用字典,可使用多欄位,find是多條查詢 43 # result_find = collection.find({"name":"lijingbo","age":20}) 44 # print(result_find.next())#返回一個遊標,遊標相當於迭代器,可使用next()獲取一條結果,或者使用迴圈遍歷等,遍歷結果是字典 45#find_one:單個查詢,返回字典型別 46 # result = collection.find_one({'age':20}) 47 # print(result,type(result)) 48#結合關係符進行查詢:$gt,$lt,$gte,$lte,$ne,$in,$nin 49 # result = collection.find({'age':{'$gt':18}}) 50 # result = collection.find({'age':{'$in':[18,41]}}) 51#結合特殊符號查詢:$regex 52 # result = collection.find({'name':{'$regex':'^M.*'}})#正則 53 # result = collection.find({'name':{'$exists':True}})#查詢含有name屬性的 54 # result = collection.find({'age':{'$mod':[5,0]}})#求模,對5取餘=0 55 # result = collection.find({'$where':'obj.age==20'})#查詢age為20的,obj是自身 56 # result = collection.find({'age':20}).count()#統計 57 # result = collection.find().sort('age',pymongo.ASCENDING)#按照指定欄位升序排列 58 # result = collection.find().sort('age',pymongo.DESCENDING)#按照指定欄位升序排列 59 # result = collection.find().sort('age',pymongo.DESCENDING).skip(2)#按照指定欄位升序排列,偏移2個(就是把最前面兩個跳過去了) 60 # result = collection.find().sort('age',pymongo.DESCENDING).skip(2).limit(5)#限制得到5 61 # print(result) 62 # for r in result: 63 #print(r['name'],r['age']) 64 65 #---------------------------------------------------------- 66#更新 update students set name=haha where id=001 67#引數1:查詢條件(字典);引數2:更新值(字典,鍵:'$set',值:字典【也可直接使用外部字典】) 68#其他:upsert預設為False,為True時——若更新的原資料不存在,則插入資料 69#multi——預設為False只更新查詢到的第一條資料,為True時:更新全部查詢到的資料 70# $set:是mongodb內建函式,覆蓋原始資料 71 # collection.update({"id":"001"},{'$set':{'age':34}},upsert=True,multi=True) 72 # print(collection.find().next()) 73#上面的官方也不推薦,可以使用下面的 74 # result = collection.update_one({'name':'haha'},{'$set':{'age':18}}) 75 # result = collection.update_many({'name':'haha'},{'$set':{'age':18}}) 76 # print(result)#只修改一條資料,若該資料不修改就和修改條件一樣了,那有可能修改數為0 77 # print(result.matched_count,result.modified_count) 78 79 80 #----------------------------------------------------- 81#刪除,remove方法官方不推薦 82 # collection.remove({"id":"001"},justOne=1) 83 # result = collection.delete_one({'name':'Mike'}) 84 # result = collection.delete_many({'name':'Mike'}) 85 # print(result) 86 # print(result.deleted_count) 87 88 #--------------------------------------------------- 89#組合方法 90 # result = collection.find_one_and_delete({'name':'haha'}) 91 # result = collection.find_one_and_update({'name':'haha'},{'$set':{'age':45}}) 92 # result = collection.find_one_and_replace({'name':'haha'}) 93 # print(result)
MongoCache
將資料以字典的特性儲存快取到mongodb資料庫
匯入類庫
import pickle,zlib#物件序列化壓縮資料 from datetime import datetime,timedelta#設定快取超時間間隔 from pymongo import MongoClient from bson.binary import Binary#MongoDB儲存二進位制的型別
建立MongoCache類
-
初始化init
- 連線mongodb資料庫
- 連線資料庫cache例項(沒有則建立)
- 連線集合webpage(沒有則建立)
- 建立timestamp索引,設定超時時間為30天
-
重寫
__setitem__
- 資料經過pickle序列化
- zlib壓縮
- 經Binary轉化為mongodb需要的格式
- 新增格林威治時間
- 網址為鍵_id,結果為值,存入mongodb
使用下載的url(路由)作為key,存入系統預設的_id欄位,更新資料庫,若存在則更新,不存在則插入,_id唯一就可實現爬取的資料去重
用字典的形式向資料庫新增一條快取(資料)
-
重寫
__getitem__
- 將快取資料按照item作為key取出(key仍然是下載的url)
- 根據_id(url)查詢(find_one)結果
- 解壓縮,反序列化
-
重寫
__contains__
__getitem__
-
方法
clear
-
清空該集合中的資料
1 import pickle,zlib#物件序列化壓縮資料 2 from datetime import datetime,timedelta#設定快取超時間間隔 3 from pymongo import MongoClient 4 from bson.binary import Binary#MongoDB儲存二進位制的型別 5 from http_ljb.tiebaspider import TiebaSpider 6 from http_ljb.qiushispider import QiushiSpider 7 8 class MongoCache: 9def __init__(self,client=None,expires=timedelta(days=30)): 10''' 11初始化函式 12:param client: 資料庫連線(資料庫例項) 13:param expires: 超時時間 14''' 15self.client = MongoClient('localhost',27017) 16self.db = self.client.cache#建立名為cache的資料庫 17web_page = self.db.webpage#建立集合webpage並賦值給變數 18#建立timestamp索引,設定超時時間為30天,total_seconds會將days轉為秒 19self.db.webpage.create_index('timestamp',expireAfterSeconds=expires.total_seconds()) 20 21def __setitem__(self, key, value): 22''' 23用字典的形式向資料庫新增一條快取(資料) 24:param key: 快取的鍵 25:param value: 快取的值 26:return: 27''' 28#資料---》pickle序列化---》zlib壓縮---》Binary轉化為mondodb需要的格式,使用格林威治時間 29record = {'result':Binary(zlib.compress(pickle.dumps(value))),'timestamp':datetime.utcnow()} 30#使用下載的url(路由)作為key,存入系統預設的_id欄位,更新資料庫,若存在則更新,不存在則插入,_id唯一就可實現爬取的資料去重 31self.db.webpage.update({'_id':key},{'$set':record},upsert=True) 32 33def __getitem__(self, item): 34''' 35將快取資料按照item作為key取出(key仍然是下載的url) 36:param item:鍵 37:return: 38''' 39record = self.db.webpage.find_one({'_id':item}) #查找出來就不是Binary了,不用進行轉化 40if record: 41return pickle.loads(zlib.decompress(record['result'])) #解壓縮,反序列化 42else: 43raise KeyError(item + 'does not exist')#查詢不到就丟擲鍵錯誤異常 44 45def __contains__(self, item): 46''' 47當呼叫in,not in ,會自動呼叫該方法判斷連結對應網址是否在資料庫中 48:param item: 下載的url連結(路由) 49:return: 50''' 51try: 52self[item]#這一步會呼叫__getitem__,找不到__getitem__會丟擲異常,在這裡進行捕獲異常只返回False,否則返回True 53except KeyError: 54return False 55else: 56return True 57 58def clear(self): 59''' 60清空該集合中的資料 61:return: 62''' 63self.db.webpage.drop()
-
清空該集合中的資料
爬取例項
呼叫貼吧爬取程式碼和百科爬取程式碼,使用mongodb儲存爬取資料
- 匯入爬取類
- 建立新類並繼承自爬取類
-
重寫儲存方法
- 建立MongoCache物件
- 網址為鍵,資料為值,以字典形式存入mongodb
-
重寫run方法
-
在儲存時,需多傳一個網址引數(為了在儲存方法中對應儲存)
1 import pickle,zlib#物件序列化壓縮資料 2 from datetime import datetime,timedelta#設定快取超時間間隔 3 from pymongo import MongoClient 4 from bson.binary import Binary#MongoDB儲存二進位制的型別 5 from http_ljb.tiebaspider import TiebaSpider 6 from http_ljb.qiushispider import QiushiSpider 7 8 class MongoCache: 9def __init__(self,client=None,expires=timedelta(days=30)): 10''' 11初始化函式 12:param client: 資料庫連線(資料庫例項) 13:param expires: 超時時間 14''' 15self.client = MongoClient('localhost',27017) 16self.db = self.client.cache#建立名為cache的資料庫 17web_page = self.db.webpage#建立集合webpage並賦值給變數 18#建立timestamp索引,設定超時時間為30天,total_seconds會將days轉為秒 19self.db.webpage.create_index('timestamp',expireAfterSeconds=expires.total_seconds()) 20 21def __setitem__(self, key, value): 22''' 23用字典的形式向資料庫新增一條快取(資料) 24:param key: 快取的鍵 25:param value: 快取的值 26:return: 27''' 28#資料---》pickle序列化---》zlib壓縮---》Binary轉化為mondodb需要的格式,使用格林威治時間 29record = {'result':Binary(zlib.compress(pickle.dumps(value))),'timestamp':datetime.utcnow()} 30#使用下載的url(路由)作為key,存入系統預設的_id欄位,更新資料庫,若存在則更新,不存在則插入,_id唯一就可實現爬取的資料去重 31self.db.webpage.update({'_id':key},{'$set':record},upsert=True) 32 33def __getitem__(self, item): 34''' 35將快取資料按照item作為key取出(key仍然是下載的url) 36:param item:鍵 37:return: 38''' 39record = self.db.webpage.find_one({'_id':item}) #查找出來就不是Binary了,不用進行轉化 40if record: 41return pickle.loads(zlib.decompress(record['result'])) #解壓縮,反序列化 42else: 43raise KeyError(item + 'does not exist')#查詢不到就丟擲鍵錯誤異常 44 45def __contains__(self, item): 46''' 47當呼叫in,not in ,會自動呼叫該方法判斷連結對應網址是否在資料庫中 48:param item: 下載的url連結(路由) 49:return: 50''' 51try: 52self[item]#這一步會呼叫__getitem__,找不到__getitem__會丟擲異常,在這裡進行捕獲異常只返回False,否則返回True 53except KeyError: 54return False 55else: 56return True 57 58def clear(self): 59''' 60清空該集合中的資料 61:return: 62''' 63self.db.webpage.drop() 64 65 class TiebaMongo(TiebaSpider): 66def save_result(self, result,url_str): 67""" 68重寫父類的該方法,將資料儲存到資料庫 69:param result: 70:param url_str: 71:return: 72""" 73mc = MongoCache() 74mc[url_str] = result 75 76def run(self): 77url_lists = self.make_url() 78for url_str in url_lists: 79result_str = self.download_url(url_str) 80self.save_result(result=result_str,url_str=url_str) 81 82 # class QiushiMongo(QiushiSpider): 83 #def save_result(self, result,url_str): 84 #mc = MongoCache() 85 #mc[url_str] = result 86 # 87 #def run(self): 88 #url_lists = self.make_url() 89 #for url_str in url_lists: 90 #result_str = self.download_url(url_str) 91 #self.save_result(result=result_str,url_str=url_str) 92 93 # if __name__ == '__main__': 94#爬取貼吧並存到MongoDB 95# test = TiebaMongo('lol') 96# test.run() 97#爬取糗事並存到MongoDB 98# qiushi = QiushiMongo() 99# qiushi.run() 100#查詢MongoDB 101# mc = MongoCache() 102# print(mc['https://tieba.baidu.com/f?kw=lol&ie=utf-8&pn=2']) 103# print('https://tieba.baidu.com/f?kw=lol&ie=utf-8&pn=3' in mc) 104# cha = MongoCache() 105# print(cha[test.url_base]) 106# print(mc["https://www.qiushibaike.com/8hr/page/2/"])
-
在儲存時,需多傳一個網址引數(為了在儲存方法中對應儲存)