⽹页⾃动化——VBA和InternetExplorer.Application
⽹页⾃动化——VBA和InternetExplorer.Application
VBA⾃动化⽹页的多种⽅式
其实并不知道有多少种⽅式,下⾯随便罗列了⼀些:
1.WebBrower⽅式
2.InternetExplorer.Application⽅式,需要引⼊接⼝:'在VBA编辑器窗⼝依次点击⼯具==引⽤勾选Microsoft  Internet  Controls 确定,再运
⾏,OK!
3.XMLHTTP 学习资料如下:
链接已死!
4.
InternetExplorer.Application⽅式
创建InternetExplorer.Application
Set ie = CreateObject("internetexplorer.application")
ie.Visible = True
连接InternetExplorer.Application
如果能直接链接到已经打开⾄特定⽹页的浏览器,这就可以省略掉许多如登录等⾮重复⼯作的编码⼯作,但愿如此。
1. 或许可使⽤此函数GetObject实现(似乎实现不了)
set ie = GetObject(“”, “InternetExplorer.Application”)
这条语句并不会链接到已经打开的IE上,⽽是重新打开⼀个IE,更坑的是,它还是隐藏的,是个空⽩页。
2.Win32 API⽅式
Function FindWin(ByVal strRef As String) As Object
'寻已打开的、以strRef为开头⽹址的⽹页
Dim objWin As Object
For Each objWin In CreateObject("Shell.Application").Windows
Do adyState <> 4 Or objWin.Busy
DoEvents
Loop
If LCase(TypeName(objWin.document)) = "htmldocument" Then
If objWin.LocationURL Like strRef & "*" Then
Set FindWin = objWin
Exit For
End If
End If
Next
Set objWin = Nothing
End Function
3.未知原理⽅式,简洁有效
1. 注意的是,此种情况下IE不具有焦点,可以⽤如下语句将其设为活动窗⼝:
SetForegroundWindow(IE.HWND)
此时由于IE为活动窗⼝,将其上的控件设为具有焦点后,则可接受按键信息
item.focus
SendKeys "{enter}"
点连接出现新选项卡的处理
InternetExplorer.Application中没有选择选项卡的功能,或许可以⽤GetObject功能来获得新选项卡中的⽂档?未知。
另⼀个⽅式:在点击前,改变<link 中的target值为_SELF,让它在当前窗⼝当前选项卡中打开,处理完毕后返回历史记录获得之前的ie⽂档。待
另⼀个⽅式:在点击前,改变<link 中的target值为_SELF,让它在当前窗⼝当前选项卡中打开,处理完毕后返回历史记录获得之前的ie⽂档。待证实
事件驱动
要利⽤事件驱动,必须有WithEvent语句,⽽此语句不能⽤在通⽤模块中,只能⽤在窗体模块或类模块中。
DimWithEvents ie As SHDocVw.InternetExplorer
Private Subie_NavigateComplete2(ByVal pDisp As Object, URL As Variant)
pDisp.Script "window.alert=functionmyalert(msg){};"
End Sub
待验证
页⾯加载完成判断和框架页⾯加载完成判断
⽅法⼀:
Do Until ie.ReadyState = READYSTATE_COMPLETE And ie.busy = False
DoEvents
Loop
其中READYSTATE_COMPLETE的值为4.
document亦具有readystate状态,其值为四种字符串,感兴趣的当为”complete”。
⽅法⼆:NavigateComplete2事件判断。
⽅法三:页⾯特殊字眼判断。
时间等待
⽅法⼀:
t1 = Timer
Do Until Timer > t1 + 5 '需要时间触发⽹页上的onblur函数
DoEvents
Loop
⽅法⼆:
在VBA中使⽤Sleep函数,需要添加:
Private Declare Sub Sleep Lib "kernel32" (ByValdwMilliseconds As Long)
'  Sleep (53000)
⽅法三:
'如下,可以暫停10秒.实现类似于Sleep函数的功能
'newHour = Hour(Now())
'newMinute = Minute(Now())
'newSecond = Second(Now()) + 10
'waitTime = TimeSerial(newHour, newMinute, newSecond)
'Application.Wait waitTime
处理Alert等弹出式窗⼝
⽅法⼀:
利⽤事件驱动⽅式将相关函数预设为空函数。待证实
DimWithEvents ie As SHDocVw.InternetExplorer
'Private Subie_NavigateComplete2(ByVal pDisp As Object, URL As Variant)
'pDisp.Script "window.alert=null;"
'pDisp.Script "firm=null;"
'pDisp.Script "firm=null;"
'pDisp.Script "window.showModalDialog=null;"
'pDisp.Script "window.open=null;"
INTERNET EXPLORER 无法打开'End Sub
'
⽅法⼆:
原理和上⾯的相似,但不需要⽤到事件驱动⽅式。待证实,可能不适合动态产⽣的信息窗⼝
Set objscr = .ateElement_x("script") '创建⼀个脚本元素
objscr.Text = "firm=function(x){return true;};" 'true是点击“确定”,false是点击“取消”
.Document.body.appendChild objscr '将脚本元素添加到body⾥
.
⽅法三:
感觉此⽅法与InternetExplorer.Application不协调,但是我唯⼀成功使⽤过的⽅法。这种⽅法应该算是软件⾃动化的⼀个基础,例如编写游戏外挂。
到弹出窗⼝的窗⼝句柄,并向其上的按钮发送单击事件从⽽关闭窗⼝。已证实可⽤,可应付动态产⽣的信息窗⼝
MicrosoftSpy++:⼯具,⽤于取得窗⼝类名、名称,控件类名、名称和WM信息等。
FindWindow:Win32 API函数,功能为取得窗⼝句柄
FindWindowEx: Win32 API函数,功能为取得窗⼝中控件的句柄
SendMessage: Win32 API函数,发送WM信息
声明部分:
Private Declare PtrSafe Function FindWindowEx Lib"user32" Alias "FindWindowExA" (ByVal hWnd1 A
s Long, ByValhWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As Any) As Long 'API抓窗⼝函数
Private Declare PtrSafe Function GetWindowText Lib"user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVallpString As String, ByVal cch As Long) As Long 'api取窗⼝⽂本函数
Private Declare PtrSafe Function FindWindow Lib"user32" Alias "FindWindowA" (ByVal lpClassName As String,ByVal lpWindowName As String) As Long
Private Declare PtrSafe Function SendMessage Lib"user32" Alias "SendMessageA" (ByVal hwnd As Long, ByValwMsg As Long, ByVal
wParam As Long, lParam As Any) As Long
Public Const WM_LBUTTONDOWN = &H201
Public Const WM_LBUTTONUP = &H202
Public Const MK_LBUTTON = &H1
执⾏语句部分:
Do Until FindWindow("#32770", "来⾃⽹页的消息") >0
DoEvents
Loop
hwd = FindWindow("#32770", "来⾃⽹页的消息")  '⽹页对话框的句柄
Do Until FindWindowEx(hwd, 0, "Button", "确定") > 0
DoEvents
Loop
hwd_child = FindWindowEx(hwd, 0, "Button", "确定") '保存按钮的句柄
SendMessage hwd_child, BM_CLICK, 0, 0 '发送⿏标单击      ‘这⼀句似乎不能起作⽤,下⾯两句可以完成点击功能
SendMessage hwd_child, WM_LBUTTONDOWN, 0, ByVal0              '点击“确定”按钮(按下左键)
SendMessage hwd_child, WM_LBUTTONUP, 0, ByVal0                '点击“确定”按钮(松开左键)
SendMessage hwd_child, WM_LBUTTONUP, 0, ByVal0                '点击“确定”按钮(松开左键)
注意:由于⽹页和程序是异步的,所以要防⽌弹出窗⼝还没准备好,⽽执⾏语句已经到达,故上⾯层层检查弹出窗⼝是否已经准备好,最好在发送WM信息前再延时1秒,已防意外。
动态加载页⾯的处理
本条内容待证实。
⽹页脚本中,加⼊的js类的代码,该代码的作⽤是动态加载⽹页内容,这⾥的动态是指,当⿏标或者滚动条滚动到此处时,才会⾃动加载⽹页内容,否则⽹页始终不加载,所以程序就陷⼊了⽆限循环,这个解决⽅法就是模拟滚动条滚动到需要加载内容的区域。
这涉及到两个内容:
第⼀个⽹页元素在浏览器页⾯中的定位⽅法;
元素对象相对于⽬前浏览器顶部位置的像素距离:BoundingClientRect().top
元素对象相对于⽬前浏览器左侧位置的像素距离:BoundingClientRect().left
第⼆个滚动条控制⽅法;
Document.parentWindow.scrollBy X,Y(⼀般x为0,Y为top值)
所以,完整答案为:
⽤框架⾥⾯或者链接加载完毕后⾥⾯的代码,这个代码要能够跟主页⾯代码有所区别,就是说主页⾯⾥⾯没有的代码,然后通过在主页⾯代码⾥⾯查框架或链接⾥⾯独特代码是否存在的形式,来完成页⾯是否加载的判断,具体代码为:
Do WhileInStr(主页⾯代码, "框架某⼀独特代码") <=1
DoEvents
Loop
DOM
1.HTML DOM的对象模型
2.⽂档树
元素与节点,ID与name
在HTMLDOM中,⽂档的每⼀部分都是节点,整个⽂档被定义为⼀个⽂档节点,每个标签是⼀个元素节点,包含在元素中的⽂本是⽂本节点,每⼀个元素的属性是⼀个属性节点。
⽹页⽂档,可以说是由元素组合⽽成的,也可以说是由节点连接⽽成的树构造的。节点是⽂档树结构中特有的名词,元素是节点,但是节点不⼀定是元素,节点还有⽂档节点、⽂本节点、属性节点等;元素是元素节点的扩展,元素可以拥有属性还有⽂本。
可⼤致理解为,同⼀个html dom对象,提供的两个不同接⼝。
元素集合
引⽤:集合(0)
长度: 集合.length
元素的引⽤⽅式
1.直接调⽤
对象
描述
Document
代表整个 HTML ⽂档,可被⽤来访问页⾯中的所有元素
Anchors
代表 <a> 元素集合
Body
代表 <body> 元素
Forms
代表 <form> 元素集合
Frames
代表 <frame> 元素或<iframe> 元素集合
Images
代表 <img> 元素集合
Links
代表 <link> 元素集合
Options
代表 <option> 元素集合(select元素⾥⾯可以直接使⽤)
Cells
代表 <td> 元素集合(table元素⾥⾯可以直接使⽤)
Rows
代表 <tr> 元素集合(table元素⾥⾯可以直接使⽤)
All
对象集合,提供对⽂档中所有 HTML 元素的访问。
2.函数调⽤
getElementById(“元素的id属性”)或all(“元素的id属性”):返回拥有指定id的元素;
getElementsByName(“元素的name属性”)或all(“元素的name属性”):返回拥有指定名称的元素的集合;
getElementsByTagName_r(“标签名称”)或all.tags(“标签名称”):返回该类标签的元素集合;
all(索引号)循环与InStr字符串查结合;
getElementsByClassName(“class”)(n) 此函数可能没有实现,请参见getElementsByClassName。
3.树型结点查
l⽗结点:parentNode
l⼦结点:childNodes (children, 在IE9、IE10模式下,可能要⽤此属性,可参见下⼀条内容:getElementsByClassName);
lnodeName(节点名称):元素节点的名称为其标签名,属性节点的名称为其属性名称;
lnodeValue(节点值):⽂本节点的值为其包含的⽂本,属性节点的值为其包含的属性值;
lnodeType(节点类型):元素节点为1、属性节点为2、⽂本节点为3、注释节点为8、⽂档节点为9
4.树型元素查
l⽗元素:parentElement
l⼦元素集合:children,然后通过判断标签名称(tagname),值(value),内含⽂本(innertext)等⽅式来进⾏查
l兄弟元素:nextSibling、previousSibling
getElementsByClassName(“classname”)
以下内容未知。
⽬前这⼀⽅法IE9 IE10⽀持,返回的是⼀个对象集合,但是如果你的浏览器本⾝是IE9或者IE10,如果你⽤excel调⼊插件webbrowser插件,你可能仍然⽆法使⽤这⼀⽅法,但是可以解决。
1、如果你的浏览器本⾝IE9以下,那么如果还想⽤这种⽅法,就⾃⼰编辑⼀个函数,有点问题,这个问题就是如果你是IE9或者IE10,你是可以使⽤这个⽅法的,但是需要修改注册表。
因为IE浏览器不⽀持getElementsByClassName,所以你要⾃⼰写⼀个⽅法得到class
但是⽕狐浏览器知道getElementsByClassName,可以直接的⽤
<html>
<head>
<title></title>
<script type="text/javascript">