经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » Python » 查看文章
爬虫——实战完整版
来源:cnblogs  作者:抿嘴唇  时间:2018/9/25 20:35:41  对本文有异议

mongodb操作

  1. 1 import pymongo
  2. 2
  3. 3 #连接数据库实例(连接数据库)---》获取相应数据库---》获取相应collection集合(表)
  4. 4 client = pymongo.MongoClient(host='localhost',port=27017)
  5. 5
  6. 6 db = client.test #也可用字典形式操作,如下
  7. 7 # db = client["test"]
  8. 8
  9. 9 collection = db.students #也可用字典形式操作,如下
  10. 10 # collection = db["students"]
  11. 11
  12. 12 student1 = {
  13. 13 'id':'001',
  14. 14 'name':'haha',
  15. 15 'age':20,
  16. 16 'gender':'male'
  17. 17 }
  18. 18 student2 = {
  19. 19 'id': '002',
  20. 20 'name': 'Mike',
  21. 21 'age': 41,
  22. 22 'gender': 'male'
  23. 23 }
  24. 24 #--------------------------------------------------------------------------
  25. 25 #插入 insert into students(...) values('002',...)
  26. 26 #若不指定 _id 字段,系统默认会生成一个ObjectId
  27. 27 #可插入一条或多条数据(列表形式),python3不推荐使用insert
  28. 28 # collection.insert([student1,student2])
  29. 29 # collection.insert(student1)
  30. 30
  31. 31 #官方推荐,分开使用,返回值不是ObjectId,而是InsertOneResult对象,我们可以调用其inserted_id属性获取_id。
  32. 32 # result = collection.insert_one(student2)
  33. 33 # print(result)
  34. 34 # print(result.inserted_id)
  35. 35
  36. 36 # result = collection.insert_many([student1,student2])
  37. 37 # print(result)
  38. 38 # print(result.inserted_ids)
  39. 39
  40. 40 #------------------------------------------------------------------
  41. 41 #查询 select * from students where id=002
  42. 42 #查询条件使用字典,可使用多字段,find是多条查询
  43. 43 # result_find = collection.find({"name":"lijingbo","age":20})
  44. 44 # print(result_find.next()) #返回一个游标,游标相当于迭代器,可使用next()获取一条结果,或者使用循环遍历等,遍历结果是字典
  45. 45 #find_one:单个查询,返回字典类型
  46. 46 # result = collection.find_one({'age':20})
  47. 47 # print(result,type(result))
  48. 48 #结合关系符进行查询:$gt,$lt,$gte,$lte,$ne,$in,$nin
  49. 49 # result = collection.find({'age':{'$gt':18}})
  50. 50 # result = collection.find({'age':{'$in':[18,41]}})
  51. 51 #结合特殊符号查询:$regex
  52. 52 # result = collection.find({'name':{'$regex':'^M.*'}}) #正则
  53. 53 # result = collection.find({'name':{'$exists':True}}) #查询含有name属性的
  54. 54 # result = collection.find({'age':{'$mod':[5,0]}}) #求模,对5取余=0
  55. 55 # result = collection.find({'$where':'obj.age==20'}) #查询age为20的,obj是自身
  56. 56 # result = collection.find({'age':20}).count() #统计
  57. 57 # result = collection.find().sort('age',pymongo.ASCENDING) #按照指定字段升序排列
  58. 58 # result = collection.find().sort('age',pymongo.DESCENDING) #按照指定字段升序排列
  59. 59 # result = collection.find().sort('age',pymongo.DESCENDING).skip(2) #按照指定字段升序排列,偏移2个(就是把最前面两个跳过去了)
  60. 60 # result = collection.find().sort('age',pymongo.DESCENDING).skip(2).limit(5) #限制得到5
  61. 61 # print(result)
  62. 62 # for r in result:
  63. 63 # print(r['name'],r['age'])
  64. 64
  65. 65 #----------------------------------------------------------
  66. 66 #更新 update students set name=haha where id=001
  67. 67 #参数1:查询条件(字典);参数2:更新值(字典,键:'$set',值:字典【也可直接使用外部字典】)
  68. 68 #其他:upsert默认为False,为True时——若更新的原数据不存在,则插入数据
  69. 69 #multi——默认为False只更新查询到的第一条数据,为True时:更新全部查询到的数据
  70. 70 # $set:是mongodb内置函数,覆盖原始数据
  71. 71 # collection.update({"id":"001"},{'$set':{'age':34}},upsert=True,multi=True)
  72. 72 # print(collection.find().next())
  73. 73 #上面的官方也不推荐,可以使用下面的
  74. 74 # result = collection.update_one({'name':'haha'},{'$set':{'age':18}})
  75. 75 # result = collection.update_many({'name':'haha'},{'$set':{'age':18}})
  76. 76 # print(result) #只修改一条数据,若该数据不修改就和修改条件一样了,那有可能修改数为0
  77. 77 # print(result.matched_count,result.modified_count)
  78. 78
  79. 79
  80. 80 #-----------------------------------------------------
  81. 81 #删除,remove方法官方不推荐
  82. 82 # collection.remove({"id":"001"},justOne=1)
  83. 83 # result = collection.delete_one({'name':'Mike'})
  84. 84 # result = collection.delete_many({'name':'Mike'})
  85. 85 # print(result)
  86. 86 # print(result.deleted_count)
  87. 87
  88. 88 #---------------------------------------------------
  89. 89 #组合方法
  90. 90 # result = collection.find_one_and_delete({'name':'haha'})
  91. 91 # result = collection.find_one_and_update({'name':'haha'},{'$set':{'age':45}})
  92. 92 # result = collection.find_one_and_replace({'name':'haha'})
  93. 93 # print(result)

 

MongoCache

将数据以字典的特性存储缓存到mongodb数据库

导入类库

  1. import pickle,zlib #对象序列化 压缩数据
  2. from datetime import datetime,timedelta #设置缓存超时间间隔
  3. from pymongo import MongoClient
  4. 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. 1 import pickle,zlib #对象序列化 压缩数据
      2. 2 from datetime import datetime,timedelta #设置缓存超时间间隔
      3. 3 from pymongo import MongoClient
      4. 4 from bson.binary import Binary #MongoDB存储二进制的类型
      5. 5 from http_ljb.tiebaspider import TiebaSpider
      6. 6 from http_ljb.qiushispider import QiushiSpider
      7. 7
      8. 8 class MongoCache:
      9. 9 def __init__(self,client=None,expires=timedelta(days=30)):
      10. 10 '''
      11. 11 初始化函数
      12. 12 :param client: 数据库连接(数据库实例)
      13. 13 :param expires: 超时时间
      14. 14 '''
      15. 15 self.client = MongoClient('localhost',27017)
      16. 16 self.db = self.client.cache #创建名为cache的数据库
      17. 17 web_page = self.db.webpage #创建集合webpage并赋值给变量
      18. 18 #创建timestamp索引,设置超时时间为30天,total_seconds会将days转为秒
      19. 19 self.db.webpage.create_index('timestamp',expireAfterSeconds=expires.total_seconds())
      20. 20
      21. 21 def __setitem__(self, key, value):
      22. 22 '''
      23. 23 用字典的形式向数据库添加一条缓存(数据)
      24. 24 :param key: 缓存的键
      25. 25 :param value: 缓存的值
      26. 26 :return:
      27. 27 '''
      28. 28 #数据---》pickle序列化---》zlib压缩---》Binary转化为mondodb需要的格式,使用格林威治时间
      29. 29 record = {'result':Binary(zlib.compress(pickle.dumps(value))),'timestamp':datetime.utcnow()}
      30. 30 #使用下载的url(路由)作为key,存入系统默认的_id字段,更新数据库,若存在则更新,不存在则插入,_id唯一就可实现爬取的数据去重
      31. 31 self.db.webpage.update({'_id':key},{'$set':record},upsert=True)
      32. 32
      33. 33 def __getitem__(self, item):
      34. 34 '''
      35. 35 将缓存数据按照item作为key取出(key仍然是下载的url)
      36. 36 :param item:键
      37. 37 :return:
      38. 38 '''
      39. 39 record = self.db.webpage.find_one({'_id':item}) #查找出来就不是Binary了,不用进行转化
      40. 40 if record:
      41. 41 return pickle.loads(zlib.decompress(record['result'])) #解压缩,反序列化
      42. 42 else:
      43. 43 raise KeyError(item + 'does not exist') #查询不到就抛出键错误异常
      44. 44
      45. 45 def __contains__(self, item):
      46. 46 '''
      47. 47 当调用in,not in ,会自动调用该方法判断链接对应网址是否在数据库中
      48. 48 :param item: 下载的url链接(路由)
      49. 49 :return:
      50. 50 '''
      51. 51 try:
      52. 52 self[item] #这一步会调用__getitem__,找不到__getitem__会抛出异常,在这里进行捕获异常只返回False,否则返回True
      53. 53 except KeyError:
      54. 54 return False
      55. 55 else:
      56. 56 return True
      57. 57
      58. 58 def clear(self):
      59. 59 '''
      60. 60 清空该集合中的数据
      61. 61 :return:
      62. 62 '''
      63. 63 self.db.webpage.drop()

       

爬取实例

调用贴吧爬取代码和百科爬取代码,使用mongodb存储爬取数据

 

  • 导入爬取类
  • 创建新类并继承自爬取类
  • 重写保存方法
    • 创建MongoCache对象
    • 网址为键,数据为值,以字典形式存入mongodb
  • 重写run方法
    • 在保存时,需多传一个网址参数(为了在保存方法中对应保存)
      1. 1 import pickle,zlib #对象序列化 压缩数据
      2. 2 from datetime import datetime,timedelta #设置缓存超时间间隔
      3. 3 from pymongo import MongoClient
      4. 4 from bson.binary import Binary #MongoDB存储二进制的类型
      5. 5 from http_ljb.tiebaspider import TiebaSpider
      6. 6 from http_ljb.qiushispider import QiushiSpider
      7. 7
      8. 8 class MongoCache:
      9. 9 def __init__(self,client=None,expires=timedelta(days=30)):
      10. 10 '''
      11. 11 初始化函数
      12. 12 :param client: 数据库连接(数据库实例)
      13. 13 :param expires: 超时时间
      14. 14 '''
      15. 15 self.client = MongoClient('localhost',27017)
      16. 16 self.db = self.client.cache #创建名为cache的数据库
      17. 17 web_page = self.db.webpage #创建集合webpage并赋值给变量
      18. 18 #创建timestamp索引,设置超时时间为30天,total_seconds会将days转为秒
      19. 19 self.db.webpage.create_index('timestamp',expireAfterSeconds=expires.total_seconds())
      20. 20
      21. 21 def __setitem__(self, key, value):
      22. 22 '''
      23. 23 用字典的形式向数据库添加一条缓存(数据)
      24. 24 :param key: 缓存的键
      25. 25 :param value: 缓存的值
      26. 26 :return:
      27. 27 '''
      28. 28 #数据---》pickle序列化---》zlib压缩---》Binary转化为mondodb需要的格式,使用格林威治时间
      29. 29 record = {'result':Binary(zlib.compress(pickle.dumps(value))),'timestamp':datetime.utcnow()}
      30. 30 #使用下载的url(路由)作为key,存入系统默认的_id字段,更新数据库,若存在则更新,不存在则插入,_id唯一就可实现爬取的数据去重
      31. 31 self.db.webpage.update({'_id':key},{'$set':record},upsert=True)
      32. 32
      33. 33 def __getitem__(self, item):
      34. 34 '''
      35. 35 将缓存数据按照item作为key取出(key仍然是下载的url)
      36. 36 :param item:键
      37. 37 :return:
      38. 38 '''
      39. 39 record = self.db.webpage.find_one({'_id':item}) #查找出来就不是Binary了,不用进行转化
      40. 40 if record:
      41. 41 return pickle.loads(zlib.decompress(record['result'])) #解压缩,反序列化
      42. 42 else:
      43. 43 raise KeyError(item + 'does not exist') #查询不到就抛出键错误异常
      44. 44
      45. 45 def __contains__(self, item):
      46. 46 '''
      47. 47 当调用in,not in ,会自动调用该方法判断链接对应网址是否在数据库中
      48. 48 :param item: 下载的url链接(路由)
      49. 49 :return:
      50. 50 '''
      51. 51 try:
      52. 52 self[item] #这一步会调用__getitem__,找不到__getitem__会抛出异常,在这里进行捕获异常只返回False,否则返回True
      53. 53 except KeyError:
      54. 54 return False
      55. 55 else:
      56. 56 return True
      57. 57
      58. 58 def clear(self):
      59. 59 '''
      60. 60 清空该集合中的数据
      61. 61 :return:
      62. 62 '''
      63. 63 self.db.webpage.drop()
      64. 64
      65. 65 class TiebaMongo(TiebaSpider):
      66. 66 def save_result(self, result,url_str):
      67. 67 """
      68. 68 重写父类的该方法,将数据保存到数据库
      69. 69 :param result:
      70. 70 :param url_str:
      71. 71 :return:
      72. 72 """
      73. 73 mc = MongoCache()
      74. 74 mc[url_str] = result
      75. 75
      76. 76 def run(self):
      77. 77 url_lists = self.make_url()
      78. 78 for url_str in url_lists:
      79. 79 result_str = self.download_url(url_str)
      80. 80 self.save_result(result=result_str,url_str=url_str)
      81. 81
      82. 82 # class QiushiMongo(QiushiSpider):
      83. 83 # def save_result(self, result,url_str):
      84. 84 # mc = MongoCache()
      85. 85 # mc[url_str] = result
      86. 86 #
      87. 87 # def run(self):
      88. 88 # url_lists = self.make_url()
      89. 89 # for url_str in url_lists:
      90. 90 # result_str = self.download_url(url_str)
      91. 91 # self.save_result(result=result_str,url_str=url_str)
      92. 92
      93. 93 # if __name__ == '__main__':
      94. 94 #爬取贴吧并存到MongoDB
      95. 95 # test = TiebaMongo('lol')
      96. 96 # test.run()
      97. 97 #爬取糗事并存到MongoDB
      98. 98 # qiushi = QiushiMongo()
      99. 99 # qiushi.run()
      100. 100 #查询MongoDB
      101. 101 # mc = MongoCache()
      102. 102 # print(mc['https://tieba.baidu.com/f?kw=lol&ie=utf-8&pn=2'])
      103. 103 # print('https://tieba.baidu.com/f?kw=lol&ie=utf-8&pn=3' in mc)
      104. 104 # cha = MongoCache()
      105. 105 # print(cha[test.url_base])
      106. 106 # print(mc["https://www.qiushibaike.com/8hr/page/2/"])

       

 

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号