网页自动化——VBA和InternetExplorer.Application

网页自动化——VBA和InternetExplorer.Application

转载:http://www.360doc.com/content/18/0223/17/52075843_731762749.shtml

 
 

 

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

   ie.Navigate "http://www.baidu.com/"

连接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 While objWin.readyState <> 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.未知原理方式,简洁有效

'引用:
'Library SHDocVw
'    C:\WINDOWS\system32\SHDOCVW.dll
'    Microsoft Internet Controls
Sub Inputall()
    Dim mShellwindows As New ShellWindows
    Dim IE As InternetExplorer
   
    For Each IE In mShellwindows
        If IE.LocationURL Like "http://mail.126.com*" Then Exit For
    Next
   
    With IE.document
        .all("USER").Value = "ABCD"
        .all("PASSWORD").Value = 1234
        .all("enter.x").Click
        Do While IE.Busy
            DoEvents
        Loop
    End With
End Sub

  1. 注意的是,此种情况下IE不具有焦点,可以用如下语句将其设为活动窗口:

SetForegroundWindow(IE.HWND)

此时由于IE为活动窗口,将其上的控件设为具有焦点后,则可接受按键信息

item.focus

SendKeys "{enter}"

点连接出现新选项卡的处理

InternetExplorer.Application中没有选择选项卡的功能,或许可以用GetObject功能来获得新选项卡中的文档?未知。

另一个方式:在点击前,改变<link 中的target值为_SELF,让它在当前窗口当前选项卡中打开,处理完毕后返回历史记录获得之前的ie文档。待证实

事件驱动

要利用事件驱动,必须有WithEvent语句,而此语句不能用在通用模块中,只能用在窗体模块或类模块中。

DimWithEvents ie As SHDocVw.InternetExplorer

Private Subie_NavigateComplete2(ByVal pDisp As Object, URL As Variant)

   pDisp.Document.parentWindow.execScript "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.Document.parentWindow.execScript "window.alert=null;"

'pDisp.Document.parentWindow.execScript "window.confirm=null;"

'pDisp.Document.parentWindow.execScript "window.showModalDialog=null;"

'pDisp.Document.parentWindow.execScript "window.open=null;"

'End Sub

'

方法二:

原理和上面的相似,但不需要用到事件驱动方式。待证实,可能不适合动态产生的信息窗口

   Set objscr = .Document.createElement_x("script") '创建一个脚本元素

   objscr.Text = "window.confirm=function(x){return true;};" 'true是点击“确定”,false是点击“取消”

.Document.body.appendChild objscr '将脚本元素添加到body里

.document.getElementByIdx_x("submit").Click ‘会产生弹出窗口的执行语句

方法三:

感觉此方法与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 As 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                '点击“确定”按钮(松开左键)

注意:由于网页和程序是异步的,所以要防止弹出窗口还没准备好,而执行语句已经到达,故上面层层检查弹出窗口是否已经准备好,最好在发送WM信息前再延时1秒,已防意外。

动态加载页面的处理

本条内容待证实。

网页脚本中,加入的js类的代码,该代码的作用是动态加载网页内容,这里的动态是指,当鼠标或者滚动条滚动到此处时,才会自动加载网页内容,否则网页始终不加载,所以程序就陷入了无限循环,这个解决方法就是模拟滚动条滚动到需要加载内容的区域。

这涉及到两个内容:

第一个网页元素在浏览器页面中的定位方法;

元素对象相对于目前浏览器顶部位置的像素距离:object.getBoundingClientRect().top

元素对象相对于目前浏览器左侧位置的像素距离:object.getBoundingClientRect().left

第二个滚动条控制方法;

     Document.parentWindow.scrollBy X,Y(一般x为0,Y为top值)

所以,完整答案为:

用框架里面或者链接加载完毕后里面的代码,这个代码要能够跟主页面代码有所区别,就是说主页面里面没有的代码,然后通过在主页面代码里面查找框架或链接里面独特代码是否存在的形式,来完成页面是否加载的判断,具体代码为:

Do WhileInStr(主页面代码, "框架某一独特代码") <=1

DoEvents

Loop

DOM

1.HTML DOM的对象模型
网页自动化——VBA和InternetExplorer.Application

2.文档树
网页自动化——VBA和InternetExplorer.Application

元素与节点,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">
        window.onload = function () {
var tagName = getClass("div","a1");

//因为返回的是包含多个元素的数组,所以要遍历一下
for (var i = 0; i< tagName.length; i++) {

                tagName[i].innerHTML= "你好";
            }
var tagName = getClass("div","a2");
for (var i = 0; i< tagName.length; i++) {
                tagName[i].innerHTML= "ALL好";
            }
        }

function getClass(tagname, className){ //tagname指元素,classNameclass的值

//判断浏览器是否支持getElementsByClassName,如果支持就直接的用
if (document.getElementsByClassName){  

return getElementsByClassName(className);
            }
else {    //当浏览器不支持getElementsByClassName的时候用下面的方法
var tagname =document.getElementsByTagName_r(tagname);  //获取指定元素
var tagnameAll = [];     //这个数组用于存储所有符合条件的元素
for (var i = 0; i< tagname.length; i++) {     //遍历获得的元素
                    if(tagname[i].className == className) {     //如果获得的元素中的class的值等于指定的类名,就赋值给tagnameAll
                        tagnameAll[tagnameAll.length]= tagname[i];
                    }
                }
return tagnameAll;
            }
        }
    </script>
</head>
<body>
<div class="a1"></div>
<div class="a1"></div>
<div class="a1"></div>
<div class="a1"></div>
<div class="a2"></div>
<div class="a2"></div>
<div class="a2"></div>
<div class="a2"></div>
</body>
</html>

2、如果你的浏览器是IE9或者IE10,根据微软介绍,通常使用的webbrowser插件的版本是IE7,所以你需要修改注册表,让他默认的webbrowser用IE9或者IE10.

浏览器内核检测地址:http://se.360.cn/v5/iecoretest.html

There are two different sets of keys for 32 bit and 64bit applications.
32 bit: 
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\InternetExplorer\MAIN\FeatureControl\FEATURE_BROWSER_EMULATION
Value Key: yourapplication.exe
64 bit: 
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\InternetExplorer\MAIN\FeatureControl\FEATURE_BROWSER_EMULATION
Value Key: yourapplication.exe
The value to set this key to is (taken from MSDN here) as decimal values:
网页自动化——VBA和InternetExplorer.Application

注意:如果更换了webbrowser用的基础IE版本,如果换了电脑,由于对方的IE版本可能不同,会引起一些列问题,需要注意。
目前发现:

·excel2013,在插入webbrowser控件存在问题,无法插入,可能需要修改注册表等,具体解决方案暂没有看到。

·childnodes在IE9 IE10下,存在问题,需要用children来代替;

·getBoundingClientRect()方法在IE7下可以用getBoundingClientRect().bottom(right/top),但是IE9 10就需要加入元素名称getBoundingClientRect("id").bottom,才不会弹出错误。

innerHTML,outerHTML,innerText,outerText的区别

innerHTML 设置或获取位于对象起始和结束标签内的 HTML

outerHTML 设置或获取对象及其内容的 HTML 形式

innerText 设置或获取位于对象起始和结束标签内的文本

outerText 设置(包括标签)或获取(不包括标签)对象的文本

innerText和outerText在获取时是相同效果,但在设置时,innerText仅设置标签内的文本,而outerText设置包括标签在内的文本。

简单的说innerHTML和outerHTML、innerText与outerText的不同之处在于:

1)、innerHTML与outerHTML在设置对象的内容时包含的HTML会被解析,而innerText与outerText则不会。

2)、在设置时,innerHTML与innerText仅设置标签内的文本,而outerHTML与outerText设置包括标签在内的文本。

对于一个id为"testdiv"的div来说,outerHTML、innerHTML以及innerTEXT三者的区别可以通过下图展示出来:
网页自动化——VBA和InternetExplorer.Application


表单form的处理

表单form对象,有一个方法比较重要,就是submit,这个方法提供了表单的提交的动作。如果我们捕捉页面的提交按钮非常困难时,有时候只要对表单,执行submit方法,表单也是可以提交的,不需去点击提交按钮。

表单控件,文本输入类控件,最常用就是value的属性了,通过这个属性,可以往文本框里面添加文本。

单选框、复选框,常用的就是checked属性了,如果为true就是被选中了,或者直接使用click方法也行。

下拉列表呢,可以通过select对象的selectedIndex属性去设置选中项,也可以通过其内含对象集合options(),设置某个options(x)的selected属性为true,来设置选中项。

表格table的处理

Table对象.rows(0).cells(0)

每个单元格的innertext属性即可获取单元格的文本

框架frame和iframe

Frame和iframe元素,均体现在frames对象集合里面,其最重要的属性就是contentDocument,也就是获取框架内的页面文档。

页面内容加载完毕,不代表框架页面内容加载完毕,故判断此点是一个麻烦事。

document的属性frames仅支持到IE8,其后的IE只能通过getElementsByTagName_r(“frames”)来获得。

fireevent

fireevent主要用于,有的表单的校验机制非常强,需要光标聚焦了,文本change了等等,才能提交表单,这些事件的模拟只能靠fireevent了,其他方法就很难替代了。

dmt.body.FireEvent"onclick" '触发body的点击事件

InternetExplorer.Application完整列表

http://user.qzone.qq.com/22235949/blog/1374319276

HTML简介

整体框架

<html>

   <head> <!--注释:文档头部,文档相关消息,并不提供文档内容-->

             <title> 网页标题</title>

      </head>

      <body> <!--注释:文档主体-->

网页文档主体

      </body>

</html>

布局 <div> <span>

段落<p>

超链接<a>

<a href=”跳转的URL” target=”_blank/_self”>显示的超链接文本</a>

图像<img>

<img src=”url” alt=”文本”>

表格<table>

<tableborder="1"> <!--注释:border设置表格边框样式-->

      <tr>

             <td>第一行第一个单元格</td>

             <td>第一行第二个单元格</td>

      </tr>

      <tr>

             <td>第二行第一个单元格</td>

             <td>第二行第二个单元格</td>

      </tr>

</table>

列表<ol><ul><dl>

1.有序列表 <ol> <li>

2.元序列表 <ul> <li>

3.自定义列表 <dl> <dt> <dd>

表单和控件<form>

表单form这个元素,有“method”和“action”两个属性,action属性指定的就是,提交表单后,向这个属性指定URL发送http请求(呵呵,涉及到第一节课的知识啦),method这个属性设定的就是,要按照get或者post等方式发送http请求。

1.<input>

<inputtype=类型 name=元素名称 id=元素id value=元素值/>

其类型由type属性定义,常见的有:text(文本框)、Radio(单选按钮)、Checkboxes(复选框)、submit(提交按钮)、hidden(隐藏)、reset(重置)和password(密码框)等。

2.<select>

<selectmultiple="multiple" name=名称 size=显示菜单条目数>

如果存在multiple="multiple"的属性设定,则允许菜单多选,否则单选。Size是设置可见的菜单条目数。其下级元素,option代表的是其每个菜单项目,语法为:

<optionvalue=值selected="selected">显示文字</option>

框架<frame>、<iframe>

框架已死。

验证码图片处理

 

网页自动化——VBA和InternetExplorer.Application

上一篇:Android R 新特性变化,2021Android笔试真题


下一篇:前端浏览器兼容性问题整理