爬虫——实战完整版

发布时间:2019-03-13 22:28:32编辑:auto阅读(1792)

    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__

      • 当调用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/"])

         

     

关键字