網頁自動化——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的對象模型
圖片

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">
        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:
圖片

注意:如果更換了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三者的區別可以通過下圖展示出來:
圖片


表單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>

框架已死。

驗證碼圖片處理

 

d39f731e616437ff1a06ac38ef755272


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM