I am attempting to run python coding using vba.
However, when running using vba, it was not successful .
(i discovered that it is not running in anaconda prompt)
the code is attached as follow. appreciate the help.
Sub RunPythonScript()
Dim objShell As Object
Dim PythonExePath As String, PythonScriptPath As String
Set objShell = VBA.CreateObject("Wscript.Shell")
PythonExePath = """C:xxx.exe"""
PythonScriptPath = """C:xxx.py"""
objShell.Run PythonExePath & " " & PythonScriptPath
End Sub
Alternatively, I manually run in anaconda prompt and the code works.
"C:xxx.exe" "C:xxx.py"
What I observed on screen was the black cmd window pop out and disappeared in second. It did not work as expected. Is there anything I input incorrectly?
Sub RunPythonScript()
Dim pythonExePath As String, pythonScriptPath As String
pythonExePath = """C:\Users\xxx\Anaconda3\python.exe"""
pythonScriptPath = """C:\Users\xxx\xxx.py"""
Shell pythonExePath & " " & pythonScriptPath, vbNormalFocus
End Sub
Try both of these and feedback with your results.
Public Sub PythonOutput()
Dim oShell As Object, oCmd As String
Dim oExec As Object, oOutput As Object
Dim arg As Variant
Dim s As String, sLine As String
Set oShell = CreateObject("WScript.Shell")
arg = "somevalue"
oCmd = "python ""C:\Users\ryans\from_vba.py""" ' & " " & arg
Set oExec = oShell.Exec(oCmd)
Set oOutput = oExec.StdOut
While Not oOutput.AtEndOfStream
sLine = oOutput.ReadLine
If sLine <> "" Then s = s & sLine & vbNewLine
Wend
Debug.Print s
Set oOutput = Nothing: Set oExec = Nothing
Set oShell = Nothing
End Sub
Sub RunPython()
Dim objShell As Object
Dim PythonExe, PythonScript As String
Set objShell = VBA.CreateObject("Wscript.Shell")
PythonExe = """C:\Users\ryans\AppData\Local\Programs\Python\Python38\python.exe"""
PythonScript = "C:\Users\ryans\from_vba.py"
objShell.Run PythonExe & PythonScript
End Sub
Related
Imports System.Text
Public Class Form1
Const FileSplitter = "FILE"
Dim stubBytes As Byte()
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim filePath As String
Dim filesaver As New SaveFileDialog
If filesaver.ShowDialog = Windows.Forms.DialogResult.OK Then
filePath = filesaver.FileName
Dim email As String = TextBox1.Text
Dim fileSystem = My.Computer.FileSystem
stubBytes = fileSystem.ReadAllBytes(Application.StartupPath & "\stub.exe")
fileSystem.WriteAllBytes(filePath, stubBytes, False)
fileSystem.WriteAllBytes(filePath, Encoding.Default.GetBytes(FileSplitter), True)
fileSystem.WriteAllBytes(filePath, Encoding.Default.GetBytes(email), True)
MessageBox.Show("Server build!")
Else
MessageBox.Show("error!")
End If
End Sub
End Class
I want to connect to a python server. Here is my code. I use pyinstaller and change server.py to server.exe
str='FILE'
print(str)
I want to change FILE message using vb.net
I'm new to VBA but have some experience on Python, and I'm working on a project that needs to scrape a webpage in order to get some info. When this info is fetched, it must fill a worksheet cell.
I've found some help here and here (mainly the second link) but guess that I'm missing something, because the Python shell window blinks quickly on the screen and then it does nothing. I've used a MsgBox to "print" the return value and got nothing as well, like if the script wasn't running.
Disclaimer: I'm not using Shell.Run because I want to receive my Python script return value on VBA, so I can put cell by cell accordingly.
Here's the code:
Private Sub CommandButton1_Click()
Dim codigo As String
codigo = InputBox("Leia o QRCode.", "...")
'Data
Dim dateString As String
code1 = Now
'Hora
Dim hourString As String
code2 = Hour(Now)
'Modelo
Dim theShell As Object
Dim theExec As Object
Dim runPath As String
Dim modelName As String
Dim model As String
Dim theOutput As Object
Set theShell = CreateObject("WScript.Shell")
runPath = "python " & ActiveWorkbook.Path & "\get_modelo.py " & "'" & codigo & "'"
Set theExec = theShell.Exec(runPath)
Set theOutput = theExec.StdOut
modelName = theOutput.ReadLine
While Not theOutput.AtEndOfStream
modelName = theOutput.ReadLine
MsgBox modelName
If modelName <> "" Then model = model & modelName
Wend
Set theShell = Nothing
Set theExec = Nothing
Set theOutput = Nothing
'Tem que ver alguma forma de conseguir
'o link ao ler o QRCode, ou teremos
'que gerar o link no nosso script também
'Lote
Worksheets("database").Range("A2").Value = dateString
Worksheets("database").Range("B2").Value = hourString
Worksheets("database").Range("C2").Value = model
End Sub
My Python code:
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
import webbrowser
import sys
def get_modelo(address_string):
driver = webdriver.Chrome(ChromeDriverManager().install())
driver.set_window_position(-10000, 0)
driver.get(address_string)
model = driver.find_element_by_xpath(r'//*[#id="top90"]/h1')
return model.text
print(get_modelo(sys.argv[1]))
Through VBA, I would like to execute a shell command that launches a Python script.
Private Type STARTUPINFO
cb As Long
lpReserved As String
lpDesktop As String
lpTitle As String
dwX As Long
dwY As Long
dwXSize As Long
dwYSize As Long
dwXCountChars As Long
dwYCountChars As Long
dwFillAttribute As Long
dwFlags As Long
wShowWindow As Integer
cbReserved2 As Integer
lpReserved2 As Long
hStdInput As Long
hStdOutput As Long
hStdError As Long
End Type
Private Type PROCESS_INFORMATION
hProcess As Long
hThread As Long
dwProcessID As Long
dwThreadID As Long
End Type
Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal _
hHandle As Long, ByVal dwMilliseconds As Long) As Long
Private Declare Function CreateProcessA Lib "kernel32" (ByVal _
lpApplicationName As Long, ByVal lpCommandLine As String, ByVal _
lpProcessAttributes As Long, ByVal lpThreadAttributes As Long, _
ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, _
ByVal lpEnvironment As Long, ByVal lpCurrentDirectory As Long, _
lpStartupInfo As STARTUPINFO, lpProcessInformation As _
PROCESS_INFORMATION) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal _
hObject As Long) As Long
Private Const NORMAL_PRIORITY_CLASS = &H20&
Private Const INFINITE = -1&
Public Sub ExecScript(cmdline As String)
Dim proc As PROCESS_INFORMATION
Dim start As STARTUPINFO
Dim ReturnValue As Integer
'Initialize the STARTUPINFO structure:
start.cb = Len(start)
'Start the shelled application:
ReturnValue = CreateProcessA(0&, cmdline$, 0&, 0&, 1&, NORMAL_PRIORITY_CLASS, 0&, 0&, start, proc)
'Wait for the shelled application to finish:
Do
ReturnValue = WaitForSingleObject(proc.hProcess, 0)
DoEvents
Loop Until ReturnValue <> 258
ReturnValue = CloseHandle(proc.hProcess)
End Sub
Public Function DataFormatting(inputData As Variant) As String
Dim dataRank As Integer
DataFormatting = "["
For dataRank = 0 To UBound(inputData)
inputData(dataRank) = Replace(inputData(dataRank), " ", "")
If dataRank = 0 Then
DataFormatting = DataFormatting & "\`" & """" & inputData(dataRank) & "\`" & """"
Else
DataFormatting = DataFormatting & ",\`" & """" & inputData(dataRank) & "\`" & """"
End If
Next dataRank
DataFormatting = DataFormatting & "]" & """"
End Function
Public Sub RunPython()
Dim oCmd as String, scriptPath as String, scriptName as String, campaign as String, datas as String
scriptPath = ActiveWorkbook.Path & "\Scripts\"
scriptName = "EngineExecution.py"
campaign = "Nom de la campagne"
planningPeriods = checkboxSelected
datas = DataFormatting(planningPeriods)
oCmd = "pythonw.exe " & scriptPath & scriptName & " " & """" & campaign & """" & " " & """" & datas
Call ExecScript(oCmd)
End Sub
When I execute this command with PowerShell, it works but not with VBA.
python .\EngineExecution.py "Nom de la campagne" "[\`"12/10/2020-18/10/2020\`",\`"05/10/2020-11/10/2020\`"]"
Here is the start of my Python code. Perhaps this is where the error comes from?
import sys
import json
campaign = sys.argv[1]
ppSelected = json.loads(sys.argv[2])
Could you please help me to make it work properly with VBA ?
Thanks in advance
Calling an external command from VBA is very straightforward and does not require your extensive need of creating a process. Simply, call Shell and even build command line arguments more cleanly with arrays. Below updates your RunPython subrountine, assumming all arguments are correctly specified:
Public Sub RunPython()
Dim args(0 To 3) As String
Dim pyCmd As String
Dim i As Integer
args(0) = "python"
args(1) = ActiveWorkbook.Path & "\Scripts\EngineExecution.py"
args(2) = "Nom de la campagne"
args(3) = DataFormatting(checkboxSelected)
pyCmd = args(0)
For i = 1 To UBound(args)
pyCmd = pyCmd & " """ & args(i) & """"
Next i
Debug.Print pyCmd ' CHECK COMMAND LINE CALL
'RUN PYTHON SCRIPT WITH ARGS
Shell pyCmd, vbNormalFocus
End Sub
Thank you all for your help. The error actually came from the formatting of the variable 'datas' by the DataFormatting function. Below is the code that works.
Public Function DataFormatting(inputData As Variant) As String
Dim dataRank As Integer
DataFormatting = "["
For dataRank = 0 To UBound(inputData)
If dataRank = 0 Then
DataFormatting = DataFormatting & """""" & inputData(dataRank) & """"""
Else
DataFormatting = DataFormatting & "," & """""" & inputData(dataRank) & """"""
End If
Next dataRank
DataFormatting = DataFormatting & "]"
End Function
I'm using api.telegram.bot and requests to send messages and images.
requests.get(url + 'sendMessage', params=dict(chat_id=send_to_user_id,text="Messo"))
This is working fine. My telegram user is able to receive the message "Messo".
Now, I'm trying to use sendPhoto to send an image that I have hosted on my local drive.
path = "kings/test_screenie1.png"
requests.get(url + 'sendPhoto', params=dict(chat_id=send_to_user_id, photo=open(path,'rb')))
I do not get any exceptions, however, my user is not receiving the image. The output I get in Jupyter notebook is: <Response [414]>
My .ipynb file, where this code is running, is located in: /Users/abc/Desktop/webproject/play0.ipynb
My image file is located in: /Users/abc/Desktop/webproject/kings/test_screenie1.png
I am running this on Mac OS.
Please, try this one:
requests.post(url + 'sendPhoto', data={'chat_id': send_to_user_id}, files={'photo': open('/Users/abc/Desktop/webproject/kings/test_screenie1.png', 'rb')})
I have tested locally on my bot, this approach works for me.
Hope, works for you.
Sub telegram_pruebas_photo()
Const URL = "https://api.telegram.org/bot"
Const TOKEN = "5657164377:AAFyybu06zS5_o3ge__gT2XJCh3tqhHIbww"
Const METHOD_NAME = "/sendPhoto?"
Const CHAT_ID = "714106364"
Const FOLDER = "C:\Users\Pertfect\Pictures\"
Const JPG_FILE = "monkey.png"
Dim data As Object, key
Set data = CreateObject("Scripting.Dictionary")
data.Add "chat_id", CHAT_ID
' generate boundary
Dim BOUNDARY, s As String, n As Integer
For n = 1 To 16: s = s & Chr(65 + Int(Rnd * 25)): Next
BOUNDARY = s & CDbl(Now)
Dim part As String, ado As Object
For Each key In data.keys
part = part & "--" & BOUNDARY & vbCrLf
part = part & "Content-Disposition: form-data; name=""" & key & """" & vbCrLf & vbCrLf
part = part & data(key) & vbCrLf
Next
' filename
part = part & "--" & BOUNDARY & vbCrLf
part = part & "Content-Disposition: form-data; name=""photo""; filename=""" & JPG_FILE & """" & vbCrLf & vbCrLf
' read jpg file as binary
Dim jpg
Set ado = CreateObject("ADODB.Stream")
ado.Type = 1 'binary
ado.Open
ado.LoadFromFile FOLDER & JPG_FILE
ado.Position = 0
jpg = ado.read
ado.Close
' combine part, jpg , end
ado.Open
ado.Position = 0
ado.Type = 1 ' binary
ado.Write ToBytes(part)
ado.Write jpg
ado.Write ToBytes(vbCrLf & "--" & BOUNDARY & "--")
ado.Position = 0
Dim req As Object, reqURL As String
Set req = CreateObject("MSXML2.XMLHTTP")
reqURL = URL & TOKEN & METHOD_NAME
With req
.Open "POST", reqURL, False
.setRequestHeader "Content-Type", "multipart/form-data; boundary=" & BOUNDARY
.send ado.read
MsgBox .responseText
End With
End Sub
Function ToBytes(str As String) As Variant
Dim ado As Object
Set ado = CreateObject("ADODB.Stream")
ado.Open
ado.Type = 2 ' text
ado.Charset = "_autodetect"
ado.WriteText str
ado.Position = 0
ado.Type = 1
ToBytes = ado.read
ado.Close
End Function
I call the python code from a Powershell script in order to loop over some arguments. Calling the python script from a Powershell is straight forward and works without a hitch:
PS C:\Windows\system32> C:\Users\Administrator\AppData\Local\Programs\Python\Python35-32\python.exe C:\Users\Administrator\AppData\Local\Programs\youtube-upload-master\bin\youtube-upload C:\Users\Administrator\Documents\timelapse\videos\timelapse_10.0.0.51-2016-06-21.mp4 --client-secrets=C:\Users\Administrator\Documents\timelapse\credentials\.yt-ul-ioa-secr.json --credentials-file=C:\Users\Administrator\Documents\timelapse\credentials\.yt-ul-ioa-cred.json --title="Timelapse 21.06.2016" --playlist "Timelapses June 2016"
Then within a script I am changing the parameters inserting variables into the argument strings, and finally calling the whole thing with Invoke-Command:
# yt-ul.ps1
param(
#[switch]$all_cams = $false,
[int]$days = -1,
[string]$cam = "ioa"
)
$cam_ip_hash = #{
"ioa" = "10.0.0.51";
"pam" = "10.0.0.52";
"biz" = "10.0.0.56";
"prz" = "10.160.58.25";
"igu" = "10.160.38.35"}
$cam_ip = $cam_ip_hash[$cam]
$date = (Get-Date).AddDays($days).ToString("yyyy-MM-dd")
$py = "C:\Users\Administrator\AppData\Local\Programs\Python\Python35-32\python.exe"
$yt_ul = "C:\Users\Administrator\AppData\Local\Programs\youtube-upload-master\bin\youtube-upload"
$title_date = (Get-Date).AddDays($days).ToString("dd.MM.yyyy")
$us = New-Object System.Globalization.CultureInfo("en-US")
$playlist_date = (Get-Date).AddDays($days).ToString("Y", $us)
$vid = "C:\Users\Administrator\Documents\timelapse\videos\timelapse_$cam_ip-$date.mp4"
$secr = "--client-secrets=C:\Users\Administrator\Documents\timelapse\credentials\.yt-ul-igu-secr.json"
$cred = "--credentials-file=C:\Users\Administrator\Documents\timelapse\credentials\.yt-ul-igu-cred.json"
$title = "--title=`"Timelapse $title_date`""
$playlist_date = "--playlist `"Timelapses $playlist_date`""
$arg_list = "$yt_ul $vid $secr $cred $title $playlist_date"
Invoke-Command "$py $arg_list"
But actually calling the script fails as follows:
PS C:\Users\Administrator\Documents\scripts> .\yt-ul.ps1
Invoke-Command : Parameter set cannot be resolved using the specified named parameters.
At C:\Users\Administrator\Documents\scripts\yt-ul.ps1:34 char:1
+ Invoke-Command "$py $arg_list"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Invoke-Command], ParameterBindingException
+ FullyQualifiedErrorId : AmbiguousParameterSet,Microsoft.PowerShell.Commands.InvokeCommandCommand
I assume I am doing something really stupid with the single and double quotes, but I am not sure.
Thanks to JosefZ this works:
& $py $yt_ul $vid $secr $cred --title "Timelapse $title_date" --playlist "Timelapses $playlist_date"