write with una tutorial trabajar modificar manejo leer hoja desde crear con cargar archivos python excel vba macros

with - trabajar excel en python



Actualizar enlaces en hoja de cálculo de Excel con Python (1)

Considere que Python ejecute directamente el método UpdateLink con los objetos COM que inicializa, es decir, los objetos xl_app y wb . No es necesario crear una macro en cada libro de trabajo y luego llamarlo.

Debajo de UpdateLink() se UpdateLink() un bloque try/except/finally en caso de que el libro de trabajo no tenga enlaces, ya que LinkSources devolverá un valor Empty , generando una excepción COM, el mismo error que recibes:

error de tiempo de ejecución ''1004'' método ''updatelink'' método del objeto ''_workbook'' fallido

También asegúrese de desinicializar los objetos (una buena práctica recomendada en VBA también: Set wb = Nothing ) luego de usarlos para liberar recursos de la CPU o permanecer como procesos en segundo plano hasta la recolección de basura.

def run_macro(workbook_name, com_instance): wb = com_instance.workbooks.open(workbook_name) com_instance.AskToUpdateLinks = False try: wb.UpdateLink(Name=wb.LinkSources()) except Exception as e: print(e) finally: wb.Close(True) wb = None return True def main(): dir_root = ("C://Model_Spreadsheets") xl_app = Dispatch("Excel.Application") xl_app.Visible = False xl_app.DisplayAlerts = False for root, dirs, files in os.walk(dir_root): for fn in files: if fn.endswith(".xlsx") and fn[0] is not "~": run_macro(os.path.join(root, fn), xl_app) xl_app.Quit() xl = None

Aparte, aunque VBA se envía por defecto con las aplicaciones de Excel y MS Office, en realidad es un componente separado. Para verificar, en Herramientas / Referencias en VBA IDE, verá que VBA es el primer elemento marcado, no tiene nada incorporado. De hecho, VBA hace exactamente lo que está haciendo en Python: crear una interfaz COM para la Biblioteca de objetos de Excel. Entonces, en cierto sentido, VBA está relacionado con Excel y con Python.

Estoy ejecutando simulaciones en Python que generan resultados que deben ser consumidos directamente por un modelador en sus libros de trabajo de Excel. He generado código que generará directamente mis datos en su plantilla de hoja de cálculo de Excel. El código que he generado para generar los datos directamente a su plantilla está bien, pero el problema con el que me estoy encontrando es que el modelador tiene una serie de libros de trabajo que están "vinculados" entre sí. Si inserto mis datos en su hoja de cálculo, los enlaces a ese libro de trabajo no se actualizan a menos que el usuario abra físicamente el libro de trabajo para "Editar enlaces" -> "Actualizar valores". Si había un libro de trabajo, entonces el usuario simplemente puede abrir el libro de trabajo sin ningún problema. En realidad, habrá más de 100 libros de trabajo que necesitan que los enlaces estén actualizados. Lamentablemente, no hay nada que pueda hacer para cambiar el enfoque del modelador al vincular los libros de trabajo: lo único que puedo hacer es adaptar su enfoque.

Mi objetivo es crear una solución de Python que me permita 1) Generar los datos simulados, 2) Insertar mis datos generados en el libro de trabajo del modelador, y 3) Actualizar todos los enlaces entre los libros de trabajo. En última instancia, para ser optimizado, quiero poder hacer los tres en un programa de punta a punta de python. He resuelto (1) y (2), y tengo una solución para (3) que casi funciona. He generado el siguiente script funcional:

from win32com.client import Dispatch import pandas as pd from openpyxl import load_workbook import os import time def run_macro(workbook_name, vba_sub, com_instance): wb = com_instance.workbooks.open(workbook_name) wb.RefreshAll() xl_module = wb.VBProject.VBComponents.Add(1) xl_module.CodeModule.AddFromString(vba_sub.strip()) com_instance.Application.Run(''UpdateLinkValues'') wb.Save() wb.Close() return True def main(): dir_root = ("C://Model_Spreadsheets") vba_sub = / '''''' sub UpdateLinkValues() Application.AskToUpdateLinks = False ActiveWorkbook.UpdateLink Name:=ActiveWorkbook.LinkSources end sub '''''' xl_app = Dispatch("Excel.Application") xl_app.Visible = False xl_app.DisplayAlerts = False for root, dirs, files in os.walk(dir_root): for fn in files: if fn.endswith(".xlsx") and fn[0] is not "~": run_macro(os.path.join(root, fn), vba_sub, xl_app) xl_app.Quit() if __name__ == "__main__": main()

Este script está realmente cerca de la solución correcta que estoy buscando, pero me encuentro con un error de VBA aparentemente ''aleatoriamente'':

run-time error ''1004'' method ''updatelink'' method of object ''_workbook'' failed

Este error aparece cada vez que intento ejecutar este script, pero no ocurre para el mismo libro de trabajo cada vez; a veces, aparece en el primer libro de trabajo, a veces el día 15, etc.

Tengo una opción para depurar en VBA, y la única forma en que puedo continuar con el próximo libro de trabajo es si cambio la macro a

sub UpdateLinkValues() Application.AskToUpdateLinks = False end sub

si ejecuto esta macro y salgo de la depuración, el programa continuará ejecutándose hasta que vuelva a encontrar el mismo error. Lo primero que pensé fue que tal vez haya un problema de tiempo entre la apertura del libro de trabajo y el intento de ejecutar la macro. Una solución alternativa que he encontrado es que puedo cambiar la macro y la visibilidad de la aplicación:

vba_sub = / '''''' sub UpdateLinkValues() Application.AskToUpdateLinks = False end sub ''''''

y

xl_app.Visible = True

Esto funciona bien, pero no soy partidario de tener todos los libros de trabajo abiertos y cerrados porque lleva mucho tiempo. Mi pregunta es, ¿alguien sabe por qué está surgiendo este error en tiempo de ejecución, con una solución? O quizás, ¿alguien sabe cómo interceptar este error en tiempo de ejecución en Python como una excepción? Si puedo interceptar este error como una excepción en Python, entonces podría usar mi solución alternativa para esos libros de datos particulares.

¡Gracias por adelantado!