前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >爬虫断了 ?

爬虫断了 ?

作者头像
小小詹同学
发布2019-11-12 22:31:12
5700
发布2019-11-12 22:31:12
举报
文章被收录于专栏:小詹同学小詹同学

摘要:使用 update_one() 而不是 insert_one() 方法存储数据。

相信你一定有过这样的经历:大晚上好不容易写好一个爬虫,添加了种种可能出现的异常处理,测试了很多遍都没有问题,点击了 RUN 开始正式运行 ,然后美滋滋地准备钻被窝睡觉,睡前还特意检查了下确认没有问题,合上眼后期待着第二天起来,数据都乖乖地躺在 MongoDB 中。第二天早上一睁眼就满心欢喜地冲到电脑前,结果发现爬虫半夜断了,你气得想要砸电脑,然后你看了一下 MongoDB 中爬了一半的数据,在想是删掉重新爬,还是保留下来接着爬。

到这儿问题就来了,删掉太可惜,接着爬很可能会爬到重复数据,虽然后期可以去重,但你有强迫症,就是不想爬到重复数据,怎么办呢?

这就遇到了「爬虫断点续传」问题,关于这个问题的解决方法有很多种,不过本文主要介绍数据存储到 MongoDB 时如何做到只插入新数据,而重复数据自动过滤不插入。

先来个简单例子,比如现在有两个 list ,data2 中的第一条数据和 data 列表中的第一条数据是重复的,我们想将这两个 list 依次插入 MnogoDB 中去, 通常我们会使用 insert_one() 或者 insert_many() 方法插入,这里我们使用 insert_one() 插入,看一下效果。

1data = [ 2{'index':'A','name':'James','rank':'1' }, 3{'index':'B','name':'Wade','rank':'2' }, 4{'index':'C','name':'Paul','rank':'3' }, 5] 6 7data2 = [ 8{'index':'A','name':'James','rank':'1' }, 9{'index':'D','name':'Anthony','rank':'4' }, 10] 11 12import pymongo 13client = pymongo.MongoClient('localhost',27017) 14db = client.Douban 15mongo_collection = db.douban 16 17for i in data: 18 mongo_collection.insert_one(i)

插入第一个 list :

插入第二个 list :

你会发现,重复的数据 A 被插入进去了,那么怎么只插入 D,而不插入 A 呢,这里就要用到 update_one() 方法了,改写一下插入方法:

1for i in data2: 2 mongo_collection.update_one(i,{'$set':i},upsert=True)

这里用到了 $set 运算符,该运算符作用是将字段的值替换为指定的值,upsert 为 True 表示插入。这里也可以用 update() 方法,但是这个方法比较老了,不建议使用。另外尝试使用 update_many() 方法发现不能更新多个相同的值。

1for i in data2: 2 mongo_collection.update(i, i, upsert=True)

下面举一个豆瓣电影 TOP250 的实例,假设我们先获取 10 个电影的信息,然后再获取前 20 个电影,分别用 insert_one() 和 update_one() 方法对比一下结果。

insert_one() 方法会重复爬取前 10 个电影,最终生成 30 个数据:

update_one() 方法则只会插入新的 10 个电影,最终生成 20 个数据:

这就很好了对吧,所以当我们去爬那些需要分页的网站,最好在爬取之前使用 update_one() 方法,这样就算爬虫中断了,也不用担心会爬取重复数据。

代码实现如下:

1import requests 2import json 3import csv 4import pandas as pd 5from urllib.parse import urlencode 6import pymongo 7 8client = pymongo.MongoClient('localhost', 27017) 9db = client.Douban 10mongo_collection = db.douban 11class Douban(object): 12 def __init__(self): 13 self.url = 'https://api.douban.com/v2/movie/top250?' 14 15 def get_content(self, start_page): 16 params = { 17 'start': start_page, 18 'count': 10 19 } 20 response = requests.get(self.url, params=params).json() 21 movies = response['subjects'] 22 data = [{ 23 'rating': item['rating']['average'], 24 'genres':item['genres'], 25 'name':item['title'], 26 'actor':self.get_actor(item['casts']), 27 'original_title':item['original_title'], 28 'year':item['year'], 29 } for item in movies] 30 31 self.write_to_mongodb(data) 32 33 def get_actor(self, actors): 34 actor = [i['name'] for i in actors] 35 return actor 36 37 def write_to_mongodb(self, data): 38 for item in data: 39 if mongo_collection.update_one(item, {'$set': item}, upsert=True): 40 # if mongo_collection.insert_one(item): 41 print('存储成功') 42 else: 43 print('存储失败') 44 45 def get_douban(self, total_movie): 46 # 每页10条,start_page循环1次 47 for start_page in range(0, total_movie, 10): 48 self.get_content(start_page) 49 50if __name__ == '__main__': 51 douban = Douban() 52 douban.get_douban(10)

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-12-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 小詹学Python 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 MongoDB
腾讯云数据库 MongoDB(TencentDB for MongoDB)是腾讯云基于全球广受欢迎的 MongoDB 打造的高性能 NoSQL 数据库,100%完全兼容 MongoDB 协议,支持跨文档事务,提供稳定丰富的监控管理,弹性可扩展、自动容灾,适用于文档型数据库场景,您无需自建灾备体系及控制管理系统。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档