博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
python使用win32*模块模拟人工操作——城通网盘下载器(一)
阅读量:4056 次
发布时间:2019-05-25

本文共 5752 字,大约阅读时间需要 19 分钟。

上篇讲了,如何使用“
城通网盘批量下载器 v2.0
”来下载城通网盘的文件。其主要操作集中在主界面中,所以我们首先使用python来模拟在主界面的操作。
打开城通网盘批量下载器,进入主界面,如图所示:
然后打开spy++,查看该程序的窗口信息。
可以看到,这个程序主窗口的句柄为 00090816(十六进制数),值得注意的是,这个句柄是每次打开程序时,windows随机生成的。故不能直接指定句柄号来操作窗口。在python中可以使用win32*模块来调用windows函数,之前你得安装pywin32。使用win32gui.FindWindow和win32gui.FindWindowEx函数来拿到句柄。具体用法为:
  • FindWindow(lpClassName=None, lpWindowName=None):
    • 描述:自顶层窗口(也就是桌面)开始搜索条件匹配的窗体,并返回这个窗体的句柄。不搜索子窗口、不区分大小写。找不到就返回0
    • 参数:
      • lpClassName:字符型,是窗体的类名,这个可以在Spy++里找到。
      • lpWindowName:字符型,是窗口名,也就是标题栏上你能看见的那个标题。
    • 说明:这个函数我们仅能用来找主窗口。
  • FindWindowEx(hwndParent=0, hwndChildAfter=0, lpszClass=None, lpszWindow=None);
    • 描述:搜索类名和窗体名匹配的窗体,并返回这个窗体的句柄。不区分大小写,找不到就返回0。
    • 参数:
      • hwndParent:若不为0,则搜索句柄为hwndParent窗体的子窗体。
      • hwndChildAfter:若不为0,则按照z-index的顺序从hwndChildAfter向后开始搜索子窗体,否则从第一个子窗体开始搜索。
      • lpClassName:字符型,是窗体的类名,这个可以在Spy++里找到。
      • lpWindowName:字符型,是窗口名,也就是标题栏上你能看见的那个标题。
    • 说明:找到了主窗口以后就靠它来定位子窗体啦。
      来源: 

对于一个窗口下的多个子窗口,可以通过类名和窗口名进行区分,若有多个子窗口的类名和窗口名相同,则只能从第一个开始迭代查找。当然,如果我们知道子窗口的排列顺序,可以对FindWindowEx函数进行简单的封装,通过索引号查找指定窗口的句柄。

1
2
3
4
5
6
7
8
9
10
11
def 
find_idxSubHandle(pHandle, winClass, winName 
= 
None
, index
=
0
): 
    
"""
    
已知子窗口的窗体类名,窗口名
    
寻找第index号个同类型的兄弟窗口
    
""" 
    
assert 
type
(index) 
=
= 
int 
and 
index >
= 
0 
    
handle 
= 
win32gui.FindWindowEx(pHandle, 
0
, winClass, winName) 
    
while 
index > 
0
        
handle 
= 
win32gui.FindWindowEx(pHandle, handle, winClass, winName) 
        
index 
-
= 
1 
    
return 
handle

若要获取任意子窗口的句柄,则可以建立一个索引数组,然后多次调用find_idxSubHandle 函数,写成一个递归函数的形式:

1
2
3
4
5
6
7
8
9
10
11
12
def 
find_subHandle(pHandle, winClassList): 
    
"""
    
递归寻找子窗口的句柄
    
pHandle是祖父窗口的句柄

    winClassList是各个子窗口的class列表,由元组(窗口类名,窗口名,索引号)为元素组成的数组,父辈的list-index小于子辈

      """ 

    
assert 
type
(winClassList) 
=
= 
list 
    
if 
len
(winClassList) 
=
= 
1
        
return 
find_idxSubHandle(pHandle, winClassList[
0
][
0
], winClassList[
0
][
1
], winClassList[
0
][
2
]) 
    
else
:
        
pHandle 
= 
find_idxSubHandle(pHandle, winClassList[
0
][
0
], winClassList[
0
][
1
], winClassList[
0
][
2
]) 
        
return 
find_subHandle(pHandle, winClassList[
1
:])

好了,只要能拿到句柄,一切就都好办了。

按照上一篇中的步骤,一步一步模拟操作就可以了。

1)在下载地址对应的文本编辑框中输入要下载的网址。如下图所示:

在spy++中可以看出,主程序中一共有2个编辑框,除了下载地址的编辑框,还有就是右下角的那个。并且可以注意到,编辑框的窗口名就是编辑框中的文本,因此在程序运行过程中,改变编辑框的文本,其窗口名就会发生变化。故只通过类名加索引的方式获取这个编辑框的句柄。

1
edithd
=
find_subHandle(MHandle,[(
'Edit'
,
None
,
1
)]) 
# 下载地址输入框

模拟向输入框中输入网址,可以使用win32gui.SendMessage函数给输入框发送消息。

1
win32gui.SendMessage(edithd,win32con.WM_SETTEXT,
None
,url) 
# 输入下载地址

2)点击 添加任务 按钮。

1
2
btAddhd 
= 
find_subHandle(MHandle,[(
'Button'
,"
",2),('Button',u"
添加任务",
0
)])
win32gui.SendMessage(btAddhd,win32con.BM_CLICK,
None
,
None
)

这时列表中就会出现 已加入的任务。

3)点击 整理任务 按钮。

1
2
sorthd
=
find_subHandle(MHandle,[(
'Button'
,u
"整理任务"
,
0
)]) 
#
win32gui.SendMessage(sorthd,win32con.BM_CLICK,
None
,
None
)

这时列表中会显示网盘地址和文件ID

待全部解析完后, 整理任务 按钮旁边出现 解析勾选 按钮。

4)点击 解析勾选 按钮

1
2
parsehd
=
find_subHandle(MHandle,[(
'Button'
,u
"解析勾选"
,
0
)]) 
#
win32gui.PostMessage(parsehd,win32con.BM_CLICK,
None
,
None
)

注意,这里使用PostMessage来处理消息。主要是由于点击 解析勾选 按钮后,会弹出对话框,如果使用SendMessage,主程序就会阻塞,直至对话框关闭。而主程序又必须在发送完消息后捕获对话框句柄,然后将其关闭。这就导致了一个死循环,除非人工将对话框关闭。关于PostMessage和SendMessage的区别,如下:

    • PostMessage(hWnd, Msg, wParam, lParam)
      • 描述:在消息队列中加入为指定的窗体加入一条消息,并马上返回,不等待线程对消息的处理。
      • 参数:
        • hWnd:整型,接收消息的窗体句柄
        • Msg:整型,要发送的消息,这些消息都是windows预先定义好的,可以参见))
        • wParam:整型,消息的wParam参数
        • lParam:整型,消息的lParam参数
      • 说明:简单说,就是给指定程序发一个消息,这些消息都用整型编好号,作为windows的常量可以查询的。在这里,我们用的就是win32con这个库里定义的WM_COMMAND这个消息,具体的wParam和lParam是根据消息的不同而不同的。具体请根据MSDN查阅。

    关于wParam的low word和high word:

        

    查阅MSDN的消息时,会发现有的wParam定义了low word和high word,这是什么呢?wParam的定义是32位整型,high word就是他的31至16位,low word是它的15至0位,如图。当参数超过两个,wParam和lParam不够用时,可以将wParam就给拆成两个int16来使用。这种时候在里记得用把HIWORD的常数向左移16位,再加LOWORD,即wParam = HIWORD<<16+LOWORD。

    来源: 

 SendMessage(hWnd, Msg, wParam, lParam)

  • 描述:在消息队列中加入为指定的窗体加入一条消息,直到窗体处理完信息才返回。
  • 参数:
    • hWnd:整型,接收消息的窗体句柄
    • Msg:整型,要发送的消息,这些消息都是windows预先定义好的,可以参见.aspx#system_defined)
    • wParam:整型,消息的wParam参数
    • lParam:整型,消息的lParam参数
  • 说明:wParam和IParam根据具体的消息不同而有不同的定义,详情参阅Part 2.
    来源: 

5)关闭烦人的对话框

上步说过,当点击勾选解析 按钮时,就会弹出下面的对话框。我们需要点击 取消 按钮,或者直接点右下角的关闭 按钮。

由于后面还会出现对话框,对于这类只需点击关闭按钮的操作,我们可以写个函数封装。

def closeDialog(win_name): 
   handle = get_wHandle(u'#32770',win_name) # Dialog的类名为 #32770
   print(handle)
   time.sleep(0.5)
   win32gui.SendMessage(handle,win32con.WM_CLOSE,0,0)

def get_wHandle(win_class_name,win_name):   
   while not win32gui.FindWindow(win_class_name, win_name):  
       time.sleep(0.2)  
   return win32gui.FindWindow(win_class_name, win_name)
然后调用这个函数,
closeDialog(u"是否启用VIP模式解析")
6)选中 全选。
   allSelhd=find_subHandle(MHandle,[('Button',"",1),('Button',u"全选",0)]) # ‭4F0A4E‬ 
   if win32gui.SendMessage(allSelhd,win32con.BM_GETCHECK):
       win32gui.SendMessage(allSelhd,win32con.BM_CLICK,None,None)
   win32gui.SendMessage(allSelhd,win32con.BM_CLICK,None,None)
7)点击 复制链接 按钮。
   copyhd = find_subHandle(MHandle,[('Button',u"复制链接",0)]) 
   win32gui.PostMessage(copyhd,win32con.BM_CLICK,None,None)
此时,又会弹出烦人的对话框。利用前面写的函数,关闭对话框。
closeDialog(u"复制成功")
8)从系统剪切板中读取链接地址。完成后关闭程序。
   win32clipboard.OpenClipboard() 
   text = win32clipboard.GetClipboardData(win32clipboard.CF_TEXT)
   win32clipboard.CloseClipboard()
   win32gui.SendMessage(MHandle,16)
注意:
1、这些步骤需按顺序执行,前一个步骤的结果直接影响下一步的进行。
2、由于每一步执行需要时间,而每步所需的时间不可预测,故需要一个状态量指示当前状态。在这个程序中,我们发现控件 Afx:400000:b:10003:900015:0 的名字每步执行完后都会响应变化,故可根据名字来控制程序流的执行。
--》1--》2--》
--》3--》
--》4--》5--》
--》6--》7--》
--》8
通过查询控件名,等待每步执行完成。
def getState(pHandle): 
   time.sleep(1)
   afx = win32gui.FindWindowEx(pHandle,None,'Afx:400000:b:10003:900015:0',None)
   return win32gui.GetWindowText(afx)
def waitState(pHandle,msg):
   while  msg != getState(pHandle):
       time.sleep(0.2)
waitState(MHandle,u"请整理任务 →")
waitState(MHandle,u"← 请点此解析")
waitState(MHandle,u"复制真实链接 →")
waitState(MHandle,u"引导完毕..")
3. 全部的程序和代码见我的资源(http://download.csdn.net/detail/shawpan/9755395)
 

 

 

 
 

转载地址:http://jrhci.baihongyu.com/

你可能感兴趣的文章
第16课:选择最优执行计划
查看>>
第15课:参数化路径
查看>>
第14课:选择率
查看>>
第13课:表达式提取
查看>>
第12课:统计信息
查看>>
第11课:逻辑优化汇总
查看>>
第10课:表达式的规范化
查看>>
第09课:等价推理
查看>>
第08课:消除外连接
查看>>
第07课:子查询提升
查看>>
第06课:子连接提升
查看>>
第05课:连接顺序交换规则
查看>>
第04课:谓词下推
查看>>
第03课:调整执行计划
查看>>
第02课:解读执行计划
查看>>
第01课:SQL 语句的历程
查看>>
导读:物理优化篇
查看>>
导读:逻辑优化篇
查看>>
开篇词:翻过数据库优化器这座山峰
查看>>
堆排序之MAX-HEAPIFY注释
查看>>