使用 Python 使用 Uno 访问 LibreOffice Calc
Using Python to access LibreOffice Calc using Uno
我正在尝试使用 Python 3.7 编写脚本来操作 Ubuntu Mint _LibreOffice Calc sheet。出于某种原因,我在尝试导入 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 与 sheet 交互。有没有我需要设置为 Uno_
的路径
使用 LibreOffice 6.4、Python 3.7 和 APSO。我对 LibreOffice 感到非常沮丧,似乎 python 对新手的支持很少。
经过大量研究,我弄清楚了如何使用 Python 3.7、PyCharm 和 MySQL 来操作 Ubuntu LibreOffice Calc sheet .我是所有这一切的新手,所以请原谅我的编码,我还在学习。我提供了用于完成此项目的信息源的链接。
导致我出现问题的主要障碍是不了解 LibreOffice 需要在通过套接字连接之前启动。之后,我能够使用 Uno 和其他模块与 Calc spreadsheet 进行交互。我提供了所有 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://pjryan126.github.io/jupyter-db-connections/
Add dataframe and button to same sheet with XlsxWriter
https://pynative.com/python-mysql-database-connection/
感谢所有帮助过的人。
我遇到了同样的问题,我是这样解决的:
- 在 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()
- 你可以在这里找到我的实现:https://github.com/CosminEugenDinu/libreoffice-python-library
- 祝你好运!
我正在尝试使用 Python 3.7 编写脚本来操作 Ubuntu Mint _LibreOffice Calc sheet。出于某种原因,我在尝试导入 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 与 sheet 交互。有没有我需要设置为 Uno_
的路径使用 LibreOffice 6.4、Python 3.7 和 APSO。我对 LibreOffice 感到非常沮丧,似乎 python 对新手的支持很少。
经过大量研究,我弄清楚了如何使用 Python 3.7、PyCharm 和 MySQL 来操作 Ubuntu LibreOffice Calc sheet .我是所有这一切的新手,所以请原谅我的编码,我还在学习。我提供了用于完成此项目的信息源的链接。
导致我出现问题的主要障碍是不了解 LibreOffice 需要在通过套接字连接之前启动。之后,我能够使用 Uno 和其他模块与 Calc spreadsheet 进行交互。我提供了所有 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://pjryan126.github.io/jupyter-db-connections/
Add dataframe and button to same sheet with XlsxWriter
https://pynative.com/python-mysql-database-connection/
感谢所有帮助过的人。
我遇到了同样的问题,我是这样解决的:
- 在 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()
- 你可以在这里找到我的实现:https://github.com/CosminEugenDinu/libreoffice-python-library
- 祝你好运!