实用案例
查找句柄
win32gui.findwindow(class_name:str, window_text:str) -> int
根据pid获取句柄
import win32gui
import win32process
def get_hwnds_for_pid(pid):
# 通过PID查询句柄ID
def callback(hwnd, hwnds):
if win32gui.IsWindowVisible(hwnd) and win32gui.IsWindowEnabled(hwnd):
_, found_pid = win32process.GetWindowThreadProcessId(hwnd)
if found_pid == pid:
hwnds.append(hwnd)
return True
hwnds = []
win32gui.EnumWindows(callback, hwnds)
hwndy = 0
if hwnds:
hwndy = hwnds[0]
return hwndy
if __name__ in "__main__":
get_hwnds_for_pid(传入PID值) # 传入PID值后返回句柄ID
查找子窗口或父窗口
win32gui.findwindow(
parent_hwnd:int|None, # 以父窗口向下查找子窗口,此时子窗口可以设置为None
child_hwnd:int|None, # 以子窗口下上查找父窗口,此时父窗口可以设置为None
class_name:str,
window_text:str
) -> int
向窗体发送指令
win32gui.SendMessage(
hWnd:int,
Msg:str, # 要发送的消息,这些消息都是windows预先定义好的
wParam:wParam, # 按照消息的要求进行设置
lParam:lParam # 按照消息的要求进行设置
)
预先定义好的Msg
两者区别
PostMessageW
只是通知窗口有个消息要处理,发送消息后不会等待消息处理结果直接返回SendMessage
是通知窗口有个消息要立即处理,并等待处理结果再返回,二者在发送消息时没有区别
wParam
和lParam
都需要按照消息的要求进行设置。每个消息的要求都不一样,具体如何设置,需要查看对应消息的文档。
枚举窗口
Hwnd = NewType('hWnd', int)
def enum_windows() -> Hwnd_List:
hwnd_list:Hwnd_List = []
win32gui.EnumWindows(lambda hWnd, param: param.append(hWnd), hwnd_list)
return hwnd_list
获取窗体尺寸
def get_info_by_hwnd(hwnd:Hwnd, context_hwnd:Optional[Hwnd]=None) -> HwndInfo:
"""
@Description 获取窗体详细信息
- param hwnd :{Hwnd} 目标窗体
- param context=None :{Optional[Hwnd]} 指定内容区窗口句柄,一般是子窗口句柄
@returns `{dict}` {description}
```python
{
"hwnd":窗口句柄,
"window_width":完整窗体宽度,
"window_height":完成窗体高度,
'context_width':真实内容区宽度,
'context_height':真实内容去高度,
'border':左右下边宽,一般只有上边宽不一样,
'border_top':上边宽高度,
'window_left':窗体位置,
'window_top':int,
'window_right':int,
'window_bottom':int
}
"""
window_left, window_top, window_right, window_bottom = win32gui.GetWindowRect(hwnd)
window_width = window_right - window_left
window_height = window_bottom - window_top
if not context_hwnd:
context_hwnd = hwnd
context_left, context_top, context_right, context_bottom = win32gui.GetClientRect(context_hwnd)
context_width = context_right - context_left
context_height = context_bottom - context_top
border = (window_width - context_width) // 2
border_top = (window_height - context_height) - border
result = {
"hwnd":hwnd,
"window_width":window_width,
"window_height":window_height,
'context_width':context_width,
'context_height':context_height,
'border':border,
'border_top':border_top,
'window_left':window_left,
'window_top':window_top,
'window_right':window_right,
'window_bottom':window_bottom,
}
return result
前置窗口
win32gui.SetForegroundWindow(hwnd) # 设置前置窗口
窗口最小化
def is_mini(hwnd: int) -> bool:
from win32gui import IsIconic
try:
return IsIconic(hwnd) != 0
except Exception as err:
return False
return False
关闭窗口
win32gui.PostMessage(
hwnd:int,
win32con.WM_CLOSE, # 功能代码
0,
0)
关闭程序(pid)
import win32gui
import win32process
import psutil
def handle_window(hwnd, extra):
if win32gui.IsWindowVisible(hwnd):
if '程序标题' in win32gui.GetWindowText(hwnd): # 判断是否符合
_,PID = win32process.GetWindowThreadProcessId(hwnd) # 通过句柄ID查询进程PID(第0个元素不管,第1个元素是PID)
p = psutil.Process(PID) # 实例化PID
p.terminate() # 关闭PID进程
if __name__ in "__main__":
win32gui.EnumWindows(handle_window, None) # 通过句柄ID查询PID并关闭PID
显示窗口
win32gui.ShowWindow(
hwnd:int,
win32con.SW_SHOWNORMAL # 系统内置的参数
)
- SW_HIDE:隐藏窗口并激活其他窗口。nCmdShow=0。
- SW_SHOWNORMAL:激活并显示一个窗口。如果窗口被最小化或最大化,系统将其恢复到原来的尺寸和大小。应用程序在第一次显示窗口的时候应该指定此标志。nCmdShow=1。
- SW_SHOWMINIMIZED:激活窗口并将其最小化。nCmdShow=2。
- SW_SHOWMAXIMIZED:激活窗口并将其最大化。nCmdShow=3。
- SW_SHOWNOACTIVATE:以窗口最近一次的大小和状态显示窗口。激活窗口仍然维持激活状态。nCmdShow=4。
- SW_SHOW:在窗口原来的位置以原来的尺寸激活和显示窗口。nCmdShow=5。
- SW_MINIMIZE:最小化指定的窗口并且激活在Z序中的下一个顶层窗口。nCmdShow=6。
- SW_SHOWMINNOACTIVE:窗口最小化,激活窗口仍然维持激活状态。nCmdShow=7。
- SW_SHOWNA:以窗口原来的状态显示窗口。激活窗口仍然维持激活状态。nCmdShow=8。
- SW_RESTORE:激活并显示窗口。如果窗口最小化或最大化,则系统将窗口恢复到原来的尺寸和位置。在恢复最小化窗口时,应用程序应该指定这个标志。nCmdShow=9。
- 用例
def _hide_w32_window(self):
try:
w32win = win32gui.FindWindow(None, self.title)
win32gui.ShowWindow(w32win, SW_HIDE)
win32gui.SetWindowLong(
w32win,
GWL_EXSTYLE,
win32gui.GetWindowLong(
w32win, GWL_EXSTYLE) | WS_EX_TOOLWINDOW
)
win32gui.ShowWindow(w32win, SW_SHOW)
self._return_focus_w32()
except Exception:
tb = traceback.format_exc()
Logger.error(
'Notification: An error occured in {}\n'
'{}'.format(self.title, tb)
)
def Show(self):
win32gui.ShowWindow(self.hwnd, win32con.SW_SHOW)
根据进程标题名称隐藏运行进程
import win32gui
from win32.lib import win32con
def handle_window(hwnd, extra):
if win32gui.IsWindowVisible(hwnd):
if '需要隐藏的程序标题名称' in win32gui.GetWindowText(hwnd):
win32gui.ShowWindow(hwnd, win32con.SW_HIDE)
if __name__ == '__main__':
win32gui.EnumWindows(handle_window, None)
# win32gui.EnumWindows(枚举函数名称, None) 语句是进行句柄ID枚举
# win32gui.GetWindowText(句柄ID) 语句是通过句柄ID来获取进程名称
# win32gui.IsWindowVisible(句柄ID) 语句是查询此句柄ID是否存在,存在返回1 否则返回0
# win32gui.ShowWindow(句柄ID, win32con.SW_HIDE) 语句是通过指定句柄ID来隐藏进程
操作Word
import win32com #引入使用
from win32com import client as com #引入使用
# 必须使用内部的client的dispatch方法
from win32com import client as wordApi
# 引入ms的officeAPI进行word的操作
word = wordApi.dispatch('Word.Application')
# 打开word文件的路径
doc = word.Document.Open(path)
# 保存/转换文件, 16是必须添加的参数
doc.SaveAs(path,16)
鼠标操作
案例1(失败)
def Mouse_RB(self,str_app,lb_dx,lb_dy,Flag='1'):
print "*********Mouse_RB function**********"
time.sleep(1)
tmp=(string.atoi(lb_dx),string.atoi(lb_dy))
hwnd = win32gui.FindWindow(None, str_app)
print 'Mouse_RB str_app,hwnd ',str_app,hwnd
if hwnd < 1:
hwnd = self.find_main_window(str_app)
#win32gui.ShowWindow(hwnd, 0)
win32api.SetCursorPos(tmp)
print 'Mouse_RB tmp =',tmp
if Flag == '1':
time.sleep(1)
win32api.mouse_event(win32con.MOUSEEVENTF_RIGHTDOWN,tmp[0], tmp[1])
time.sleep(0.05)
win32api.mouse_event(win32con.MOUSEEVENTF_RIGHTUP,tmp[0], tmp[1])
time.sleep(0.05)
return True
def Mouse_LB(self,str_app,lb_dx,lb_dy,Flag='1'):
print "*********Mouse_LB function**********"
time.sleep(1)
tmp=(string.atoi(lb_dx),string.atoi(lb_dy))
hwnd = win32gui.FindWindow(None, str_app)
if hwnd < 1:
hwnd = self.find_main_window(str_app)
#win32gui.ShowWindow(hwnd, 0)
win32api.SetCursorPos(tmp)
print 'Mouse_LB tmp =',tmp
if Flag == '1':
time.sleep(1)
win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN,tmp[0], tmp[1])
time.sleep(0.05)
win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP,tmp[0], tmp[1])
time.sleep(0.05)
return True
后台截图
案例1
(部分逻辑参考自onmyoji_bot)
1、获取窗体信息
import win32gui, win32con, win32api, win32ui
import typing
# (x,y) 常用坐标类型
coord = typing.NewType('tuple(int,int)', tuple)
# 获取窗体信息
def get_context_size(hwnd:int=0) -> coord:
"""
@Description {description}
- param hwnd=0 :{int} {description}
returns `{coord}` {description}
```python
(
"border":"窗体的边宽",
"border_top":"窗体菜单栏的高度",
"c_width":"客户端的内容宽度",
"c_height":"客户端的内容高度"
)
"""
# 窗体的尺寸
w_left, w_top, w_right, w_bot = win32gui.GetWindowRect(hwnd)
w_width = w_right - w_left
w_height = w_bot - w_top
# 内容区的尺寸
c_left, c_top, c_right, c_bot = win32gui.GetClientRect(hwnd)
c_width = c_right - c_left
c_height = c_bot - c_top
# 计算边框的宽度
border = (w_width - c_width) // 2
# 计算菜单栏的高度
border_top = (w_height - c_height) - border
return (border, border_top, c_width, c_height)
def window_capture(hwnd, filename=None, mode="file", region=None):
"""
@Description 截取指定窗口句柄的图片
- param hwnd :{param} {description}
- param filename=None :{param} {description}
- param mode=win32 :{string} 采用哪种方式:file|PIL|cv2
returns `{}` {description}
"""
# 获取该窗体的内容区范围
X = Y = 0
border, border_top, w,h = get_context_size(hwnd)
# 范围截图
if region:
startX, startY, endX, endY = region
x = startX + border
y = startY + border_top
w = endX - startX
h = endY - startY
else:
# 完整截图
x = border
y = border_top
# 取设备上下文DC(Divice Context)
hwndDC = win32gui.GetWindowDC(hwnd)
# 根据窗口的DC获取mfcDC
mfcDC = win32ui.CreateDCFromHandle(hwndDC)
# 创建可兼容的DC
saveDC = mfcDC.CreateCompatibleDC()
# 创建bigmap用来存放图片信息对内存对象
BitMap = win32ui.CreateBitmap()
BitMap.CreateCompatibleBitmap(mfcDC, w, h)
# 截取图片到内存
saveDC.SelectObject(BitMap)
saveDC.BitBlt(
(X, Y), # 开始截取的位置
(w, h), # 内容的尺寸 GetClientRect 的宽和高
mfcDC,
(x, y), # 偏移,一般将窗口的border和上方菜单栏高度输入即可
win32con.SRCCOPY)
res = BitMap
if mode == "file":
# 保存为本地文件
res = bitMap_to_file(BitMap, DC=saveDC, filename=filename)
elif mode == "PIL":
res = bitMap_to_PIL_img(BitMap)
if res: res.show()
elif mode == "cv2":
res = bitMap_to_cv2_img(BitMap, w, h)
# 释放资源
win32gui.DeleteObject(BitMap.GetHandle())
saveDC.DeleteDC()
mfcDC.DeleteDC()
win32gui.ReleaseDC(hwnd, hwndDC)
return res
3、处理截取到的图片
3.1 保存图片到文件(win32api)
def bitMap_to_file(BitMap, DC, filename) -> bool:
try:
BitMap.SaveBitmapFile(DC, filename)
return True
except:
return False
3.2 保存为PIL文件对象
from PIL import Image
def bitMap_to_PIL_img(BitMap) -> Image:
try:
# 提取当前截取的图片信息
bitMapInfo = BitMap.GetInfo()
# 转换为buffer供pil使用
bitMapStr = BitMap.GetBitmapBits(True)
# 通过buffer生成pil的图片对象实例
img_PIL = Image.frombuffer(
'RGB',
(bitMapInfo['bmWidth'],
bitMapInfo['bmHeight']),
bitMapStr,'raw','BGRX',
0,
1)
return img_PIL
except:
return None
3.3保存为 cv2 图片对象
import cv2
import numpy as np
def bitMap_to_cv2_img(BitMap, w, h, gray=False):
signedIntsArray = BitMap.GetBitmapBits(True)
img = np.frombuffer(signedIntsArray, dtype='uint8')
img.shape = (h, w, 4)
# 灰度处理
if gray:
return cv2.cvtColor(img, cv2.COLOR_BGRA2GRAY)
else:
return cv2.cvtColor(img, cv2.COLOR_BGRA2BGR)
案例2
#对后台窗口截图
import win32gui, win32ui, win32con
from ctypes import windll
from PIL import Image
import cv2
import numpy
#获取后台窗口的句柄,注意后台窗口不能最小化
#窗口的类名可以用Visual Studio的SPY++工具获取
hWnd = win32gui.FindWindow("NotePad",None)
#获取句柄窗口的大小信息
left, top, right, bot = win32gui.GetWindowRect(hWnd)
width = right - left
height = bot - top
#返回句柄窗口的设备环境,覆盖整个窗口,包括非客户区,标题栏,菜单,边框
hWndDC = win32gui.GetWindowDC(hWnd)
#创建设备描述表
mfcDC = win32ui.CreateDCFromHandle(hWndDC)
#创建内存设备描述表
saveDC = mfcDC.CreateCompatibleDC()
#创建位图对象准备保存图片
saveBitMap = win32ui.CreateBitmap()
#为bitmap开辟存储空间
saveBitMap.CreateCompatibleBitmap(mfcDC,width,height)
#将截图保存到saveBitMap中
saveDC.SelectObject(saveBitMap)
#保存bitmap到内存设备描述表
saveDC.BitBlt((0,0), (width,height), mfcDC, (0, 0), win32con.SRCCOPY)
#如果要截图到打印设备:
###最后一个int参数:0-保存整个窗口,1-只保存客户区。如果PrintWindow成功函数返回值为1
#result = windll.user32.PrintWindow(hWnd,saveDC.GetSafeHdc(),0)
#print(result) #PrintWindow成功则输出1
#保存图像
##方法一:windows api保存
###保存bitmap到文件
saveBitMap.SaveBitmapFile(saveDC,"img_Winapi.bmp")
##方法二(第一部分):PIL保存
###获取位图信息
bmpinfo = saveBitMap.GetInfo()
bmpstr = saveBitMap.GetBitmapBits(True)
###生成图像
im_PIL = Image.frombuffer('RGB',(bmpinfo['bmWidth'],bmpinfo['bmHeight']),bmpstr,'raw','BGRX',0,1)
##方法二(后续转第二部分)
##方法三(第一部分):opencv+numpy保存
###获取位图信息
signedIntsArray = saveBitMap.GetBitmapBits(True)
##方法三(后续转第二部分)
#内存释放
win32gui.DeleteObject(saveBitMap.GetHandle())
saveDC.DeleteDC()
mfcDC.DeleteDC()
win32gui.ReleaseDC(hWnd,hWndDC)
##方法二(第二部分):PIL保存
###PrintWindow成功,保存到文件,显示到屏幕
im_PIL.save("im_PIL.png") #保存
im_PIL.show() #显示
##方法三(第二部分):opencv+numpy保存
###PrintWindow成功,保存到文件,显示到屏幕
im_opencv = numpy.frombuffer(signedIntsArray, dtype = 'uint8')
im_opencv.shape = (height, width, 4)
cv2.cvtColor(im_opencv, cv2.COLOR_BGRA2RGB)
cv2.imwrite("im_opencv.jpg",im_opencv,[int(cv2.IMWRITE_JPEG_QUALITY), 100]) #保存
cv2.namedWindow('im_opencv') #命名窗口
cv2.imshow("im_opencv",im_opencv) #显示
cv2.waitKey(0)
cv2.destroyAllWindows()
https://blog.csdn.net/zhuisui_woxin/article/details/84345036
案例3
def window_capture(hwnd):
hwndDC= win32gui.GetWindowDC(hwnd)
mfcDC = win32ui.CreateDCFromHandle(hwndDC)
saveDC = mfcDC.CreateCompatibleDC()
saveBitMap = win32ui.CreateBitmap()
rctA = win32gui.GetWindowRect(hwnd)
w = rctA[2] - rctA[0]
h = rctA[3] - rctA[1]
saveBitMap.CreateCompatibleBitmap(mfcDC, w, h)
saveDC.SelectObject(saveBitMap)
saveDC.BitBlt((0, 0), (w, h), mfcDC, (0, 0), win32con.SRCCOPY)
signedIntsArray = saveBitMap.GetBitmapBits(True)
img = np.frombuffer(signedIntsArray, dtype="uint8")
img.shape = (h, w, 4)
win32gui.DeleteObject(saveBitMap.GetHandle())
mfcDC.DeleteDC()
saveDC.DeleteDC()
return cv2.cvtColor(img, cv2.COLOR_RGBA2RGB)
桌面截图
# 截图整个桌面
import win32gui
import win32ui
import win32con
import win32api
# 获取桌面
hdesktop = win32gui.GetDesktopWindow()
# 分辨率适应
width = win32api.GetSystemMetrics(win32con.SM_CXVIRTUALSCREEN)
height = win32api.GetSystemMetrics(win32con.SM_CYVIRTUALSCREEN)
left = win32api.GetSystemMetrics(win32con.SM_XVIRTUALSCREEN)
top = win32api.GetSystemMetrics(win32con.SM_YVIRTUALSCREEN)
# 创建设备描述表
desktop_dc = win32gui.GetWindowDC(hdesktop)
img_dc = win32ui.CreateDCFromHandle(desktop_dc)
# 创建一个内存设备描述表
mem_dc = img_dc.CreateCompatibleDC()
# 创建位图对象
screenshot = win32ui.CreateBitmap()
screenshot.CreateCompatibleBitmap(img_dc, width, height)
mem_dc.SelectObject(screenshot)
# 截图至内存设备描述表
mem_dc.BitBlt((0, 0), (width, height), img_dc, (0, 0), win32con.SRCCOPY)
# 将截图保存到文件中
screenshot.SaveBitmapFile(mem_dc, 'screenshot.bmp')
# 内存释放
mem_dc.DeleteDC()
win32gui.DeleteObject(screenshot.GetHandle())
列出当前显示器
import win32api
MoniterDev = win32api.EnumDisplayMonitors(None, None)
print("MoniterDev: ", len(MoniterDev))
显示屏幕尺寸和放大比例
获取屏幕的真实分辨率,放大比例,显示分辨率等信息
from win32 import win32api, win32gui, win32print
from win32.lib import win32con
from pydantic import BaseModel
class ScreenType(BaseModel):
show_width: int
show_height: int
real_width: int
real_height: int
scale_rate: int
def getSrceen() -> ScreenType | None:
"""
@Description 获取屏幕的真实尺寸和放大比例
@returns `{ ScreenType | None}` {description}
@example
```py
screen_size = getSrceen()
```
"""
try:
"""获取缩放后的分辨率"""
sX = win32api.GetSystemMetrics(0) # 获得屏幕分辨率X轴
sY = win32api.GetSystemMetrics(1) # 获得屏幕分辨率Y轴
"""获取真实的分辨率"""
hDC = win32gui.GetDC(0)
w = win32print.GetDeviceCaps(hDC, win32con.DESKTOPHORZRES) # 横向分辨率
h = win32print.GetDeviceCaps(hDC, win32con.DESKTOPVERTRES) # 纵向分辨率
# 缩放比率
scale_rate = round(w / sX, 2)
return ScreenType(
show_width=sX,
show_height=sY,
real_width=w,
real_height=h,
scale_rate=scale_rate,
)
except Exception as e:
print("getSrceen fail", e)
return None
粘贴板操作
复制PIL图片到粘贴板
http://t.zoukankan.com/enumx-p-12359863.html
引入依赖
import win32clipboard
from PIL import Image
from io import BytesIO
def copy_img_to_clipboard(type_data, data):
# 打开粘贴板
win32clipboard.OpenClipboard()
# 清空粘贴板
win32clipboard.EmptyClipboard()
# 将数据放到粘贴板
win32clipboard.SetClipboardData(type_data, msg)
# 关闭粘贴板
win32clipboard.CloseClipboard()
PIL
def pil_img_to_byte(img_path:str):
image = Image.open(file_img)
# 创建一个字节对象
data_byte = BytesIO()
# 保存未bmp格式,将数据保存到为字节对象
image.save(data_byte, 'BMP')
# BMP图片有14字节的header,需要额外去除
data = data_byte.getvalue()[14:]
# 关闭字节对象
data_byte.close()
# DIB: 设备无关位图(device-independent bitmap),名如其意
# BMP的图片有时也会以.DIB和.RLE作扩展名
# 设置好剪贴板的数据格式,再传入对应格式的数据,才能正确向剪贴板写入数据
copy_img_to_clipboard(win32clipboard.CF_DIB, data)
CV2
def cv2_img_to_byte(img_path: str) -> bool:
try:
img = cv2.imread(img_path)
img_to_bytes_res = cv2.imencode(".bmp", img)
if img_to_bytes_res[0]:
img_byte = img_to_bytes_res[1].tobytes()
bmp_data = img_byte[14:]
copy_img_to_clipboard(bmp_data)
return True
return False
except Exception as e:
print("cv2_img_to_byte fail ", e)
return False
word转pdf
import os, pathlib
from win32com import client
from pydantic import BaseModel, Field
class WORD_CODE: # 记录所有word代码
pdf: int = 17
class CpsWordConverterConfig(BaseModel):
overwrite: bool = Field(False, description="如果文件已存在,是否覆盖输出")
show_details: bool = Field(False, description="是否打印错误")
class CpsWordConverter:
def __init__(self, config: CpsWordConverterConfig = None):
"""
@Description {description}
- param config=None :{CpsWordConverterConfig} 实例配置
@example
```python
target = r"Z:/xxxdir/xxxx.docx"
target_dir = r"Z:/work/2023/改图/2023职称/周末bk"
# 初始化
Config = CpsWordConverterConfig(overwrite=False, show_details=True)
Convert = CpsWordConverter(Config)
# 单独转换文件
Convert.convert(target)
# 遍历目录
Convert.convert(target_dir)
```
"""
# 检查当前系统环境是否安装了word
if not self.__check():
raise "实例化失败"
if config:
self.config = config
else:
self.config = CpsWordConverterConfig()
self.word = None # 存储word实例
def print(self, *argvs, **keys):
if self.config.show_details:
print(*argvs, **keys)
def convert(self, target: str) -> list[str]:
"""
@Description 转换主函数
- param target :{str} target可以是目录,也可以是文件,如果是目录,将直接进行递归
"""
try:
if not os.path.exists(target):
self.print("目标不存在: ", target)
return []
# 判断是目录还是文件
p = pathlib.Path(target)
result = []
if p.is_file():
result.append(self.__word2pdf(p))
elif p.is_dir():
result = self.__dir_handler(p)
return result
except Exception as e:
self.print("convert err: ", e)
return []
def __del__(self):
if self.word:
self.word.Quit()
self.word = None
def __check(self) -> bool:
return True
def __open_word(self):
self.word = client.Dispatch("Word.Application")
self.word.Visible = False
return self.word
def __dir_handler(self, dir_path: str | pathlib.Path) -> str:
docx = list(pathlib.Path(dir_path).glob("**/*.docx"))
doc = list(pathlib.Path(dir_path).glob("**/*.doc"))
word_list = docx + doc
result = []
if len(word_list) == 0:
return ""
else:
self.print("当前需要处理的文件有: ", len(word_list))
for each in word_list:
result.append(self.__word2pdf(each))
return result
@staticmethod
def word_accept_all_revisions(word):
"""
@Description 对当前的word文件进行一次接收所有修订操作,并原地保存
- param word :{param} word实例
"""
try:
word.ActiveDocument.TrackRevisions = False
# word.WordBasic.AcceptAllChangesInDoc() # 会报错,但也可以接收所有修订
word.ActiveDocument.Revisions.AcceptAll()
if word.ActiveDocument.Comments.Count >= 1:
word.ActiveDocument.DeleteAllComments()
return word
except Exception as err:
print("word_accept_all_revisions: ", err)
return word
def __word2pdf(self, word_file: pathlib.Path) -> str:
"""
- param word_file :{str} `.doc|.docx`结尾的文件
"""
try:
# 获取同名的pdf输出路径
word_file_path = str(word_file.resolve())
output_pdf_path = str(word_file.resolve()).replace(word_file.suffix, ".pdf")
# 已存在pdf,是否进行覆盖
if os.path.exists(output_pdf_path):
# 不覆盖的话,直接跳过
if not self.config.overwrite:
self.print("文件已存在: ", output_pdf_path)
return ""
# 打开word应用程序
if not self.word:
self.word = self.__open_word()
# 打开word文件
doc = self.word.Documents.Open(word_file_path)
# 所有修订
self.word_accept_all_revisions(self.word)
# 另存为后缀为".pdf"的文件,其中参数17表示为pdf
doc.Activate()
doc.SaveAs(output_pdf_path, WORD_CODE.pdf)
# 关闭原来word文件
doc.Close()
self.print("完成转换: ", word_file)
return output_pdf_path
except Exception as e:
self.print("word2pdf err: ", e)
return ""
def example():
target = r"Z:\work\2024\项目\东莞海腾码头补办水利手续\0808珠江水文水资源勘测中心-东莞海腾码头补办水利手续工作大纲及报价书(1).docx"
target_dir = r"Z:\work\2023\改图\2023职称\周末bk"
Config = CpsWordConverterConfig(overwrite=False, show_details=True)
Convert = CpsWordConverter(Config)
Convert.convert(target)
def main(target: str):
Config = CpsWordConverterConfig(overwrite=False, show_details=True)
Convert = CpsWordConverter(Config)
Convert.convert(target)
if __name__ == "__main__":
# example()
import argparse
# 初始化实例
parser = argparse.ArgumentParser()
# 解释参数
parser.add_argument(
"target", # 不要处理的word文件
help="需要处理的.doc/.docx文件,绝对路径",
type=str,
)
args = parser.parse_args()
main(args.target)