网页自动化初级教程

供新手入门和老手参考的教程和相关资料,包括中文帮助

Moderators: tmplinshi, arcticir

tmplinshi
Posts: 1604
Joined: 01 Oct 2013, 14:57

网页自动化初级教程

05 Jan 2014, 05:41

网页自动化教程导读:
  • 网页自动化两种方式:通过 IE 操作网页(进程外)和内嵌 IE 控件到 AHK GUI 中(进程内,请参阅 GUI 控件类型中的示例):
    两者在操作网页 DOM 上是一致的。
  • 一楼:良好的网页操作示例,包含修改网页内容、检测网页事件等,以本论坛登录页面为例。
  • 四楼:网页操作基础入门,通过分析源码说明了基本网页元素的操作方法,以老官方论坛搜索页面为例(似乎打不开?)。
  • 五楼:网页操作基础入门,使用 ahk web recorder 快速获取网页信息,以百度登录页为例,部分代码基于 AutoHotkey Classical。
  • linpinger 的教程:操作网页使用wget模拟http的get/post来模拟登录并获取资源等,并回复了大量网页操作的问题。
    JScript 代码注入网页:以后可能会扩展这部分内容
其他:
学习 DHTML与 DOM 的关系
网页操作辅助工具:iWB2 Learnerahk web recorder
网页调试工具:一般浏览器自带或作为扩展,如 Firefox 中的 Firebug。
抓包分析工具:HttpWatch/HTTP Debugger Pro/HttpFox(Firefox)
外部操作网页工具:curl、wget(自动化网页的第三种方式)
参考一些现成的工具:网页自动操作通用工具、网页点击专家、网页幽灵、网页自动提交监控工具等
注:以上内容由 amnesiac 补充。

写着玩的 :D

Code: Select all

; DOM示例.ahk

; DOM 文档:
; 	http://www.w3school.com.cn/xmldom/xmldom_reference.asp
; 	http://www.w3schools.com/jsref/dom_obj_all.asp
; 	http://www.w3school.com.cn/htmldom/htmldom_reference.asp

#NoEnv
#SingleInstance Force
SetBatchLines -1
ListLines Off
ComObjError(False)

; =================================
;		界面
; =================================
Gui, Margin, 0, 0
Gui Add, ActiveX, w800 h500 vWB, Shell.Explorer
Gui, Show

; =================================
;		打开网页,并等待加载完毕
; =================================
OpenLoginPage:
WB.Navigate("http://ahkscript.org/boards/ucp.php?mode=login")
While WB.readystate != 4 or WB.busy
	Sleep 10

; 如果已经登录则退出
if !InStr(WB.LocationUrl, "login")
{
	Gui, +OwnDialogs
	MsgBox, 36, 确认退出登录, 脚本需要退出论坛的登录,是否允许?(因为此脚本是在登录页面进行演示的)
	IfMsgBox, No
	{
		MsgBox, 好吧。请手工退出登录后再运行此脚本。再见!
		ExitApp
	}

	; 退出登录
	WB.document.getElementById("menubar").all.tags("a")[0].Click()
	While WB.readystate != 4 or WB.busy
		Sleep 10

	Goto, OpenLoginPage
}

; =================================
;		修改网页
; =================================
doc := WB.doc
doc.getElementById("username").Disabled := True ; 禁用【用户名输入框】
doc.getElementById("password").Disabled := True ; 禁用【密码输入框】
doc.getElementById("username").style.backgroundColor := "A0FABF" ; 修改【用户名输入框】背景色
doc.getElementById("password").style.backgroundColor := "FDCAAE" ; 修改【密码输入框】背景色
doc.getElementById("login").value := "点击登录 :)" ; 修改【登录按钮】文字
doc.getElementById("login").style.Color := "Red"   ; 修改【登录按钮】文字颜色
doc.getElementById("login").style.backgroundColor := "FFFF00" ; 修改【登录按钮】背景颜色
doc.images[0].src := "http://t1.qpic.cn/mblogpic/7d0ba55a04cb2e504246/2000.jpg" ; 修改 logo 图片

; =================================
;		监测事件
; =================================
; 监测 doc 事件
ComObjConnect(doc, doc_events)

; 监测登录按钮所在 form 的事件
form := doc.forms[0]
ComObjConnect(form, "LoginForm_")

; 监测登录按钮事件
LogInBtn := doc.getElementById("login")
ComObjConnect(LogInBtn, "LogInBtn_")

; 监测登录按钮上级<TD>事件
LogInBtnPTD := LogInBtn.parentNode
ComObjConnect(LogInBtnPTD, "LogInBtnPTD_")

; =================================
;		设置定时移动登录按钮
; =================================
LogInBtn.style.position := "relative" ; 按钮位置设为相对位置
MoveStep                := -50 ; 按钮移动步伐
BtnW                    := LogInBtn.offsetWidth ; 按钮宽度
BtnPW                   := LogInBtn.parentNode.offsetWidth ; 按钮的上级元素的宽度
SetTimer, Move_LogInBtn, 200
Return

; =================================
;		移动登录按钮
; =================================
Move_LogInBtn:
	x += MoveStep
	LogInBtn.style.left := x

	BtnX := LogInBtn.offsetLeft
	MoveStep := ( BtnX < Abs(MoveStep) || (BtnX + BtnW >= BtnPW) ) ? -MoveStep : MoveStep
Return

; =================================
;		关闭界面则退出脚本
; =================================
GuiClose:
ExitApp

; ================================================== 以下是函数 ==================================================

; =================================
;		整个 wb 文档的事件
; =================================
Class doc_events
{
	oncontextmenu(doc) {
		doc.parentWindow.event.returnvalue := False ; 取消事件的动作
		MsgBox, 右键被禁用了
	}

	OnClick(doc) {
	    if doc.parentWindow.event.srcElement.name in username,password
	    	doc.parentWindow.event.srcElement.value := doc.parentWindow.event.srcElement.name
	}

	ondblclick(doc) {
		MsgBox, 检测到双击
	}
}

; =================================
;		登录按钮所在 form 的事件
; =================================
LoginForm_onsubmit(form) {
	form.document.parentWindow.event.returnvalue := False ; 取消事件的动作
	form.document.getElementById("login").value := "点击登录 :)" ; 按钮文字会被网页恢复,这里重新修改【登录按钮】文字
	MsgBox, 登录动作被取消了
}

; =================================
;		登录按钮上级 <TD> 的事件
; =================================

; 鼠标悬停
LogInBtnPTD_onmouseover(LogInBtn) {
	SetTimer, Move_LogInBtn, Off ; 停止移动按钮
}

; 鼠标移开
LogInBtnPTD_onmouseout(LogInBtn) {
	SetTimer, Move_LogInBtn, 200 ; 恢复移动按钮
}

; =================================
;		登录按钮的事件
; =================================

; 鼠标悬停
LogInBtn_onmouseover(LogInBtn) {
	LogInBtn.style.backgroundColor := "FDD0FD"
}

; 鼠标移开
LogInBtn_onmouseout(LogInBtn) {
	LogInBtn.style.backgroundColor := "FFFF00"
}
Gist: https://gist.github.com/tmplinshi/8266669
Last edited by tmplinshi on 30 Sep 2018, 00:16, edited 5 times in total.
abs
Posts: 15
Joined: 06 Jan 2014, 01:28

Re: DOM示例

06 Jan 2014, 03:04

代码非常棒!
比我之前找到的还全!!
有了这些,其实我觉得AHK真的应该好好发展HTML GUI。像AAUTO那样。

AAUTO号称很好用,可是我觉得太难学,所以还是继续用AHK来写工具。
tmplinshi
Posts: 1604
Joined: 01 Oct 2013, 14:57

Re: DOM示例

06 Jan 2014, 03:06

很高兴这个代码有所帮助 :)
User avatar
amnesiac
Posts: 186
Joined: 22 Nov 2013, 03:08
Location: Egret Island, China
Contact:

网页自动化初级教程

19 Aug 2014, 03:25

注:本文待更新11目标网页已失效(考虑替换为 http://ahkscript.org/boards/search.php)22简介 iWebBrowser2 的用法(另:本文作为网页自动化的教程似乎过于简单,以后可能完全重写)。
本文翻译并改写自官网的两篇教程,因为它们写的都通俗易懂,不论您之前对 HTML 了解多少,相信在学习本文后都能轻松入门:
  • 本文说明
    本文的目的是让普通的 AutoHotkey 用户学会如何使用 COM 控制网页,就像控制 Windows 程序那样。这里不会对一些相关概念进行深入探讨,不过会提供对这些内容进行深入了解的链接。不要求您有多少编程经验,不过这里假设您已经能轻松地编写/执行 AutoHotkey 代码了。在本文中对网页进行操作时提供了 JavaScript 代码及相同功能的 AutoHotkey 代码。我觉得通过 Javascript 学习在 AutoHotkey 中如何控制网页是很棒的方法,因为很容易在网上找到大量的 Javascript 代码,同时可以方便地把它们转换成 AutoHotkey 代码,这样对我们学习使用 COM 控制网页有很大的帮助。另一方面,通过 COM 操作网页只适合 Internet Explorer,而 Javascript 可以用于大部分浏览器。
  • 相关术语
    在本文中使用了下面的术语,您可以点击这些链接对它们进行更深入的了解。
    HTML DOMJavaScriptCOMMethodsdocumentvalueelementformnameIDInputTagselectedIndexcheckedinnerTextinnerHTML
  • 对象方法
    在本文中使用了下列方法:
    alert()getElementById()getElementsByName()getElementsByTagName()focus()click()
  • 代码用法
    在本文中使用了一些含有 javascript 的例子, 它表示输入到 URL 地址栏的代码。这些例子基于 (且可用于) 论坛的 Search 页面。这个例子使用 alert() 方法弹出消息框并显示 Hello World! 只需把这段 Javascript 代码简单地放到地址栏并回车即可看到效果:
    javascript: alert('Hello World!')
    objIE.Navigate("javascript: alert('Hello World!')")
创建 Internet Explorer 对象

Code: Select all

objIE := ComObjCreate("InternetExplorer.Application") ; 创建 IE 对象
objIE.Visible := true ; 由于 IE 对象默认是隐藏的(后台),这里让它显示出来,这样我们可以看到操作的效果
objIE.Navigate("www.AutoHotkey.com") ; 导航到网页
访问已有的 Internet Explorer 对象
没有一个简单的命令可以实现,这里需要使用另外的函数:

Code: Select all

objIE := IEGet()   ;上次活动的窗口/选项卡
; 或 objIE := IEGet("Google")   ; 选项卡名称
在使用这个函数时,只需把下面的函数定义也添加到脚本中即可:

Code: Select all

IEGet(Name="")      ; 获取到现有的 IE 窗口/选项卡的指针
{
   IfEqual, Name,, WinGetTitle, Name, ahk_class IEFrame
      Name := ( Name="New Tab - Windows Internet Explorer" ) ? "about:Tabs"
      : RegExReplace( Name, " - (Windows|Microsoft) Internet Explorer" )
   For Pwb in ComObjCreate( "Shell.Application" ).Windows
      If ( Pwb.LocationName = Name ) && InStr( Pwb.FullName, "iexplore.exe" )
         Return Pwb
} ;written by Jethrow
判断网页加载完成
一般情况下使用 ReadyState 可以工作的很好(不放心就加个 busy)。

Code: Select all

while, objIE.ReadyState != 4  or objIE.busy
   Sleep, 10
还可以使用 DocumentComplete 事件:

Code: Select all

objIE := ComObjCreate("InternetExplorer.Application")
objIE.Visible := True
ComObjConnect(objIE, "IE_"), loading := true ; Connect IE object & set var "loading" as TRUE
objIE.Navigate("www.AutoHotkey.com")
while, loading
   Sleep, 10
MsgBox, DONE!
objIE := "" ; Release & Disconnect IE object
return

IE_DocumentComplete() { ; the "IE_" prefix corresponds to the ComObjConnect() function above
   global loading := false ; Break the While-Loop
}
在官方论坛中还可以找到其他的方法。

访问网页内容 - HTML DOM
要理解 Javascript 是如何控制网页的,我们需要对 HTML DOM 有个简单的认识。它类似于网页中的地图或层次结构,像下面的图中显示的那样:
*Image is from this website, which is another great resource for learning Javascript.
Image
在这图片中,请注意 document 对象,以后我们会经常使用它。在访问网页时,需要通过 HTML DOM 进行导航,下面是一些简单的操作:

对象名称与索引
获取首个表格中首个元素的值,首个表格是 Search for Keywords 输入框。这个路径看起来类似这样(集合中对象的索引从 0 开始):
document.forms[0].elements[0].value
可以把这个值在弹出窗口中显示出来(这里使用 Javascript 的方法):
javascript: alert(document.forms[0].elements[0].value)
MsgBox % objIE.document.forms[0].elements[0].value

对象名称 / ID 属性
还可以使用对象的名称或 ID。这里第一个表格的名称为 SearchForm,在它里面的第一个元素名称为 search_keywords。下面的代码会产生相同的效果:
javascript: alert(document.SearchForm.search_keywords.value)
MsgBox % objIE.document.SearchForm.search_keywords.value

或者如果我们只知道元素名称为 search_keywords,那么可以使用 all 来显示这个元素的值,它表示对网页中所有元素的引用:
javascript: alert(document.all.search_keywords.value)
MsgBox % objIE.document.all.search_keywords.value

getElement 方法
如果要根据一些条件获取元素的值,可以使用下面的三种方法:
  • getElementById(id):返回到指定 ID 的首个对象的引用
  • getElementsByName(name):返回含指定名称的对象的集合
  • getElementsByTagName(tagname):返回含指定标记名的对象的集合
下面的例子将显示 Search for Author 输入框的值,这是网页中含 INPUT 标记的第四个元素:(注:项目的编号可能是动态的)
javascript: alert(document.getElementsByTagName('input')[3].value)
MsgBox % objIE.document.getElementsByTagName("input")[3].value

控制网页
现在我们已经能从网页中获取信息,接着开始学习如何控制网页。注:如果 JavaScript 没有对方法进行结束,则使用 void 0。

把焦点放到某个网页元素 - focus()
把焦点设置到 Search for Keywords 输入框:
javascript: document.all.search_keywords.focus()
objIE.document.all.search_keywords.focus()

点击某个网页元素 - click()
点击 Search 按钮:
javascript: document.getElementsByTagName('input')[11].click()
objIE.document.getElementsByTagName("input")[11].click()

设置输入字段的值 - value
设置 Search for Keywords 输入框的值:
javascript: document.all.search_keywords.value = 'Input Value'; void 0
objIE.document.all.search_keywords.value := "Input Value"

选择下拉框 - selectedIndex
<SELECT class=post name=sort_by><OPTION selected value=0>Post Time</OPTION><OPTION value=1>Post Subject</OPTION><OPTION value=2>Topic Title</OPTION><OPTION value=3>Author</OPTION><OPTION value=4>Forum</OPTION></SELECT>
这是 Sort By 下拉框的 HTML 代码。下面将 Dropdown 设置为 Author:
javascript: document.all.sort_by.selectedIndex = 3; void 0(注:还可以使用 value = 3)
objIE.document.all.sort_by.selectedIndex := 3

选择单选框/复选框 - checked
<INPUT value=ASC type=radio name=sort_dir> Ascending<BR><INPUT value=DESC CHECKED type=radio name=sort_dir> Descending
这是 Sort By 单选框的 HTML 代码。下面设置单选框为 Ascending:
javascript: document.all.sort_dir[0].checked = true; void 0
objIE.document.all.sort_dir[0].checked := True

从网页元素中获取文本 - innerText
如果想获取页面顶部的文本(innerHTML 将返回整个 HTML):
text := objIE.document.getElementsByTagName("TD")[2].innerText
获取网页的文本或 HTML:
text := objIE.document.documentElement.innerText

完整的演示脚本
请参阅顶楼的 DOM 示例,注意这里使用的是 WebBrowser 对象,不过对于 DOM 的操作是相同的。

小结

到这里我想您已经学会了如何对网页进行基本控制,下一步我建议:
  • 尝试对您喜爱的网页进行这些控制操作;
  • 寻找更多的 JavaScript 例子,然后尝试把它们转换成 AutoHotkey 代码;
  • 学习更多访问 HTML DOM 的方法。
必须提及的一点是:WebBrowser 对象和 InternetExplorer 对象(两者的用法请参阅 Reference for Visual Basic Developers)的差异。前者用于 AutoHotkey GUI 中的托管网页,后者直接利用 IE 浏览器自动化网页,它们的大多数方法、属性和事件都相同。由于文中操作于 IE 浏览器的网页,所以我将对象名称更换为 objIE 以免误解(原文为 WB)。
AutoHotkey 学习指南(Beauty of AutoHotkey)
I do not make codes, and only a porter of AutoHotkey: from official to Chinese, from other languages to AutoHotkey, and show AutoHotkey to ordinary users sometimes.
User avatar
amnesiac
Posts: 186
Joined: 22 Nov 2013, 03:08
Location: Egret Island, China
Contact:

AHK的网页自动化操作(COM编程)

07 Sep 2014, 22:08

转注:本文作者彪悍的小玄([email protected]),原发表于 AHKCN 群共享。尽管主要内容适用于当时的 AutoHotkey Classical 版,不过仍有些内容有参考意义,所以经作者授权做细微格式调整后转发于此。

其实AHK官网上关于web的自动化操作的资料和代码已经很齐全了,但由于没有整理出一个完整的文档,也没有集成到帮助文件里面,所以一直很多人都不知道如何操作。在开始本文之前,先推荐官网上的 Basic Webpage Controls with JavaScript / COM(作者:jethrow),如果英文能力还可以的朋友可以去看看。 本文基本上是对官方这篇文章的讲解和扩展。

建立COM编程环境
在开始学习之间,我们需要先建立一个COM编程的开发环境,需要的应用程序有: autohotkey v1.0.48.05 , COM.ahk , ACC.ahk 和一个用ahk写的小工具ahk_web_recorder.ahk ,测试ahk_l的时候,同样需要ahk_l的最新版本。 COM.ahk和ACC.ahk是编程中需要用到的ahk标准库,下载后需要放到ahk安装目录下面的lib目录下.关于什么是标准库,可以参考ahk帮助文件中的standard library一节.
ahk_web_recorder.ahk是一个非常好用的ahk工具,功能和AU3 spy一样,只是它是用来查找web页面上的控件信息的,方便我们接下来的编程.也可以使用ahk编译成exe使用.需要指出的是ahk_web_recorder.ahk本身也是通过COM.ahk和ACC.ahk这两个标准库实现的,所以需要先安装COM.ahk和ACC.ahk才能使用该程序.

从一个完整的登录实例开始
在开始讲解web操作之前,我先给出一个百度登录的实例,用vbs,js,ahk,ahk_l,au3这五种语言写出。希望大家对比一下语法的区别,然后学会这几种语言之间的转换,那么在网络上看到其它语言写的脚本,也可以很快的用ahk实现了。
Vbs版百度登录实例(将下面的代码保存为test.vbs 双击即可看到运行效果):

Code: Select all

set obj = WScript.CreateObject("InternetExplorer.Application")	'创建一个IE对象
obj.Visible=true	'设置IE为可见
obj.Navigate("https://passport.baidu.com/?login&tpl=mn")	'打开百度登录页面
While obj.ReadyState <> 4	'等待网页加载完成
Wend
obj.document.getElementById("username").value = "ahk_test"	'输入用户名
obj.document.getElementById("normModPsp").value = "qwe123"	'输入密码
obj.document.all(137).click	'点击登录按钮
Js版百度登录实例(将下面的代码保存为test.js 双击即可看到运行效果):

Code: Select all

obj = new ActiveXObject("InternetExplorer.Application");		//创建一个IE对象
obj.Visible=true;	//设置IE为可见
obj.Navigate("https://passport.baidu.com/?login&tpl=mn");	//打开百度登录页面
while (obj.ReadyState != 4){;}	//等待网页加载完成
obj.document.getElementById("username").value = "ahk_test"	//输入用户名
obj.document.getElementById("normModPsp").value = "qwe123"	//输入密码
obj.document.all(137).click()	//点击登录按钮
PS: JS是严格区分大小写的,还有如果是调用对象的方法,不管有没有参数,一定要加上“()”,如果是属性,则不要加“()”.

AHK classic版百度登录实例(有点复杂):

Code: Select all

COM_Init()  ;初始化COM组件
pwb := COM_CreateObject("InternetExplorer.Application")   ;创建一个IE对象
COM_Invoke(pwb,"Visible",1)	;设置IE为可见
COM_Invoke(pwb,"Navigate","https://passport.baidu.com/?login&tpl=mn")	;打开百度登录页面
While COM_Invoke(pwb,"ReadyState") <> 4	 ;等待网页加载完成
{}
COM_Invoke(pwb,"document.getElementById(username).value","ahk_test")	;输入用户名
COM_Invoke(pwb,"document.getElementById(normModPsp).value","qwe123")	;输入密码
COM_Invoke(pwb,"document.all(137).click")	;点击登录按钮
COM_Release(pwb)    ;释放pwb对象
COM_CoUninitialize()    ;卸载COM组件
AHK_L 版的百度登录实例(很简单):

Code: Select all

pwb := ComObjCreate("InternetExplorer.Application")
pwb.Visible := 1
pwb.Navigate("https://passport.baidu.com/?login&tpl=mn")
while pwb.ReadyState <> 4
{}
pwb.document.getElementById("username").value := "ahk_test"
pwb.document.getElementById("normModPsp").value := "qwe123"
pwb.document.all(137).click()
AutoIt3版百度登录实例(和VBS的语法很像):

Code: Select all

$pwb = ObjCreate("InternetExplorer.Application")
$pwb.Visible = 1
$pwb.Navigate("https://passport.baidu.com/?login&tpl=mn")
while $pwb.ReadyState <> 4
WEnd
$pwb.document.getElementById("username").value = "ahk_test"
$pwb.document.getElementById("normModPsp").value = "qwe123"
$pwb.document.all(137).click()
虽然上面的代码使用的语言各不相同,但是大体的过程还是类似的。我将过程归纳为下面几步:
  • 获取一个InternetExplorer.Application对象。
  • 设置网页可见,并将浏览器定位到相应页面。
  • 等待页面加载完成。
  • 操作网页上的控件,如:设置用户名、密码、点击按钮、提交表单等。
详细解析分步操作
如何获取一个InternetExplorer.Application对象
这里有两种方法:
  • 创建一个新的InternetExplorer.Application对象;
  • 获取已经启动的浏览器的InternetExplorer.Application对象。
关于创建一个新的InternetExplorer.Application,上面已经有实例,所以这里不再重复。下面讲一下从已经启动的浏览器获取InternetExplorer.Application对象。
下面提供几个ahk baisc版的函数用于获取已经存在的InternetExplorer.Application对象:
1. IE_Get(win_title) ;使用窗口的标题来获取对象(只支持IE)

Code: Select all

IEGet( name="" )
{
   IfEqual, Name,, WinGetTitle, Name, ahk_class IEFrame ; Get active window if no parameter
   Name := ( Name="New Tab - Windows Internet Explorer" ) ? "about:Tabs" : RegExReplace( Name, " - (Windows|Microsoft) Internet Explorer" )
   oShell := COM_CreateObject( "Shell.Application" ) ; Contains reference to all explorer windows
   Loop, % COM_Invoke( oShell, "Windows.Count" ) {   
      If pwb := COM_Invoke( oShell, "Windows.item[" A_Index-1 "]" )
         If ( COM_Invoke( pwb, "LocationName" ) = name && InStr( COM_Invoke( pwb, "FullName" ), "iexplore.exe" ) )
            Break
      COM_Release( pwb ), pwb := ""
   }
   COM_Release( oShell )
   Return, pwb
}
2. IE_GetPwb(hwnd) ;使用浏览器控件的句柄来获取对象(支持IE内核的浏览器,如:世界之窗,遨游,IE等)
注意这里使用的是控件的句柄,不是浏览器主窗口的句柄
;;测试说明:激活浏览器正在浏览的页面,按Alt+1看msgbox的输出结果。有值则表示获取pwb成功。

Code: Select all

COM_Init()
Return

!1::
MouseGetPos, xpos, ypos,, hCtl, 3
msgbox % IE_GetPwb(hCtl)
Return

IE_GetPwb(hWnd)
{
    Static
    If Not   pfn
      pfn := DllCall("GetProcAddress", "Uint", DllCall("LoadLibrary", "str", "oleacc.dll"), "str", "ObjectFromLresult")
    ,   msg := DllCall("RegisterWindowMessage", "str", "WM_HTML_GETOBJECT")
    ,   COM_GUID4String(iid, "{00020400-0000-0000-C000-000000000046}")
    If   DllCall("SendMessageTimeout", "Uint", hWnd, "Uint", msg, "Uint", 0, "Uint", 0, "Uint", 2, "Uint", 1000, "UintP", lr:=0) && DllCall(pfn, "Uint", lr, "Uint", &iid, "Uint", 0, "UintP", pdoc:=0)=0

    if(pdoc)
    {
        pwb :=   COM_QueryService(pdoc ,"{332C4427-26CB-11D0-B483-00C04FD90119}")
    }
    Return   pwb
}
3. IE_GetPwbByUrl(hwnd="",url="") ;使用浏览器的窗口句柄和标签的url来获取对象(支持IE内核的多标签浏览器,,如:世界之窗,遨游,IE等)。适用于多标签浏览器的后台窗口操作,强烈推荐(需要com.ahk和acc.ahk库文件)。

Code: Select all

!1::
WinGet,hwnd,ID,A
msgbox % Return IE_GetPwbByUrl(hwnd,"http://www.autohotkey.com/forum/viewtopic.php?t=30599&highlight=ie7")
Return

IE_GetPwbByUrl(hwnd="",url="")
{
    if(!hwnd)
    win := "A"
    Else
    win := "ahk_id " . hwnd
    WinGet, ControlList, ControlListhWnd, %win%
    ;msgbox % controlList
    ACC_Init()
    Loop, Parse, ControlList, `n
    {
        ; Get the class name of the current control
        WinGetClass, ThisWinClass, ahk_id %A_LoopField%
        ; If the class name is correct and it is a window, it should support JS execution
        If (ThisWinClass = "Internet Explorer_Server") && (DllCall("IsWindow", UInt, A_LoopField))
        {
            IID_IHTMLWindow2 := "{332C4427-26CB-11D0-B483-00C04FD90119}"
            pacc := ACC_AccessibleObjectFromWindow(A_LoopField)
            pwin := COM_QueryService(pacc,IID_IHTMLWindow2,IID_IHTMLWindow2)

            if(!url)
            {
				rv := pwin
                break
            }
            Else if( COM_Invoke(pwin, "document.url") = url)
            {
                rv := pwin
                break
			}
        }
    }
    COM_Release(pacc)
    Return rv
}
设置网页可见,并将浏览器定位到相应页面
参考前面给出的源代码,已经用5种语言实现。
等待页面加载完成
前面的代码已经给出了方法,适合阻塞式的访问。另外这个链接里面提供了用COM事件实现的方法,适用于异步操作。这里不再做介绍了。
操作网页上的控件
IE上面的控件和应用程序的控件不同,不能用AU3_Spy来检测出来。需要用ahk_web_recorder.ahk来辅助编程。

让网页操作自动化实战
下面以百度登录为例讲解一下简单网页自动登录的操作方法.
输入账号
首先,用鼠标将焦点设置在”帐号”输入框内,同时观察iWebBrowser2窗口的输出。
image001.png
百度登录页:焦点定位到【账号】输入框。
通过iWebBrowser2,我们可以获取“帐号” 输入框的如下信息:
index=107 name=username id=username

因此相应的,我们有如下三种方法设置该文本框的内容(其实远远不止三种,这里仅给出最基本的方法,其它方法可以去参考DOM编程的资料)
  • javascript:document.all[107].value="ahk_test" ; void 0
  • javascript:document.getElementsByName('username')[0].value="ahk_test" ; void 0
    此方法中[0]为下标值,当页面中有多个元素的name=’username’的时候,要做相应的调整。
  • javascript:document.getElementById('username').value="ahk_test" ; void 0
以上是js代码,可以如上图在浏览器的地址栏进行很方便的测试。对应的ahk classic版代码如下。
  • COM_Invoke(pwb,"document.all[107].value","ahk_test")
  • COM_Invoke(pwb,"document.getElementsByName(username)[0].value","ahk_test")
  • COM_Invoke(pwb,"document.getElementById(username).value","ahk_test")
其中pwb这个对象的获取见上面的例子。
对应的ahk_l版代码
  • pwb.document.all[107].value := “ahk_test”
  • pwb.document.getElementsByName(“username”)[0].value := “ahk_test”
  • pwb.document.getElementById(“username”).value := “ahk_test”
可以看出,ahk_l的操作更像在做COM编程- -! ,所以推荐大家用ahk_l的版本。不过下面的例子我还是用ahk classic的版本给出,毕竟复杂一些。
其实也可以直接通过ahk来调用js语句,如:
COM_Invoke(pwb,"execscript", "javascript:document.all[107].value='ahk_test' ")
效果是一样的,所以大家完全可以测试好了js语句或者vbs语句就直接拿来用。
在上面的例子中,方法1是使用的控件的index来获取对象的,方法2是使用的控件的name来获取对象的,注意是Elements不是Element。方法3是通过控件的ID来获取对象的,注意是Element。这三种属性都可以通过iWebBrowser2很方便的获取,其中只有Index属性肯定不为空值,其实两种属性都可能为空,这样便不能使用相应的方法。
熟悉DOM的朋友可以使用别的方式来获取控件的对象,但是最后通过.value属性来设置控件的内容都是一样的。

输入密码
我们再用同样的方法去查看 “密码” 文本框。
image003.png
百度登录页:焦点定位到【密码】输入框。
“密码” 文本框的 index=111 id=normModPsp,且没有name这个属性。
那么我们就不能通过上面的方法2来获取对象了。这里先给出基于index和id操作的js代码。
  • javascript:document.all[111].value="123456" ; void 0
  • javascript:document.getElementById("normModPsp").value="123456" ; void 0
    另外还有一种方法,也是通过id来获取对象的。同样只有IE内核才支持。
  • javascript:document.all.normModPsp.value="123456" ; void 0
这里不再给出ahk代码,如果读者从前面看到这里,应该已经可以自己完成转换了。

记住登录状态
然后操作“记住我的登录状态”这个checkbox。
image005.png
百度登录页:焦点定位到【记住我的登录状态】复选框。
image005.png (5.49 KiB) Viewed 68298 times
Index=128 name=mem_pass id=mem_pass
操作“记住我的登录状态”这个checkbox 的js代码为:
  • javascript:document.all[128].checked=1 ; void 0
  • javascript:document.getElementsByName('mem_pass')[0].checked=1 ; void 0
  • javascript:document.getElementById('mem_pass').checked=1 ; void 0
另外还可以使用click()方法。
  • javascript:document.all[128].click() ; void 0
  • javascript:document.getElementsByName('mem_pass')[0].click() ; void 0
  • javascript:document.getElementById('mem_pass').click() ; void 0
点击登录
最后我们再来点击“登录”按钮。
image007.png
百度登录页:焦点定位到【登录】按钮。
发现只有一个index属性。那么操作代码为:
Javascript:document.all[137].click()
这样就完成了整个登录过程。
iamwyf
Posts: 7
Joined: 02 May 2016, 20:38

Re: 网页自动化初级教程

19 May 2016, 02:04

使用 IE_GetPwbByUrl(hwnd="",url="") 时,提示==>
Call to nonexistent function.
Specifically: ACC_AccessibleObjectFromWindow(A_LoopField)
另外,请问请问哪里可以下载到acc.ahk和com.ahk?
tmplinshi
Posts: 1604
Joined: 01 Oct 2013, 14:57

Re: 网页自动化初级教程

19 May 2016, 21:36

iamwyf wrote:使用 IE_GetPwbByUrl(hwnd="",url="") 时,提示==>
Call to nonexistent function.
Specifically: ACC_AccessibleObjectFromWindow(A_LoopField)
另外,请问请问哪里可以下载到acc.ahk和com.ahk?
IEGetbyURL 测试有效。

Code: Select all

IEGetByURL(URL) {
	For pwb in ComObjCreate("Shell.Application").Windows
		If (pwb.LocationURL = URL and InStr(pwb.FullName, "iexplore.exe"))
			Return pwb
}
iamwyf
Posts: 7
Joined: 02 May 2016, 20:38

Re: 网页自动化初级教程

19 May 2016, 22:25

tmplinshi wrote:
iamwyf wrote:使用 IE_GetPwbByUrl(hwnd="",url="") 时,提示==>
Call to nonexistent function.
Specifically: ACC_AccessibleObjectFromWindow(A_LoopField)
另外,请问请问哪里可以下载到acc.ahk和com.ahk?
IEGetbyURL 测试有效。

Code: Select all

IEGetByURL(URL) {
	For pwb in ComObjCreate("Shell.Application").Windows
		If (pwb.LocationURL = URL and InStr(pwb.FullName, "iexplore.exe"))
			Return pwb
}
十分感谢,测试成功!!!
iamwyf
Posts: 7
Joined: 02 May 2016, 20:38

Re: 网页自动化初级教程

19 May 2016, 22:33

对于下面这个页面,用wingettitle,得到的是“证书错误: 导航已阻止 - Internet Explorer”,但是用iwb2 leaner得到的title和Url相同都是https://10.*.*.*
用ie := IEGet("证书错误: 导航已阻止"),无法获取对象,但是用ie := IEGet("https://10.*.*.*"),确可以获得对象,请问能否修改IEGet(),使得 IEGet("证书错误: 导航已阻止")能够成功?
完整页面代码如下:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML DIR="LTR">
<HEAD>
<link rel="stylesheet" type="text/css" href="ErrorPageTemplate.css" >
<META NAME="MS.LOCALE" CONTENT="ZH-CN">
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
<META HTTP-EQUIV="MSThemeCompatible" CONTENT="Yes">
<TITLE>证书错误: 导航已阻止</TITLE>


</html>
Last edited by iamwyf on 19 May 2016, 23:21, edited 1 time in total.
tmplinshi
Posts: 1604
Joined: 01 Oct 2013, 14:57

Re: 网页自动化初级教程

19 May 2016, 22:56

没有实际URL,不方便测试。我一般用 WBGet() 函数。

Code: Select all

WBGet(WinTitle="ahk_class IEFrame", Svr#=1) {               ;// based on ComObjQuery docs
   static msg := DllCall("RegisterWindowMessage", "str", "WM_HTML_GETOBJECT")
        , IID := "{0002DF05-0000-0000-C000-000000000046}"   ;// IID_IWebBrowserApp
;//     , IID := "{332C4427-26CB-11D0-B483-00C04FD90119}"   ;// IID_IHTMLWindow2
   SendMessage msg, 0, 0, Internet Explorer_Server%Svr#%, %WinTitle%
   if (ErrorLevel != "FAIL") {
      lResult:=ErrorLevel, VarSetCapacity(GUID,16,0)
      if DllCall("ole32\CLSIDFromString", "wstr","{332C4425-26CB-11D0-B483-00C04FD90119}", "ptr",&GUID) >= 0 {
         DllCall("oleacc\ObjectFromLresult", "ptr",lResult, "ptr",&GUID, "ptr",0, "ptr*",pdoc)
         return ComObj(9,ComObjQuery(pdoc,IID,IID),1), ObjRelease(pdoc)
      }
   }
}
iamwyf
Posts: 7
Joined: 02 May 2016, 20:38

Re: 网页自动化初级教程

19 May 2016, 23:24

:superhappy: 太强了,ie := WBGet("证书错误: 导航已阻止 ") 成功!!
Bral
Posts: 20
Joined: 04 Apr 2015, 21:24

Re: 网页自动化初级教程

23 Jun 2018, 02:29

提供一条经验,在 Win 10 中用内嵌 IE 控件到 AHK GUI 中的方法来操作网页,结果发现遇到很多 DOM 操作函数不可用的情况,比如 Document.querySelector 这个命令,经多方查找原因,才发现是因为默认调用的是 IE的兼容模式,即模拟了 IE7,而导致一些命令不支持,解决办法是修改注册表,指定 AHK 中调用的 IE 版本:
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION]
"AutoHotkey.exe"=dword:00002710
xcracked
Posts: 15
Joined: 29 Sep 2018, 22:27

Re: 网页自动化初级教程

30 Sep 2018, 00:08

linpinger的教程看不到了,打不开了,有什么办法看到吗?
tmplinshi
Posts: 1604
Joined: 01 Oct 2013, 14:57

Re: 网页自动化初级教程

30 Sep 2018, 02:23

可以打开啊

Return to “教程资料”

Who is online

Users browsing this forum: No registered users and 27 guests