天天看點

python mongo存在插入不存在更新,同時指定如果不存在才插入的字段

python爬蟲的任務資料操作的小技巧

好久沒寫公衆号了,最近太忙了,這裡就不多說了。直接根據需求上代碼,我想這個應該是大家比較喜歡的,

需求

爬取某網站的項目清單頁,擷取其url,标題等資訊,作為後續爬取詳情頁的任務url。

先上代碼

代碼

# -*- coding: utf-8 -*-
# @Time : 2019-11-08 14:04
# @Author : cxa
# @File : motor_helper.py
# @Software: PyCharm

import asyncio 
import datetime
from loguru import logger
from motor.motor_asyncio import AsyncIOMotorClient
from collections import Iterable

try:
    import uvloop

    asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
except ImportError:
    pass

db_configs = {
    'host': '127.0.0.1',
    'port': '27017',
    'db_name': 'mafengwo',
    'user': ''
}

class MotorOperation:
    def __init__(self):
        self.__dict__.update(**db_configs)
        if self.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]
    async def save_data_with_status(self, items, col="seed_data"):
        for item in items:
            data = dict()
            data["update_time"] = datetime.datetime.now()
            data["status"] = 0  # 0初始
            data.update(item)
            print("data", data)
            await self.mb[col].update_one({
                "url": item.get("url")},
                {'$set': data, '$setOnInsert': {'create_time': datetime.datetime.now()}},
                upsert=True)

     async def add_index(self, col="seed_data"):
        # 添加索引
        await self.mb[col].create_index('url')
           

因為我的爬蟲是異步網絡子產品aiohttp寫的,是以選擇了pymongo的異步版本motor進行操作。

異步代碼的基本屬性就是async/await成對的出現,如果把上面的await和async去掉,就是類似pymongo的寫法了,這裡異步不是重點,重點是我們怎麼處理每條資料。

這裡除了網頁的url,标題等資訊,我需要附加3個字段。分别是create_time, status,update_time。

這三個字段分别代表,資料插入資料,狀态和更新時間。

那麼我為什麼添加三個字段呢?

首先,我們需要判斷每次的任務資料是否存在,我這裡的情況是存在就更新不存在就插入,那麼我就需要一個查詢條件,作為更新的條件,很顯然這裡可以使用任務的url作為唯一條件(你還可以使用url+标題做個md5然後儲存)。好了查詢條件确定,

下面說create_time這個比較好了解就是資料插入時間,關鍵是為什麼還要一個update_time,這個的話和status字段有一定的關系。 畫重點:這個status作為後續爬蟲進行爬取的一個标志用。目前這個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()}}