这两天无意间看到python有c api,之前孤陋寡闻了,然后就用本机已安装的环境调用测试了下确实可以哟Local $pythonDll = DllOpen("C:\Users\subtlelonging\AppData\Local\Programs\Python\Python312\python312.dll")
DllCall($pythonDll, "none", "Py_Initialize")
DllCall($pythonDll, "int", "PyRun_SimpleString", "str", "def add(a, b): return a + b")
Local $pFunc = DllCall($pythonDll, "ptr", "PyObject_GetAttrString", "ptr", DllCall($pythonDll, "ptr", "PyImport_AddModule", "str", "__main__")[0], "str", "add")[0]
Local $pArgs = DllCall($pythonDll, "ptr", "PyTuple_New", "int", 2)[0]
DllCall($pythonDll, "none", "PyTuple_SetItem", "ptr", $pArgs, "int", 0, "ptr", DllCall($pythonDll, "ptr", "PyLong_FromLong", "long", 5)[0])
DllCall($pythonDll, "none", "PyTuple_SetItem", "ptr", $pArgs, "int", 1, "ptr", DllCall($pythonDll, "ptr", "PyLong_FromLong", "long", 7)[0])
Local $result = DllCall($pythonDll, "long", "PyLong_AsLong", "ptr", DllCall($pythonDll, "ptr", "PyObject_CallObject", "ptr", $pFunc, "ptr", $pArgs)[0])[0]
MsgBox(0, "Python计算结果", "5 + 7 = " & $result)
DllCall($pythonDll, "none", "Py_Finalize")
DllClose($pythonDll)
又翻了下资料发现python还有个嵌入版专门来解决没有python环境下的使用,虽然从官网下载过几次python但都没注意过这个嵌入版
下面就从下载开始使用嵌入版python,然后使用http库requests来请求演示网站,show下requests还有4个依赖库也需要下载Global Const $URLS[6] = ["https://mirrors.huaweicloud.com/python/3.12.10/python-3.12.10-embeddable-amd64.zip", _
"https://mirrors.huaweicloud.com/artifactory/pypi-public/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", _
"https://mirrors.huaweicloud.com/artifactory/pypi-public/packages/6b/11/cc635220681e93a0183390e26485430ca2c7b5f9d33b15c74c2861cb8091/urllib3-2.4.0-py3-none-any.whl", _
"https://mirrors.huaweicloud.com/artifactory/pypi-public/packages/6d/15/61933d1999bc5ad8cad612d67f02fa5b16a423076ea0816e39c2e797af12/idna-3.9-py3-none-any.whl", _
"https://mirrors.huaweicloud.com/artifactory/pypi-public/packages/4a/7e/3db2bd1b1f9e95f7cddca6d6e75e2f2bd9f51b1246e546d88addca0106bd/certifi-2025.4.26-py3-none-any.whl", _
"https://mirrors.huaweicloud.com/artifactory/pypi-public/packages/20/94/c5790835a017658cbfabd07f3bfb549140c3ac458cfc196323996b10095a/charset_normalizer-3.4.2-py3-none-any.whl"]
Global $g_sPythonDir = @TempDir & "\AutoitPy\Python-3.12.10"
Global $g_sSitePkgs = $g_sPythonDir & "\Lib\site-packages"
Global $g_sPythonDll = $g_sPythonDir & "\python312.dll"
If Not SetupPythonEnvironment() Then Exit MsgBox(0x10, "失败", "Python环境配置失败")
If Not FileExists($g_sPythonDll) Then Exit MsgBox(0x10, "错误", "未找到Python DLL: " & $g_sPythonDll)
Local $hDll = DllOpen($g_sPythonDll)
If $hDll = -1 Then Exit MsgBox(0x10, "错误", "无法加载Python DLL")
DllCall($hDll, "none:cdecl", "Py_SetPythonHome", "wstr", $g_sPythonDir)
DllCall($hDll, "none:cdecl", "Py_InitializeEx", "int", 0)
Local $pRequestsModule = PyImportModule($hDll, "requests")
If @error Then Exit Cleanup($hDll, "无法导入requests模块")
ExecuteRequestExample($hDll, $pRequestsModule, "get", "https://httpbin.org/get", 0, "基本GET请求")
ExecuteRequestExample($hDll, $pRequestsModule, "get", "https://httpbin.org/get", CreateParams($hDll), "带参数的GET请求")
ExecuteRequestExample($hDll, $pRequestsModule, "post", "https://httpbin.org/post", CreatePostData($hDll), "POST请求")
ExecuteRequestExample($hDll, $pRequestsModule, "get", "https://httpbin.org/headers", CreateHeaders($hDll), "带请求头的请求")
Cleanup($hDll)
Func SetupPythonEnvironment()
DirCreate($g_sSitePkgs)
If Not FileExists($g_sPythonDll) Then
ConsoleWrite("+ 安装Python核心" & @CRLF)
If Not _DownloadExtract($URLS[0], $g_sPythonDir) Then Return False
EndIf
Local $libs[5] = ["requests", "urllib3", "idna", "certifi", "charset_normalizer"]
For $i = 0 To 4
If Not FileExists($g_sSitePkgs & "" & $libs[$i] & "\__init__.py") Then
ConsoleWrite("+ 安装依赖库: " & $libs[$i] & @CRLF)
If Not _DownloadExtract($URLS[$i+1], $g_sSitePkgs) Then Return False
EndIf
Next
Return FileExists($g_sPythonDir & "\python.exe")
EndFunc
Func _DownloadExtract($url, $target)
Local $file = StringRegExpReplace($url, ".*/", "")
Local $temp = @TempDir & "" & $file
ConsoleWrite("+ 下载: " & $file & @CRLF)
InetGet($url, $temp, 1)
If Not FileExists($temp) Or FileGetSize($temp) < 1024 Then
ConsoleWrite("! 下载失败" & @CRLF)
Return False
EndIf
ConsoleWrite("+ 解压到: " & $target & @CRLF)
Local $result = RunWait(@ComSpec & ' /c tar -xf "' & $temp & '" -C "' & $target & '"', "", @SW_HIDE)
FileDelete($temp)
Return $result = 0
EndFunc
Func PyImportModule($hDll, $moduleName)
Local $pModule = DllCall($hDll, "ptr:cdecl", "PyImport_ImportModule", "str", $moduleName)
If @error Or Not $pModule[0] Then Return SetError(1, 0, 0)
Return $pModule[0]
EndFunc
Func PyObjectGetAttr($hDll, $pObject, $attrName)
Local $pAttr = DllCall($hDll, "ptr:cdecl", "PyObject_GetAttrString", "ptr", $pObject, "str", $attrName)
If @error Or Not $pAttr[0] Then Return SetError(1, 0, 0)
Return $pAttr[0]
EndFunc
Func PyCallFunction($hDll, $pFunction, $pArgs = 0, $pKwargs = 0)
If $pKwargs == 0 Then
Local $pResult = DllCall($hDll, "ptr:cdecl", "PyObject_CallObject", "ptr", $pFunction, "ptr", $pArgs)
Else
Local $pResult = DllCall($hDll, "ptr:cdecl", "PyObject_Call", "ptr", $pFunction, "ptr", $pArgs, "ptr", $pKwargs)
EndIf
If @error Or Not $pResult[0] Then Return SetError(1, 0, 0)
Return $pResult[0]
EndFunc
Func PyCreateTuple($hDll, $size)
Local $pTuple = DllCall($hDll, "ptr:cdecl", "PyTuple_New", "int", $size)
If @error Or Not $pTuple[0] Then Return SetError(1, 0, 0)
Return $pTuple[0]
EndFunc
Func PySetTupleItem($hDll, $pTuple, $index, $pItem)
DllCall($hDll, "int:cdecl", "PyTuple_SetItem", "ptr", $pTuple, "int", $index, "ptr", $pItem)
If @error Then Return SetError(1, 0, 0)
Return 1
EndFunc
Func PyCreateString($hDll, $str)
Local $pStr = DllCall($hDll, "ptr:cdecl", "PyUnicode_FromString", "str", $str)
If @error Or Not $pStr[0] Then Return SetError(1, 0, 0)
Return $pStr[0]
EndFunc
Func PyCreateDict($hDll)
Local $pDict = DllCall($hDll, "ptr:cdecl", "PyDict_New")
If @error Or Not $pDict[0] Then Return SetError(1, 0, 0)
Return $pDict[0]
EndFunc
Func PyDictSetItem($hDll, $pDict, $key, $pValue)
Local $pKey = PyCreateString($hDll, $key)
If @error Then Return SetError(1, 0, 0)
DllCall($hDll, "int:cdecl", "PyDict_SetItem", "ptr", $pDict, "ptr", $pKey, "ptr", $pValue)
If @error Then Return SetError(1, 0, 0)
Return 1
EndFunc
Func PyGetLong($hDll, $pObject)
Local $value = DllCall($hDll, "int:cdecl", "PyLong_AsLong", "ptr", $pObject)
If @error Then Return SetError(1, 0, 0)
Return $value[0]
EndFunc
Func PyGetBytes($hDll, $pBytesObject)
Local $size = DllCall($hDll, "int:cdecl", "PyBytes_Size", "ptr", $pBytesObject)
If @error Then Return SetError(1, 0, Binary(""))
$size = $size[0]
Local $pData = DllCall($hDll, "ptr:cdecl", "PyBytes_AsString", "ptr", $pBytesObject)
If @error Or Not $pData[0] Then Return SetError(1, 0, Binary(""))
Local $struct = DllStructCreate("byte[" & $size & "]")
DllCall("kernel32.dll", "bool", "RtlMoveMemory", "struct*", $struct, "ptr", $pData[0], "ulong_ptr", $size)
Return DllStructGetData($struct, 1)
EndFunc
Func CreateParams($hDll)
Local $pParams = PyCreateDict($hDll)
PyDictSetItem($hDll, $pParams, "param1", PyCreateString($hDll, "value1"))
PyDictSetItem($hDll, $pParams, "param2", PyCreateString($hDll, "value2"))
Local $pKwargs = PyCreateDict($hDll)
PyDictSetItem($hDll, $pKwargs, "params", $pParams)
Return $pKwargs
EndFunc
Func CreatePostData($hDll)
Local $pData = PyCreateDict($hDll)
PyDictSetItem($hDll, $pData, "username", PyCreateString($hDll, "autoit_user"))
PyDictSetItem($hDll, $pData, "password", PyCreateString($hDll, "autoit_password"))
Local $pKwargs = PyCreateDict($hDll)
PyDictSetItem($hDll, $pKwargs, "data", $pData)
Return $pKwargs
EndFunc
Func CreateHeaders($hDll)
Local $pHeaders = PyCreateDict($hDll)
PyDictSetItem($hDll, $pHeaders, "User-Agent", PyCreateString($hDll, "AutoItScript/1.0"))
PyDictSetItem($hDll, $pHeaders, "Authorization", PyCreateString($hDll, "Bearer token123"))
PyDictSetItem($hDll, $pHeaders, "X-Custom-Header", PyCreateString($hDll, "CustomValue"))
Local $pKwargs = PyCreateDict($hDll)
PyDictSetItem($hDll, $pKwargs, "headers", $pHeaders)
Return $pKwargs
EndFunc
Func ExecuteRequestExample($hDll, $pRequestsModule, $funcName, $url, $pKwargs, $title)
Local $pFunc = PyObjectGetAttr($hDll, $pRequestsModule, $funcName)
If @error Then Return SetError(1, 0, 0)
Local $pUrl = PyCreateString($hDll, $url)
If @error Then Return SetError(1, 0, 0)
Local $pArgs = PyCreateTuple($hDll, 1)
If @error Then Return SetError(1, 0, 0)
PySetTupleItem($hDll, $pArgs, 0, $pUrl)
Local $pResponse = PyCallFunction($hDll, $pFunc, $pArgs, $pKwargs)
If @error Then Return SetError(1, 0, 0)
ProcessResponse($hDll, $pResponse, $title)
Return 1
EndFunc
Func ProcessResponse($hDll, $pResponse, $title)
Local $pStatusCode = PyObjectGetAttr($hDll, $pResponse, "status_code")
Local $statusCode = PyGetLong($hDll, $pStatusCode)
Local $pContent = PyObjectGetAttr($hDll, $pResponse, "content")
Local $rawData = PyGetBytes($hDll, $pContent)
Local $text = BinaryToString($rawData, 4)
Local $displayText = StringLeft($text, 2500)
If StringLen($text) > 2500 Then $displayText &= "..."
MsgBox(0, $title, "状态码: " & $statusCode & @CRLF & @CRLF & "内容: " & $displayText)
EndFunc
Func Cleanup($hDll, $errorMsg = "")
If $hDll <> -1 Then
DllCall($hDll, "none:cdecl", "Py_Finalize")
DllClose($hDll)
EndIf
If $errorMsg <> "" Then
MsgBox(0x10, "错误", $errorMsg)
EndIf
EndFunc
这个嵌入版挺好的,只需要10M的环境就能跑pytnon,无论是跟程序打包还是在线下载都挺方便的,肯定还有跟多好玩法还没探索
|