用 (Excel) VBA 读取 OneNote!

本文记录,用 VBA 读取 OneNote 的方法!小白贡献,语失莫怪!


问题背景:

我在 OneNote 里有上百篇笔记,可 OneNote 自己,却无法导出全部的标题。于是我千方百计,想要读取 OneNote 的文件,来获取标题和日志信息。尝试了各种方案,都没能读出 OneNote 的数据。最后过了好久好久,才找到了这种,基于 Excel VBA 的解决方式!那么接下来,我们就来看下它的代码!在篇尾还会再讲下,我尝试过的其他方式,也许哪位路过的大神,能解决掉其中的问题!


代码如下:

  1. 首先要注意,这个代码是要添加到 Excel VBA 编辑器里的!因为 OneNote 里根本就没有 VBA 编辑器,所以只能通过 Excel 里的 VBA 编辑器,来实现 OneNote 的操控和读取!
  2. 然后要注意,在运行代码前,需先添加几个 Reference (引用库)!
    • Microsoft OneNote 12.0 Object Library
    • Microsoft OneNote 15.0 Object Library
    • Microsoft XML, V3.0
  3. 不同的 Office 可能会出现,这几个库的版本不一样,那么就需要根据你的库的版本,去微调下这个代码!否则会报错!
  4. 另外这个代码中,似乎只能使用 Early Binding (静态绑定),无法使用 Late Binding (动态绑定),不知道为什么!例如代码中的 OneNote 对象,只能采用Set OneNote = New OneNote.Application的方式,而无法采用Set OneNote = CreateObject("OneNote.Application")的方式!不知道这是不是因为,我是手动添加的 OneNote 的那几个库!
'Add the following references (adjust to your office version):
'- Microsoft OneNote 12.0 Object Library
'- Microsoft OneNote 15.0 Object Library
'- Microsoft XML, v3.0

Sub ListOneNotePages()
    'OneNote will be started, if it's not running.
    Dim OneNote As OneNote.Application
    Set OneNote = New OneNote.Application

    'Get XML data (oneNotePagesXml) represents OneNote pages
    Dim oneNotePagesXml As String
    OneNote.GetHierarchy "", OneNote12.HierarchyScope.hsPages, oneNotePagesXml
    'OneNote.GetHierarchy "", 4, oneNotePagesXml

    'Use the MSXML Library to parse the XML.
    Dim doc As MSXML2.DOMDocument
    Set doc = New MSXML2.DOMDocument

    If doc.LoadXML(oneNotePagesXml) Then
        'Find all the Page nodes in the one namespace.
        Dim nodes As MSXML2.IXMLDOMNodeList
        Set nodes = doc.DocumentElement.SelectNodes("//one:Page")

        Dim node As MSXML2.IXMLDOMNode
        Dim pageName As String
        Dim sectionName As String
        Dim pageContent As String
        Dim temp As String

        'Go through each page, and print out page content
        For Each node In nodes
            pageName = node.Attributes.getNamedItem("name").Text
            Debug.Print "Page name: "; vbCrLf & " " & pageName

            Call OneNote.GetPageContent(GetAttributeValueFromNode(node, "ID"), pageContent, piBasic)
            Debug.Print " content: " & pageContent
        Next
    Else
        MsgBox "OneNote XML Data failed to load."
    End If
End Sub

Private Function GetAttributeValueFromNode(node As MSXML2.IXMLDOMNode, attributeName As String) As String
    If node.Attributes.getNamedItem(attributeName) Is Nothing Then
        GetAttributeValueFromNode = "Not found."
    Else
        GetAttributeValueFromNode = node.Attributes.getNamedItem(attributeName).Text
    End If
End Function

几个关键的函数:

  1. GetHierarchy这个方法,就只能 Get 到 PageID 和页面名字什么的,也就能读取页面的 metadata,而不是页面的真正的 Content!而若想要 Get 到页面的内容,就需要下面这个方法了!所以 GetHierarchy 所能读取的,就只有笔记本的 outline 大纲结构而已,而不是笔记的实质性内容!而这个大纲的深度,也就只能是从 1 到 4 的深度了!到 4 就是到了每页标题的深度了,也就是最深的深度了!
  2. GetPageContent这个方法,所返回的,则就是真正的 XML 格式的,页面的全部内容了!
  3. MSXML2的这个库,就只是用来解析 XML 文本的,让我们可以,按类别选取所需的内容!

Remote Procedure Call Failed 报错:

  1. 这个报错,我的理解是,它是在说,无法访问你要用的那个程序!具体为什么无法访问,我到现在也还是不知道!
  2. 在上面 VBA 的解决方案里,我只是把代码里的 OneNote12.Application,改成了 OneNote.Application 就解决了!具体为什么,不知道!但这个报错,确实就没了!我猜测是因为 OneNote 的版本的问题,之前报错,是因为它一直找不到 OneNote14.Application 这个本版本,但细节的问题就不讨论了!
  3. 但在 Python 的 win32com 方案里,则是一直都卡在,这个报错这里,一直没能过去!也因此在 Python 的解决方案里,到了最后也没能读取任何的 OneNote Page!

OneNote 无法启动问题:

  1. 如果发现,运行了 Python 的代码后,自己的 OneNote 显示正在清理,无法打开!不用担心,只需去资源管理器里,把 OneNote.exe 这个任务关掉即可。然后 OneNote 就可以正常打开了!

其他解决方案:

其实在 Excel VBA 的解决方案之前,还尝试了很多很多其他的方案,那也粗略的说一下吧,

  1. 在 OneNote 中添加 COM 插件,使其能运行宏,类似于 VBA!这个插件叫做Onetastic!据说这个插件的作者,正是原 OneNote 开发团队的成员,所以其实这个插件的质量很高,但就是要花钱买,所以最后也没采用这个方案!还有一个插件,叫Gem for OneNote,也很强悍,但不符合我的需求!OneNote 的插件还有很多,感兴趣的同学,可以去看下面的链接!

  2. 就是自己开发插件,让其能在 OneNote 中运行。这个要求有点高,这种大神应该就不用,看我这篇文章了。所以如果有能力,这也确实是个选项!

  3. 就是使用 Python 的 win32com,其实 win32com 也是使用的 windows 自己的 com 接口,但 Python 毕竟是通过一个第三库,在做这件事情,所以这个库,要是运行不畅,或者出什么问题,作为小白,就真是很难解决了!就例如一直困扰我的,Remote Procedure Call Failed 报错问题,就到现在也没能解决!这个报错很可能是,更深层的 com 服务的问题,很可能是 onenote.dll 没了什么的,但这已经超出小白的范畴了。

  4. 就是还有各种 Python 的第三方库,例如:pyOneNote,onepy 什么的!我自己几乎都试一遍了,基本没一个好使的,都是很久之前的库了!我觉得这可能是,很少有人会去操控 OneNote,所以在这上面花心思的人就很少,这也是为什么,我找了很久,都找不到答案!所以才决定写这篇文章,希望能给需要的人,一点方便!


可用的 Python 代码:

至于下列代码里,为什么都是 OneNote.Application.12 我也不知道!但如果你的不好使,也可以改成 OneNote.Application.14 试试!但在我的电脑里,只有 OneNote.Application.12 好使!

# 输出页面结构信息
import win32com.client
oneapp = win32com.client.Dispatch('OneNote.Application.12')
result = oneapp.GetHierarchy("",4)
print(result)

## 输出所有页面的标题
import win32com.client
oneapp = win32com.client.Dispatch('OneNote.Application.12')
result = oneapp.GetHierarchy("",4)

from bs4 import BeautifulSoup
soup = BeautifulSoup(result, 'xml')
for tag in soup.find_all('one:Page'):
    print(tag.attrs['name'])

# 试图输出任何一个页面的内容 (报错暂时无解)
# >>> Error occurred: (-2147023170, 'The remote procedure call failed)
import win32com.client
onapp = win32com.client.Dispatch('OneNote.Application.12')
result = onapp.GetHierarchy("",4)
print(result)

pageID = "任何上面输出过的PageID"
content = onapp.GetPageContent(pageID)
print(content)

后期应用:

被 VBA 读取出来的,是 OneNote 每个页面的全部内容!信息量很大,都是 XML 形式的!之后的处理,完全取决于各自的需求!好的就写到这里了,希望能有帮助,(^_^)b


关于 OneNote 附件的问题:

OneNote 虽然能读取页面的全部内容,但却没有任何接口,去读取或导出,页面里的附件!所以这也是个很无语的问题,尝试了很久,依然找不到什么解决方案!理论上附件应该就是储存在 OneNote 的文件里,但实际上你就是找不着,也无法导出!可能是被 OneNote 加密了!这也是个目前未解决的问题!若有大神有什么办法,还望不吝指点!多谢!


Reference:

  1. Automate Onenote 2010 From Excel 2007, using VBA - Stack Overflow
  2. Updating OneNote from VBA Excel - Stack Overflow
  3. OneNote developer reference | Microsoft Learn
  4. reading xml files in vb6 - Stack Overflow
  5. Top 11 Microsoft OneNote Add-ins
  6. Onetastic for OneNote
  7. Is there a way to talk to OneNote through code? - Stack Overflow
  8. Creating a Page in a Notebook in OneNote 2010 | Microsoft Learn
  9. Using Excel VBA to Push Content to OneNote
  10. Enumerations (OneNote developer reference) | Microsoft Learn
  11. OneNote add-ins documentation | Microsoft Learn
  12. OneNote 开发人员参考 | Microsoft Learn
posted @ 2024-10-22 09:53  Bitssea  阅读(135)  评论(0编辑  收藏  举报