【问题标题】:Using Python to access LibreOffice Calc using Uno使用 Python 使用 Uno 访问 LibreOffice Calc
【发布时间】:2020-03-13 01:14:01
【问题描述】:

我正在尝试编写一个脚本来使用 Python 3.7 操作 Ubuntu Mint _LibreOffice Calc 表。出于某种原因,当我尝试导入 Uno 时出现错误。我可以在 Calc 中运行一个宏来调用它

    desktop = XSCRIPTCONTEXT.getDesktop()
    model = desktop.getCurrentComponent()
    active_sheet = model.CurrentController.ActiveSheet
    write 'Hello World' in A1
    active_sheet.getCellRangeByName("A1").String = "Hello World!

"

但不能直接从 VS_code IDE 与工作表进行交互。有没有我需要设置为 Uno_ 的路径?

使用 LibreOffice 6.4、Python 3.7 和 APSO。我对 LibreOffice 感到非常沮丧,似乎对新手的 python 支持很少。

【问题讨论】:

  • 如果我开始使用 Python 通过 UNO 对 LO 进行外部控制并且遇到问题(Java 是我现在使用的),我可能会仔细看看Designing & Developing Python Applications,尤其是标题为“从 IDE 通过 LibreOffice Python 解释器”的部分。
  • 感谢 Dave,我一直在玩它,但一定没有正确设置环境。我可以从 LibreOffice 内部运行 py 脚本,但我仍然无法使用我的 IDE 从外部连接。我想在这一点上,我将朝着另一个方向前进。不幸的是,我认为 LO 尚不支持 python。
  • 通常Ubuntu不需要这个,但可能你的系统缺少所需的包:wiki.documentfoundation.org/Macros/Python_Guide/…
  • 谢谢吉姆,我已经放弃尝试让它工作了。当我在 LibreOffice 中运行脚本时,我可以让 python 正常工作,但是一旦我尝试使用 IDE,就会出现 pyuno 错误和 Com 错误。我已经按照建议的文件中的示例进行操作,但没有运气。所有的信息似乎都有些过时了。我还没有找到真正能够做到这一点的人。
  • 嗨,吉姆,我不能就这样放弃这项工作。我一直在努力并想通了。看看我的解决方案。任何反馈将不胜感激。

标签: python-3.x libreoffice-calc uno


【解决方案1】:

我遇到了同样的问题,我是这样解决的:

  • 在 Ubuntu 20 中安装 libreoffice:
sudo apt update
sudo apt install libreoffice --no-install-recommends
  • 检查 uno 是否可以访问(在我的情况下,这就是我所做的全部):
python3
Python 3.8.5 (default, Jul 28 2020, 12:59:40)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import uno
>>> print(uno.__file__)
/usr/lib/python3/dist-packages/uno.py
>>> exit()
  • 使用打开的套接字启动 libreoffice 进程(更多信息 here - 第 117 页):
/usr/lib/libreoffice/program/soffice.bin --headless --invisible --nocrashreport --nodefault --nofirststartwizard --nologo --norestore --accept='socket,host=localhost,port=2002,tcpNoDelay=1;urp;StarOffice.ComponentContext'
  • 打开另一个终端,进入python3交互模式:
import uno
local_ctx = uno.getComponentContext()
smgr_local = local_ctx.ServiceManager
resolver = smgr_local.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", local_ctx)
url = "uno:socket,host=localhost,port=2002,tcpNoDelay=1;urp;StarOffice.ComponentContext"
  • 现在尝试连接:
uno_ctx = resolver.resolve(url)
  • 如果成功,uno context 就是你所需要的
  • 实例化桌面(所有应用程序的根框架 - Calc、Writer、Draw ...)
uno_smgr = uno_ctx.ServiceManager
desktop = uno_smgr.createInstanceWithContext("com.sun.star.frame.Desktop", uno_ctx )
  • 创建一个新的 Calc 文档 (private:factory/scalc):
PropertyValue = uno.getClass('com.sun.star.beans.PropertyValue')
inProps = PropertyValue( "Hidden" , 0 , True, 0 ), # this is a tuple
document = desktop.loadComponentFromURL("private:factory/scalc", "_blank", 0, inProps )
  • 玩弄文档:
sheets = document.getSheets()
sheet_1 = sheets[0]
cell_1 = sheet_1.getCellByPosition(1,1)
value = cell_1.setString('Hello World!')
  • 保存并检查结果:
# UNO requires absolute paths
import os
path = os.path.abspath('./testfile.xls')
uno_url = uno.systemPathToFileUrl(path)
# Filters used when saving document.
# https://github.com/LibreOffice/core/tree/330df37c7e2af0564bcd2de1f171bed4befcc074/filter/source/config/fragments/filters
filter = uno.createUnoStruct('com.sun.star.beans.PropertyValue')
filter.Name = 'FilterName'
filter.Value = 'Calc MS Excel 2007 XML'
filters = (filter,)
# use filters = () to save file as *.ods

document.storeToURL(uno_url, filters)
  • 别忘了终止进程:
desktop.terminate()

【讨论】:

    【解决方案2】:

    经过大量研究,我已经弄清楚如何使用 Python 3.7 和 PyCharm 和 MySQL 操作 Ubuntu LibreOffice Calc 表。我是一个新手,所以请原谅我的编码,我还在学习。我已经提供了我用来完成这个项目的信息源的链接。

    导致我出现问题的主要障碍是不了解在通过套接字连接之前需要启动 LibreOffice。之后,我可以使用 Uno 和其他模块与 Calc 电子表格进行交互。我提供了所有 Py 脚本的副本。希望这会帮助像我一样不熟悉这个环境的人。

    # opens connection to mysql database GVWC
    import mysql.connector
    import pandas as pd
    from gui import validateLogin
    
    def conn_mysql():
        validateLogin #opens input box for username and password
        us, pw=validateLogin() #returns login info
        cnx = mysql.connector.connect(user=us, password=pw ,host='localhost', database= 'GVWC') # connects to DB
        pd.set_option('display.max_columns', None)
        df = pd.read_sql("SELECT * FROM GVWC.2020", cnx) #runs query
        return df, pd #returns data
    print("Database connection resolved.")
    
    # connection to libreoffice
    
    import uno
    import os
    import time
    
    def lo_conn():
        #Open socket to LibraOffice with delay to allow program to wait for connection
        os.popen('/usr/lib/libreoffice/program/soffice --accept="socket,host=localhost,port=2002;urp;StarOffice.ServiceManager"')
        time.sleep(3)  # Sleep for 3 seconds
    
        #=======================================================================================================================================
        # get the uno component context from the PyUNO runtime
        localContext = uno.getComponentContext()
    
        # create the UnoUrlResolver
        resolver = localContext.ServiceManager.createInstanceWithContext(
            "com.sun.star.bridge.UnoUrlResolver", localContext)
    
        # connect to the running office
        ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
        smgr = ctx.ServiceManager
    
    # create input box for login info
    from tkinter import *
    from functools import partial
    
    def validateLogin(username, password):
        #print("username entered :", username.get())
        #print("password entered :", password.get())
        global pw
        pw = password.get()
        global us
        us = username.get()
        return us, pw
    
    #window
    tkWindow = Tk()
    tkWindow.geometry("500x100+500+300")
    tkWindow.title('Tkinter Login Form - pythonexamples.org')
    
    #username label and text entry box
    usernameLabel = Label(tkWindow, text="User Name").grid(row=0, column=0)
    username = StringVar()
    usernameEntry = Entry(tkWindow, textvariable=username).grid(row=0, column=1)
    
    #password label and password entry box
    passwordLabel = Label(tkWindow,text="Password").grid(row=1, column=0)
    password = StringVar()
    passwordEntry = Entry(tkWindow, textvariable=password, show='*').grid(row=1, column=1)
    
    validateLogin = partial(validateLogin, username, password)
    
    #login button
    loginButton = Button(tkWindow, text="Login", command=validateLogin).grid(row=4, column=0)
    
    tkWindow.mainloop()
    
    
    #main program to create spreedsheet and fill with data from mysql
    
    import os
    from workingConn3 import conn_mysql
    from lo_conn_3 import lo_conn
    
    def main():
        conn_mysql # call mysql def connection
        df,pd=conn_mysql() # pass table data
        lo_conn #connect to Libreoffice
    
        # open calc and fill spreedsheet
        #=====================================================================================================================================
        writer = pd.ExcelWriter('Test_DF.xlsx',
                                    engine='xlsxwriter',
                                    datetime_format='mm/dd/yyyy')
    
        df.to_excel(writer, index=False, sheet_name='TEST',
                       startrow=5, header = 4)
    
        #Get the xlsxwriter objects from the dataframe writer object.
        workbook  = writer.book
        worksheet = writer.sheets['TEST']
    
    
    
        #Add a header format.
        header_format = workbook.add_format({
            'font_color': 'white',
            'text_wrap': True,
            'font_name': 'Calibri',
            'font_size': 11,
            'fg_color': '#44546a'})
    
        # Write the column headers with the defined format.
        for col_num, value in enumerate(df.columns.values):
            worksheet.write(5, col_num, value, header_format)
    
        colwidths = {}
    
        # Store the defaults.
        for col in range(14):
            colwidths[col] = 15
    
    
    
        # Then set the column widths.
        for col_num, width in colwidths.items():
            worksheet.set_column(col_num, col_num, width)
    
    
        #Center text of column
        cell_format = workbook.add_format()
        cell_format.set_align('center')
        worksheet.set_column('E1:E100',15,cell_format)
        worksheet.set_column('F1:F100',15,cell_format)
        worksheet.set_column('M1:M100',15,cell_format)
    
        #  Freeze pane on the header row.
        #
        worksheet.freeze_panes(6, 0)
        worksheet.autofilter('A6:O6')
    
        #Button text
        worksheet.write('A3', 'Press the button to say hello.')
    
        # Add a button tied to a macro in the VBA project.
        worksheet.insert_button('A1', {'macro': 'start',
                                       'caption': 'Press Me',
                                       'width': 80,
                                       'height': 30})
    
        # Close the Pandas Excel writer and output the Excel file.
        writer.save()
        writer.close()
        #reopen excel file
        os.popen('/usr/lib/libreoffice/program/soffice Test_DF.xlsx  --accept="socket,host=localhost,port=2002;urp;StarOffice.ServiceManager"')
    
    
    if __name__== "__main__" :
        main()
    

    https://medium.com/analytics-vidhya/macro-programming-in-openoffice-libreoffice-with-using-python-en-a37465e9bfa5

    https://medium.com/analytics-vidhya/starting-libreoffice-with-python-macro-programming-in-openoffice-libreoffice-with-using-10310f9e69f1

    https://pjryan126.github.io/jupyter-db-connections/

    http://christopher5106.github.io/office/2015/12/06/openoffice-libreoffice-automate-your-office-tasks-with-python-macros.html

    https://help.libreoffice.org/6.4/en-US/text/shared/guide/start_parameters.html?&DbPAR=WRITER&System=UNIX

    https://www.saltycrane.com/blog/2010/02/using-python-write-excel-openoffice-calc-spreadsheet-ubuntu-linux/

    Add dataframe and button to same sheet with XlsxWriter

    https://pynative.com/python-mysql-database-connection/

    感谢所有帮助过的人。

    【讨论】:

      猜你喜欢
      • 2020-12-19
      • 1970-01-01
      • 2016-03-31
      • 1970-01-01
      • 1970-01-01
      • 2014-10-17
      • 2013-03-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多