当前位置: 首页 > 科技观察

Python爬虫任务数据操作小技巧

时间:2023-03-16 11:53:11 科技观察

需要爬取某网站的item列表页,获取其url、title等信息,作为后续爬取详情页的任务url。先上代码代码#-*-coding:utf-8-*-#@Time:2019-11-0814:04#@Author:cxa#@File:motor_helper.py#@Software:PyCharmportasyncioimportdatetimefromloguruimportloggerfrommotor.motor_asyncioimportAsyncIOMotorClientfromcollectionsimportIterabletry:importuv_loopasyncio(uvloop.EventLoopPolicy())exceptImportError:passdb_configs={'host':'127.0.0.1','port':'27017','db_name':'mafengwo','user':''}classMotorOperation:def__init__(self):self.__dict__.update(**db_configs)ifself.user:self.motor_uri=f"mongodb://{self.user}:{self.passwd}@{self.host}:{self.port}/{self.db_name}?authSource={self.db_name}"else:self.motor_uri=f"mongodb://{self.host}:{self.port}/{self.db_name}"self.client=AsyncIOMotorClient(self.motor_uri)self.mb=self.client[self.db_name]asyncdefsave_data_with_status(self,items,col="seed_data"):foriteminitems:data=dict()data["update_time"]=datetime.datetime.now()data["status"]=0#0开始data.update(item)print("data",data)awaitself.mb[col].update_one({"url":item.get("url")},{'$set':data,'$setOnInsert':{'create_time':datetime.datetime.now()}},upsert=True)asyncdefadd_index(self,col="seed_data"):#addindexawaitself.mb[col].create_index('url')因为我的爬虫是异步网络模块aiohttp写的,所以选择了pymongo的异步版本motor来操作。异步代码的基本属性就是async/await成对出现。如果去掉上面的await和async,就类似于pymongo的写法。这里异步不是重点,重点是我们对每条数据做什么。除了网页的url、标题等信息外,我还需要添加3个字段。它们分别是create_time、status、update_time。这三个字段分别代表数据插入数据、状态和更新时间。那么为什么要添加三个字段呢?首先我们需要判断每次任务数据是否存在。我这里的情况是存在就更新,不存在就插入。然后我需要一个查询条件作为更新条件。显然这里可以使用任务的url作为唯一条件(也可以使用url+title做一个md5保存),查询条件确定。先说create_time,更好理解为数据插入时间。关键是为什么要有一个update_time,它跟status字段有一定的关系。亮点:该状态作为后续爬虫爬取的标志。目前这个状态有4个值,0-4,我是这样定义的,0:初始状态1:正在抓取任务2:抓取成功3:抓取失败4:抓取成功但没有任务匹配。后面随着任务的爬取,状态不断变化,我们需要更新update_time为最新的时间。当前这个词不显示任何效果。它的使用场景是抓取重复的任务。例如,今天我在任务列表中捕获了url1和url2。如果我第二天再抓包,为了区分我们可以根据create_time和update_time来推断是抓包失败还是成功。如果两者相同且当前日期表示刚刚捕获了任务,如果update_time的日期比create_time更新,则表示捕获了重复的任务。字段的设计就这么多了。下面是实现。我们可以使用update_one方法对数据进行存在或插入操作,因为是用url作为查询条件,后面量大的话最好加上索引。也就是上面的add_index方法。嗯,最好说插入更新的具体代码需要注意的是{'$set':data,'$setOnInsert':{'create_time':datetime.datetime.now()}}$中使用的字段setOnInsert不是data存在才插入,存在就不移动。在$set中只插入指定的一个。此外,$setOnInsert中使用的字段不能再次出现在$set中。upsert=True表示不存在则插入。