爬虫——实战完整版
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':'lijingbo', 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':'lijingbo'},{'$set':{'age':18}}) 75 # result = collection.update_many({'name':'lijingbo'},{'$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':'lijingbo'}) 91 # result = collection.find_one_and_update({'name':'lijingbo'},{'$set':{'age':45}}) 92 # result = collection.find_one_and_replace({'name':'lijingbo'}) 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__
- 当调用in,not in ,会自动调用该方法判断链接对应网址是否在数据库中
- 可通过字典的查找方式
__getitem__
直接查找(self[item]) - 该函数返回布尔值
-
方法
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: 9 def __init__(self,client=None,expires=timedelta(days=30)): 10 ''' 11 初始化函数 12 :param client: 数据库连接(数据库实例) 13 :param expires: 超时时间 14 ''' 15 self.client = MongoClient('localhost',27017) 16 self.db = self.client.cache #创建名为cache的数据库 17 web_page = self.db.webpage #创建集合webpage并赋值给变量 18 #创建timestamp索引,设置超时时间为30天,total_seconds会将days转为秒 19 self.db.webpage.create_index('timestamp',expireAfterSeconds=expires.total_seconds()) 20 21 def __setitem__(self, key, value): 22 ''' 23 用字典的形式向数据库添加一条缓存(数据) 24 :param key: 缓存的键 25 :param value: 缓存的值 26 :return: 27 ''' 28 #数据---》pickle序列化---》zlib压缩---》Binary转化为mondodb需要的格式,使用格林威治时间 29 record = {'result':Binary(zlib.compress(pickle.dumps(value))),'timestamp':datetime.utcnow()} 30 #使用下载的url(路由)作为key,存入系统默认的_id字段,更新数据库,若存在则更新,不存在则插入,_id唯一就可实现爬取的数据去重 31 self.db.webpage.update({'_id':key},{'$set':record},upsert=True) 32 33 def __getitem__(self, item): 34 ''' 35 将缓存数据按照item作为key取出(key仍然是下载的url) 36 :param item:键 37 :return: 38 ''' 39 record = self.db.webpage.find_one({'_id':item}) #查找出来就不是Binary了,不用进行转化 40 if record: 41 return pickle.loads(zlib.decompress(record['result'])) #解压缩,反序列化 42 else: 43 raise KeyError(item + 'does not exist') #查询不到就抛出键错误异常 44 45 def __contains__(self, item): 46 ''' 47 当调用in,not in ,会自动调用该方法判断链接对应网址是否在数据库中 48 :param item: 下载的url链接(路由) 49 :return: 50 ''' 51 try: 52 self[item] #这一步会调用__getitem__,找不到__getitem__会抛出异常,在这里进行捕获异常只返回False,否则返回True 53 except KeyError: 54 return False 55 else: 56 return True 57 58 def clear(self): 59 ''' 60 清空该集合中的数据 61 :return: 62 ''' 63 self.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: 9 def __init__(self,client=None,expires=timedelta(days=30)): 10 ''' 11 初始化函数 12 :param client: 数据库连接(数据库实例) 13 :param expires: 超时时间 14 ''' 15 self.client = MongoClient('localhost',27017) 16 self.db = self.client.cache #创建名为cache的数据库 17 web_page = self.db.webpage #创建集合webpage并赋值给变量 18 #创建timestamp索引,设置超时时间为30天,total_seconds会将days转为秒 19 self.db.webpage.create_index('timestamp',expireAfterSeconds=expires.total_seconds()) 20 21 def __setitem__(self, key, value): 22 ''' 23 用字典的形式向数据库添加一条缓存(数据) 24 :param key: 缓存的键 25 :param value: 缓存的值 26 :return: 27 ''' 28 #数据---》pickle序列化---》zlib压缩---》Binary转化为mondodb需要的格式,使用格林威治时间 29 record = {'result':Binary(zlib.compress(pickle.dumps(value))),'timestamp':datetime.utcnow()} 30 #使用下载的url(路由)作为key,存入系统默认的_id字段,更新数据库,若存在则更新,不存在则插入,_id唯一就可实现爬取的数据去重 31 self.db.webpage.update({'_id':key},{'$set':record},upsert=True) 32 33 def __getitem__(self, item): 34 ''' 35 将缓存数据按照item作为key取出(key仍然是下载的url) 36 :param item:键 37 :return: 38 ''' 39 record = self.db.webpage.find_one({'_id':item}) #查找出来就不是Binary了,不用进行转化 40 if record: 41 return pickle.loads(zlib.decompress(record['result'])) #解压缩,反序列化 42 else: 43 raise KeyError(item + 'does not exist') #查询不到就抛出键错误异常 44 45 def __contains__(self, item): 46 ''' 47 当调用in,not in ,会自动调用该方法判断链接对应网址是否在数据库中 48 :param item: 下载的url链接(路由) 49 :return: 50 ''' 51 try: 52 self[item] #这一步会调用__getitem__,找不到__getitem__会抛出异常,在这里进行捕获异常只返回False,否则返回True 53 except KeyError: 54 return False 55 else: 56 return True 57 58 def clear(self): 59 ''' 60 清空该集合中的数据 61 :return: 62 ''' 63 self.db.webpage.drop() 64 65 class TiebaMongo(TiebaSpider): 66 def save_result(self, result,url_str): 67 """ 68 重写父类的该方法,将数据保存到数据库 69 :param result: 70 :param url_str: 71 :return: 72 """ 73 mc = MongoCache() 74 mc[url_str] = result 75 76 def run(self): 77 url_lists = self.make_url() 78 for url_str in url_lists: 79 result_str = self.download_url(url_str) 80 self.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/"])
- 在保存时,需多传一个网址参数(为了在保存方法中对应保存)
import pymongo
#连接数据库实例(连接数据库)—》获取相应数据库—》获取相应collection集合(表)client = pymongo.MongoClient(host=’localhost’,port=27017)
db = client.test #也可用字典形式操作,如下# db = client[“test”]
collection = db.students #也可用字典形式操作,如下# collection = db[“students”]
student1 = { ‘id’:’001′, ‘name’:’lijingbo’, ‘age’:20, ‘gender’:’male’}student2 = { ‘id’: ‘002’, ‘name’: ‘Mike’, ‘age’: 41, ‘gender’: ‘male’}#————————————————————————– #插入 insert into students(…) values(‘002’,…) #若不指定 _id 字段,系统默认会生成一个ObjectId #可插入一条或多条数据(列表形式),python3不推荐使用insert# collection.insert([student1,student2])# collection.insert(student1)
#官方推荐,分开使用,返回值不是ObjectId,而是InsertOneResult对象,我们可以调用其inserted_id属性获取_id。# result = collection.insert_one(student2)# print(result)# print(result.inserted_id)
# result = collection.insert_many([student1,student2])# print(result)# print(result.inserted_ids)
#—————————————————————— #查询 select * from students where id=002 #查询条件使用字典,可使用多字段,find是多条查询# result_find = collection.find({“name”:”lijingbo”,”age”:20})# print(result_find.next()) #返回一个游标,游标相当于迭代器,可使用next()获取一条结果,或者使用循环遍历等,遍历结果是字典 #find_one:单个查询,返回字典类型# result = collection.find_one({‘age’:20})# print(result,type(result)) #结合关系符进行查询:$gt,$lt,$gte,$lte,$ne,$in,$nin# result = collection.find({‘age’:{‘$gt’:18}})# result = collection.find({‘age’:{‘$in’:[18,41]}}) #结合特殊符号查询:$regex# result = collection.find({‘name’:{‘$regex’:’^M.*’}}) #正则# result = collection.find({‘name’:{‘$exists’:True}}) #查询含有name属性的# result = collection.find({‘age’:{‘$mod’:[5,0]}}) #求模,对5取余=0# result = collection.find({‘$where’:’obj.age==20′}) #查询age为20的,obj是自身# result = collection.find({‘age’:20}).count() #统计# result = collection.find().sort(‘age’,pymongo.ASCENDING) #按照指定字段升序排列# result = collection.find().sort(‘age’,pymongo.DESCENDING) #按照指定字段升序排列# result = collection.find().sort(‘age’,pymongo.DESCENDING).skip(2) #按照指定字段升序排列,偏移2个(就是把最前面两个跳过去了)# result = collection.find().sort(‘age’,pymongo.DESCENDING).skip(2).limit(5) #限制得到5# print(result)# for r in result:# print(r[‘name’],r[‘age’])
#———————————————————- #更新 update students set name=haha where id=001 #参数1:查询条件(字典);参数2:更新值(字典,键:’$set’,值:字典【也可直接使用外部字典】) #其他:upsert默认为False,为True时——若更新的原数据不存在,则插入数据 #multi——默认为False只更新查询到的第一条数据,为True时:更新全部查询到的数据 # $set:是mongodb内置函数,覆盖原始数据# collection.update({“id”:”001″},{‘$set’:{‘age’:34}},upsert=True,multi=True)# print(collection.find().next()) #上面的官方也不推荐,可以使用下面的# result = collection.update_one({‘name’:’lijingbo’},{‘$set’:{‘age’:18}})# result = collection.update_many({‘name’:’lijingbo’},{‘$set’:{‘age’:18}})# print(result) #只修改一条数据,若该数据不修改就和修改条件一样了,那有可能修改数为0# print(result.matched_count,result.modified_count)
#—————————————————– #删除,remove方法官方不推荐# collection.remove({“id”:”001″},justOne=1)# result = collection.delete_one({‘name’:’Mike’})# result = collection.delete_many({‘name’:’Mike’})# print(result)# print(result.deleted_count)
#————————————————— #组合方法# result = collection.find_one_and_delete({‘name’:’lijingbo’})# result = collection.find_one_and_update({‘name’:’lijingbo’},{‘$set’:{‘age’:45}})# result = collection.find_one_and_replace({‘name’:’lijingbo’})# print(result)