Python3 爬虫信息读取 MongoDB 和 Redis 的使用建议

一、少读少写少更新

        虽然MongoDB相比于MySQL来说,速度快了很多,但是频繁读写MongoDB还是会严重拖慢程序的执行速度。以插入数据为例,对于相同的数据,进行逐条插入和批量插入,速度差异非常显著。

        同样是插入10000条数据,逐条插入耗时约3.7s,批量插入耗时约0.2s。这个差距看起来已经很显著了吧。这还只是在本地测试的数据,如果使用远程的MongoDB服务器且数据量足够大,这个时间差甚至可以高达数小时。

        建议把要插入到MongoDB中的数据先统一放到一个列表中,等积累到一定量再一次性插入。

        对于读数据,在内存允许的情况下,应该一次性把数据读入内存,尽量减少对MongoDB的读取操作。

        在某些情况下,更新操作不得不逐条进行,如果使用常规操作,需要一条一条更新,首先把所有数据读入内存,根据_id查找每一条记录后再逐一更新。每一条数据都不一样,似乎没有办法批量更新。
        对于这种情况,是否有办法优化呢?答案当然是有,那就是不更新!这句话的意思是说,不要执行“更新”这个动作。把更新这个动作改为插入。这样就可以实现批量更新的效果了。具体来说,就是把数据批量插入到一个新的MongoDB集合中,再把原来的集合删除,最后将新的集合改为原来集合的名字。把更新操作改为插入操作,耗时约为逐条更新的十分之一。

二、能用Redis就不用MongoDB

        在什么情况下可以使用Redis来代替MongoDB呢?举一个最常见的例子:判断重复。例如爬取百度贴吧,在帖子列表页可以爬到每个帖子的标题和详情页的网址。如果对某一个帖子有兴趣,就从详情页网址爬进去抓取这个帖子的详细信息。由于需要节省资源,提高抓取速度,因此决定每天只爬新增加的帖子,已经爬过的帖子就不再重复爬取。
        解决这个问题,其实要实现的功能很简单。在保存数据的时候,把每个帖子的网址也保存到数据库中。爬虫在爬详情页之前,先去MongoDB中查看这个URL是否已经存在。如果已经存在就不爬详情页;如果不存在,就继续爬这个帖子的详情页。这种办法当然可以实现这个需求,但是由于在前面已经说了,频繁读/写MongoDB是非常浪费时间的,因此这种办法效率并不高。
        为了提高效率,就需要引入Redis。由于Redis是基于内存的数据库,因此即使频繁对其读/写,对性能的影响也远远小于频繁读/写MongoDB。在Redis中创建一个集合“crawled_url”,爬虫在爬一个网址之前,先把这个网址sadd到这个集合中。如果返回为1,那么表示这个网址之前没有爬过,爬虫需要去爬取详情页。如果返回0,表示这个网址之前已经爬过了,就不需要再爬了。示例代码片段如下:

… 
for url in url_list: #url_list为在贴吧列表页得到的每一个帖子的详情页网址列表   
  if client.sadd('crawled_url', url) == 1:   
      crawl(url)
…

--------------------------------------

版权声明:本文为【猿小猴子】博主的文章,同步在【猿小猴子】WeChat平台,转载请附上原文出处链接及本声明。

--------------------------------------

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是Python使用MongoDBRedis实现商品秒杀的示例代码。在这个示例中,我们使用Python的pymongo库和redis库来操作MongoDBRedis。 首先,需要安装pymongo和redis库: ``` pip install pymongo redis ``` 然后,连接MongoDBRedis: ```python import pymongo import redis # 连接MongoDB mongo_client = pymongo.MongoClient('mongodb://localhost:27017/') db = mongo_client['seckill'] # 连接Redis redis_client = redis.Redis(host='localhost', port=6379, db=0) ``` 接下来,定义商品和订单的数据结构,并初始化商品库存和秒杀开始时间: ```python # 商品数据结构 product = { 'id': 1, 'name': 'iPhone 12', 'price': 5999, 'stock': 10 } # 订单数据结构 order = { 'id': 1, 'user_id': 1, 'product_id': 1, 'quantity': 1, 'total_price': 0 } # 初始化商品库存和秒杀开始时间 redis_client.hset('seckill', product['id'], f"{product['stock']},{time.time()}") ``` 接下来,实现秒杀功能。在实现秒杀功能之前,需要先判断商品库存是否充足,如果充足,则减少库存并生成订单: ```python # 秒杀函数 def seckill(user_id, product_id, quantity): # 获取商品库存和秒杀开始时间 stock, start_time = map(int, redis_client.hget('seckill', product_id).split(',')) # 判断商品库存是否充足 if stock < quantity: return False # 开始秒杀 with redis_client.pipeline() as pipe: while True: try: # 监视商品库存 pipe.watch('seckill') # 判断商品库存是否充足 stock, start_time = map(int, pipe.hget('seckill', product_id).split(',')) if stock < quantity: pipe.unwatch() return False # 开始事务 pipe.multi() # 减少商品库存 pipe.hincrby('seckill', product_id, -quantity) # 生成订单 order['id'] = db.counters.find_one_and_update({'_id': 'order_id'}, {'$inc': {'seq': 1}})['seq'] order['user_id'] = user_id order['product_id'] = product_id order['quantity'] = quantity order['total_price'] = quantity * product['price'] db.orders.insert_one(order) # 提交事务 pipe.execute() return True except redis.exceptions.WatchError: # 事务失败,重试 continue ``` 最后,测试秒杀功能: ```python # 测试秒杀功能 seckill(1, product['id'], 1) ``` 以上代码是Python使用MongoDBRedis实现商品秒杀的示例,具体实现需要根据实际情况进行调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值