1、前言
最近項(xiàng)目中需要錄制鍵鼠命令,然后再通過注入的方式回放錄制過程。一般來說,普通的一些點(diǎn)擊命令完全可以通過python的一些包來完成鍵鼠模擬操作,比如通過pyautogui包。但是,鼠標(biāo)移動過程中,如果采用頻率很高的話,比如1s之類采樣50個點(diǎn)像素坐標(biāo),那么就會發(fā)現(xiàn),如果是通過python進(jìn)行回放的話,整個回放過程,相比于原來的錄制過程,就如同慢放一樣。
整個過程抽象如下:
在錄制過程每隔時間T進(jìn)行一次采樣(記錄下該點(diǎn)的坐標(biāo)),由于采樣本身所消耗的時間極少(小于0.1ms),可以忽略,因此,錄制過程假如采樣n個點(diǎn),需要的時間為:nT
回放過程,需要依次移動到采樣的的每個點(diǎn)p1、p2…,由于在回放過程移動到每個點(diǎn)是通過python函數(shù)moveTo來實(shí)現(xiàn)的,而函數(shù)moveTo執(zhí)行一次的時間為t(大概在100ms左右,不能忽略),所以回放過程消耗的時間為:nT + nt 。
回放過程與錄制過程的時間比比:(nT + nt)/nT = 1 + t/T,因此回放過程相對于錄制過程,相當(dāng)于是1 + t/T倍慢放。并且采樣頻率越高,即T越小,慢放的比例越大!
為了讓回放過程更加接近錄制過程,即減小慢放的比例,就需要縮放moveTo的執(zhí)行時間。由于通過python實(shí)現(xiàn)moveTo的時間消耗較長,可以通過c/c++來實(shí)現(xiàn)moveTo,就可以大幅縮短moveTo需要的時間。
2、生成dll
為了在python中調(diào)用dll,需要先生成moveTo的dll文件。對應(yīng)的源碼如下:
// mouseMove.h
#ifdef MYDLL_EXPORTS
#define MATH_API __declspec(dllexport)
#else
#define MATH_API __declspec(dllimport)
#endif
#include <windows.h>
extern "C" {
MATH_API void mouseClick(int x, int y);
MATH_API void LeftDown(int x, int y);
MATH_API void LeftUp(int x, int y);
MATH_API void mouseMove(int x, int y); // 對應(yīng)moveTo函數(shù)
}
// mouseMove.cpp
void mouseClick(int x, int y) {
INPUT input = { 0 };
input.type = INPUT_MOUSE;
input.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE | MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP;
// 計(jì)算屏幕上的坐標(biāo)位置
input.mi.dx = x * 65535 / GetSystemMetrics(SM_CXSCREEN);
input.mi.dy = y * 65535 / GetSystemMetrics(SM_CYSCREEN);
SendInput(1, &input, sizeof(INPUT));
}
void LeftDown(int x, int y) {
INPUT input = { 0 };
input.type = INPUT_MOUSE;
input.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE | MOUSEEVENTF_LEFTDOWN;
// 計(jì)算屏幕上的坐標(biāo)位置
input.mi.dx = x * 65535 / GetSystemMetrics(SM_CXSCREEN);
input.mi.dy = y * 65535 / GetSystemMetrics(SM_CYSCREEN);
SendInput(1, &input, sizeof(INPUT));
}
void LeftUp(int x, int y) {
INPUT input = { 0 };
input.type = INPUT_MOUSE;
input.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE | MOUSEEVENTF_LEFTUP;
// 計(jì)算屏幕上的坐標(biāo)位置
input.mi.dx = x * 65535 / GetSystemMetrics(SM_CXSCREEN);
input.mi.dy = y * 65535 / GetSystemMetrics(SM_CYSCREEN);
SendInput(1, &input, sizeof(INPUT));
}
void mouseMove(int x, int y) {
INPUT input = { 0 };
input.type = INPUT_MOUSE;
input.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
// 計(jì)算屏幕上的坐標(biāo)位置
input.mi.dx = x * 65535 / GetSystemMetrics(SM_CXSCREEN);
input.mi.dy = y * 65535 / GetSystemMetrics(SM_CYSCREEN);
SendInput(1, &input, sizeof(INPUT));
}
注意:在dll文件中不僅實(shí)現(xiàn)mouseMove(對應(yīng)moveTo),還順帶實(shí)現(xiàn)了mouseClick等操作。
3、通過pyton調(diào)用dll
在python中調(diào)用dll文件,只需要先導(dǎo)入ctypes包,然后通過ctypes包加載dll文件,然后調(diào)用dll中的函數(shù)即可。
import ctypes
import pyautogui
# 加載dll文件
lib = ctypes.cdll.LoadLibrary("E:\\program\\cplusplus\\myDll\\x64\\Release\\myDll.dll")
# 調(diào)用dll中的函數(shù)
lib.mouseMove(100,200)
4、python庫與dll庫運(yùn)行速度對比
都知道比速度python肯定是比不上c/c++,但是運(yùn)行速度到底差了多少呢?如果單純是就論本問題提到的移動鼠標(biāo)這個功能的話,說出來可能嚇人?。?!
無圖說個。。。。,
import time
import ctypes
import pyautogui
lib = ctypes.cdll.LoadLibrary("E:\\program\\cplusplus\\myDll\\x64\\Release\\myDll.dll")
t = time.time()
# dll執(zhí)行1000次mouseMove
for i in range(0,1000):
lib.mouseMove(i,2)
t1 = time.time()
print("mouseMove 1000 times by dll: ",t1 - t)
# 通過pyautogui執(zhí)行100次moveTo
t = time.time()
for i in range(0,100):
pyautogui.moveTo(i,300)
t1 = time.time()
print("moveTo 100 times by pyautogui:",t1 - t)
從圖中可以看到,通過dll執(zhí)行1000次mouseMove消耗的時間為0.11s,平均一次0.1ms左右
通過pyautogui執(zhí)行100 mouseTo消耗時間為10s,平均一次消耗時間100ms
居然相差了1000倍???
難怪錄制過程轉(zhuǎn)換為python回放都變慢放了~
------------------------- 更新 ------------------------------------
之前一直很難相信python和c++ dll的速度會相差這么,事實(shí)上卻是也沒有這么大的差距,應(yīng)該本質(zhì)上pyautogui也是通過調(diào)用windows API相關(guān)dll。那么問題出在哪里呢?
研究pyautogui源碼發(fā)現(xiàn),pyautogui的moveTo接口有裝飾器,絕大部分時間都消耗在了裝飾器上。
將裝飾器去掉的話,就和調(diào)用dll的速度相當(dāng)了。文章來源:http://www.zghlxwxcb.cn/news/detail-660878.html
參考文章:
【1】python 調(diào)用 c++ dll庫
【2】C++模擬鼠標(biāo)移動及單擊實(shí)現(xiàn)代碼
【3】[python] python調(diào)用C++ 程序文章來源地址http://www.zghlxwxcb.cn/news/detail-660878.html
到了這里,關(guān)于在python中通過調(diào)用dll來提高運(yùn)行速度的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!