04-03 周三 使用印象笔记API批量更新笔记标题

04-03 周三 使用印象笔记API批量更新笔记标题

时间 版本 修改人 描述
2024年4月3日11:13:50 V0.1 宋全恒 新建文档

简介

安利印象笔记

在阅读这篇博客之前,首先给大家案例一下印象笔记这个应用,楼主之前使用onenote来记录自己的生活的,也记录了许多的内容,但是,有一天自己的同事和自己说了印象笔记这个工具,然后在使用了之后,就发现确实是不错的,包括模板功能啊,大纲,XMind支持,以及剪藏功能,而且在多个终端可以非常方便的同步,而且每个笔记有300M的空间(超级用户),最新的印象笔记也上线了视图功能,让自己非常的方便。

这样让自己的复盘非常的便利,因为自己已经基本养成了周盘、月盘、年盘的习惯了

我们每天都有不同的生活,而生活是需要记录的,当时间过去之后,如果我们忘记了当时的心情,当时的事情也是有些遗憾的事。所以呢,建议大家养成记录的习惯,记录自己的开心和不快,记录自己的挣扎和痛苦,然后通过不断的反省,然后让自己辽阔。因为

痛苦 + 反思 = 进步

这是瑞·达利欧在原则中所说的话。还是很受益的。

问题

印象笔记写了很多年,也有了7000多条记录了,当然不仅仅是自己的日记笔记,也有通过剪藏收集的关于专业的内容,主要是包括

  • 专业程序类,
  • 戒色修身,改过迁善的文章
  • 日记,当然也有许多自己的经历和看法,

主要是比较真实的。都真实的记录了自己的人生过去。然后在使用过程中,自己发现在手机和app端有一个功能那年今日,可以把过去的每一年的今天写的日记给重新显示(手机的助手),可遗憾的是,电脑端没有这个功能。怎么能够在电脑端印象笔记快速的检索出来那年今日的文章呢?

在之前的时候,自己主要是使用created:这个快捷键智能检索,根据笔记的创建时间来过滤出来那年今日的内容,这样就形成了下面的解决方案:

但是这种方式有问题,第一,就是得每年新增一个这样的搜索,第二就是在查询的时候,必须挨个点击,而我又是一个高级的程序猿,忍受不了这种低效的方式。所以我应该怎么解决这个问题呢?

就是有一天工作的时候突然想到,自己可以接入印象笔记的API吧,然后使用印象笔记的高级检索intitle:04-03这样只要输入今天的日期,就可以检索笔记标题中含有04-03的内容了,哈哈,当时因为这个念头就很兴奋。因为之前没有想到使用API,就一直手动修改,但是7000多条笔记真的修改起来太机械(mechanic),太枯燥了。本篇文章就是记录了使用API批量修改笔记标题的过程的过程。

前提

  • 印象笔记的API库,由于楼主最近使用Python,因此,使用Python的印象API,即ever-sdk-python,需要注意的是,只支持Python2.7
  • 官方提供的Quciker start可以参考, 关于沙盒 和Evernote API key,如果你是修改自己的笔记,则是不需要的。
  • 需要Developer Token,进入该网站生成TOken

代码片段

程序使用Python实现,基本功能是将标题

完成GitHub自托管运行器的实践,发表印象笔记博客

修改成

04-03 完成GitHub自托管运行器的实践,发表印象笔记博客

当然日期,根据笔记的创建日期进行转换

python 复制代码
# -*- coding: utf-8 -*-
#
# A simple Evernote API demo script that lists all notebooks in the user's
# account and creates a simple test note in the default notebook.
#
# Before running this sample, you must fill in your Evernote developer token.
#
# To run (Unix):
#   export PYTHONPATH=../../lib; python EDAMTest.py
#

import hashlib
import binascii
import evernote.edam.userstore.constants as UserStoreConstants
import evernote.edam.type.ttypes as Types
from evernote.edam.notestore.ttypes import NoteFilter, NotesMetadataResultSpec


from evernote.api.client import EvernoteClient
import codecs

# Real applications authenticate with Evernote using OAuth, but for the
# purpose of exploring the API, you can get a developer token that allows
# you to access your own Evernote account. To get a developer token, visit
# https://SERVICE_HOST/api/DeveloperToken.action
#
# There are three Evernote services:
#
# Sandbox: https://sandbox.evernote.com/
# Production (International): https://www.evernote.com/
# Production (China): https://app.yinxiang.com/
#
# For more information about Sandbox and Evernote China services, please 
# refer to https://dev.evernote.com/doc/articles/testing.php 
# and https://dev.evernote.com/doc/articles/bootstrap.php
    

from datetime import datetime

def get_time_str(timestamp):
    # 将时间戳转换为datetime对象  # 注意时间戳是毫秒,需要除以1000转换为秒
    dt_object = datetime.utcfromtimestamp(timestamp / 1000) 

    # 定义日期格式
    date_format = "%Y-%m-%d %H:%M:%S"

    # 格式化日期
    formatted_date = dt_object.strftime(date_format)

    # 打印结果
    return formatted_date

import re
def is_data_prefix_with_space(title):
    """
    检查标题的前六位字符是否符合日期格式(dd-mm)。并且包含一个空格

    参数:
    title (str): 需要检查格式的标题字符串。

    返回:
    bool: 如果标题的前六位字符符合日期格式,返回 True;否则返回 False。
    """
    # 正则表达式匹配前六位是否为两位数字-两位数字
    pattern = r'^\d{2}-\d{2} '
    if re.match(pattern, title[:6]):  # 限制检查的字符串长度为6
        return True
    
    if re.match("^\d{2}-\d{2}", title[:5]) and len(title.strip())==5:
        return True
    return False
    
def is_data_prefix_without_space(title):
    """
    检查标题的前六位字符是否符合日期格式(dd-mm)。并且包含一个空格

    参数:
    title (str): 需要检查格式的标题字符串。

    返回:
    bool: 如果标题的前六位字符符合日期格式,返回 True;否则返回 False。
    """
    # 正则表达式匹配前六位是否为两位数字-两位数字
    pattern = r'^\d{2}-\d{2}'
    if re.match(pattern, title[:6]):  # 限制检查的字符串长度为6
        return True
    else:
        return False
    
def get_title_with_date(title, timestamp_ms):
    """
    将毫秒时间戳转换为日期格式,并与标题拼接,确保标题中的日期后跟有空格。

    参数:
    title (str): 需要拼接的标题字符串。
    timestamp_ms (int): 时间戳,表示自1970年1月1日以来的毫秒数。

    返回:
    str: 转换并拼接后的字符串,格式为 "xx-xx title"。
    """
    

    # 正则表达式匹配以 "xx-xx" 开头且后面没有空格的模式
    match = re.match(r'(\d{2}-\d{2})[^\s]*', title)
    if match:
        # 如果标题符合模式,添加空格
        title = match.group(1) + " " + title[len(match.group(1)):]
        return title

    # 将毫秒时间戳转换为秒
    timestamp = timestamp_ms / 1000.0
    # 将时间戳转换为datetime对象
    dt_object = datetime.fromtimestamp(timestamp)

    # 格式化日期为 "xx-xx" 格式
    date_str = dt_object.strftime("%02m-%02d")

    # 拼接标题和日期,中间有一个空格
    formatted_title = date_str +" " + title
    return formatted_title


def write_array_to_file(array, filename='success_books.txt'):
    """
    将数组写入文件,每个元素占一行。

    参数:
    array (list): 要写入文件的数组。
    filename (str): 文件名,默认为 'success_books.txt'。
    """
    with open(filename, 'w') as file:  # 移除 encoding 参数
        for item in array:
            file.write("%s\n" % item)

def read_array_from_file(filename='success_books.txt'):
    """
    从文件中读取数组,如果文件不存在则返回空数组。

    参数:
    filename (str): 文件名,默认为 'success_books.txt'。

    返回:
    list: 从文件中读取的数组,或者空数组(如果文件不存在)。
    """
    try:
        with open(filename, 'r') as file:  # 尝试以只读模式打开文件
            array = [line.strip() for line in file.readlines()]
        return array
    except OSError:
        # 如果发生OSError异常(包括FileNotFoundError),返回空数组
        return []
    except IOError:
        # 如果发生其他IOError异常(如权限问题),也返回空数组
        return []

# 请修改为自己的auth_token,这个是楼主的无效的token
auth_token = "S=s43:U=91d3be:E=18ead076f78:C=18e88fae9a8:P=1cd:A=en-devtoken:V=2:H=d0d841403a8c584016c327591d12852"

if auth_token == "your developer token":
    print "Please fill in your developer token"
    print "To get a developer token, visit " \
        "https://sandbox.evernote.com/api/DeveloperToken.action"
    exit(1)


# To access Sandbox service, set sandbox to True 
# To access production (International) service, set both sandbox and china to False
# To access production (China) service, set sandbox to False and china to True
# 请修改
sandbox = False
china = True

# Initial development is performed on our sandbox server. To use the production
# service, change sandbox=False and replace your
# developer token above with a token from
# https://www.evernote.com/api/DeveloperToken.action
client = EvernoteClient(token=auth_token, sandbox=sandbox, china=china)

user_store = client.get_user_store()

version_ok = user_store.checkVersion(
    "Evernote EDAMTest (Python)",
    UserStoreConstants.EDAM_VERSION_MAJOR,
    UserStoreConstants.EDAM_VERSION_MINOR
)
print "Is my Evernote API version up to date? ", str(version_ok)
print ""
if not version_ok:
    exit(1)

note_store = client.get_note_store()

# List all of the notebooks in the user's account
notebooks = note_store.listNotebooks()
print "Found ", len(notebooks), " notebooks:"
for notebook in notebooks:
    success_books=read_array_from_file()
    if notebook.guid in success_books:
        continue
    print "notebook name:",notebook.name," notebook guid: ", notebook.guid
    print "--------------------------------------------------------------"
    filter = NoteFilter()
    filter.notebookGuid = notebook.guid
    
    result_spec = NotesMetadataResultSpec()
    result_spec.includeTitle=True
    result_spec.includeCreated=True
    notes_metadata_list = note_store.findNotesMetadata(filter, 0, 1000, result_spec)
    print "totalNotes:", notes_metadata_list.totalNotes
    
    for note in notes_metadata_list.notes:
        if is_data_prefix_with_space(note.title):
            continue
        old_title = note.title
        new_title = get_title_with_date(note.title, note.created)
        note.title = new_title
        print "Modify title From", old_title.ljust(50, ' '), "  To    ", new_title.ljust(50, ' ')
        note_store.updateNote(auth_token, note)
    print "--------------------------------------------------------------"
    print "notebook name:",notebook.name,"处理完成"
    success_books.append(notebook.guid)
    write_array_to_file(success_books)
    


# # To create a new note, simply create a new Note object and fill in
# # attributes such as the note's title.
# note = Types.Note()
# note.title = "Test note from EDAMTest.py"

# # To include an attachment such as an image in a note, first create a Resource
# # for the attachment. At a minimum, the Resource contains the binary attachment
# # data, an MD5 hash of the binary data, and the attachment MIME type.
# # It can also include attributes such as filename and location.
# image = open('enlogo.png', 'rb').read()
# md5 = hashlib.md5()
# md5.update(image)
# hash = md5.digest()

# data = Types.Data()
# data.size = len(image)
# data.bodyHash = hash
# data.body = image

# resource = Types.Resource()
# resource.mime = 'image/png'
# resource.data = data

# # Now, add the new Resource to the note's list of resources
# note.resources = [resource]

# # To display the Resource as part of the note's content, include an <en-media>
# # tag in the note's ENML content. The en-media tag identifies the corresponding
# # Resource using the MD5 hash.
# hash_hex = binascii.hexlify(hash)

# # The content of an Evernote note is represented using Evernote Markup Language
# # (ENML). The full ENML specification can be found in the Evernote API Overview
# # at http://dev.evernote.com/documentation/cloud/chapters/ENML.php
# note.content = '<?xml version="1.0" encoding="UTF-8"?>'
# note.content += '<!DOCTYPE en-note SYSTEM ' \
#     '"http://xml.evernote.com/pub/enml2.dtd">'
# note.content += '<en-note>Here is the Evernote logo:<br/>'
# note.content += '<en-media type="image/png" hash="' + hash_hex + '"/>'
# note.content += '</en-note>'

# Finally, send the new note to Evernote using the createNote method
# The new Note object that is returned will contain server-generated
# attributes such as the new note's unique GUID.
#created_note = note_store.createNote(note)

# print "Successfully created a new note with GUID: ", created_note.guid

代码解读

修改部分

要设置自己的auth_token,并且,不需要使用沙盒并且使用国内印象笔记服务。

程序主题流程

代码执行效果

总结

手动修改,真的太痛苦了,通过程序来解决问题,真香。

通过上述的过程,就可以将所有的笔记标题均修改成包含日期的标题了,这样只要保证以后在写日记或剪藏的时候,手动添加上标题,就可以保持一致性了,这样整体就非常的方便了。轻轻松松可以实现通过intitle:04-03 查询出每年的今天所撰写的笔记。

还是那句话,无论过去每个人多么的痛苦和难以接受,无论现状多么糟糕和难以忍受,但是我们就是踏着那样的道路走到了现在的样子,不抗拒,不抱怨,接纳然后从记录中获取问题,分析问题,然后解决问题,这或许就是成长的样子吧。

相关推荐
cuisidong19975 分钟前
5G学习笔记三之物理层、数据链路层、RRC层协议
笔记·学习·5g
乌恩大侠6 分钟前
5G周边知识笔记
笔记·5g
咔叽布吉1 小时前
【论文阅读笔记】CamoFormer: Masked Separable Attention for Camouflaged Object Detection
论文阅读·笔记·目标检测
johnny2331 小时前
《大模型应用开发极简入门》笔记
笔记·chatgpt
亦枫Leonlew1 小时前
微积分复习笔记 Calculus Volume 1 - 4.7 Applied Optimization Problems
笔记·数学·微积分·1024程序员节
小肥象不是小飞象1 小时前
(六千字心得笔记)零基础C语言入门第八课——函数(上)
c语言·开发语言·笔记·1024程序员节
星LZX1 小时前
WireShark入门学习笔记
笔记·学习·wireshark
努力变厉害的小超超3 小时前
ArkTS中的组件基础、状态管理、样式处理、class语法以及界面渲染
笔记·鸿蒙
aloha_7898 小时前
从零记录搭建一个干净的mybatis环境
java·笔记·spring·spring cloud·maven·mybatis·springboot
dsywws9 小时前
Linux学习笔记之vim入门
linux·笔记·学习