拆取 Web 頁

摘要: 本文討論如何收集來自 Web 的信息,並藉助 Internet Explorer 的可重用分析器組件,將它分佈到其他 Web 頁或數據庫。(打印共 7 頁)

程序員面臨的一個共同任務就是收集 Web 站點的數據,並將它分佈到數據庫或其他 Web 頁。例如,程序員可能需要從氣象站點獲得天氣預報圖,從在線股票經紀人那裏獲得股票報價,以及從新聞站點獲得行業新聞。然後,這些信息被放在一個 Web 頁上,供 CIO、商人或銷售經理使用。或者,也許程序員需要跟蹤歷來的氣象資料,並需要每天將來自氣象站的天氣預報信息存入數據庫。其應用不勝枚舉。

過去,這些選擇相當受限制。現在,通過使用象 WinInet.dll 這樣的 HTTP 組件或許多其他第三方組件,您就可以獲取 Web 頁,並利用幾百種字符串處理功能來獲得網頁中您所感興趣的部分。這一技術已在應用,但很不理想。如果您致力於計算機科學(或者有足夠的時間),就會爲 HTML 創建一個分析器,以標記 Web 頁,然後分析您需要的網頁部分。不過,由於 Internet Explorer 的體系結構中已包含了可重複使用的用分析器,這些都不需要了。

Internet Explorer 不只是一個程序,更是許多可重複使用組件的集合與容器。在拆取 Web 頁時,最有意思的兩個組件是 shdocvw.dllmshtml.dll。第一個組件 shdocvw.dll,包含稱爲 WebBrowser 的 Microsoft(R) ActiveX(R) 控件,它真實地顯示 Web 頁。在運行 Internet Explorer 時,顯示 Web 頁的主窗口就是這樣的控件。第二個組件 mshtml.dll,含有能分析 WebBrowser 控件中所包含文檔的 HTML 分析器。

可能有這種情況,在您的應用程序內部,已經用 WebBrowser 控件來駐留 Web 頁,但仍需要重新創建一個小瀏覽器來啓動 Web 頁的拆取。

  1. 文件菜單上,請單擊新建工程,以創建“標準 EXE”,然後在工程菜單上單擊部件,以添加 Microsoft HTML Object LibraryMicrosoft Internet Controls。(見圖 1。)

    圖 1.

  2. 在工具箱中,可看見 WebBrowser 組件。拖動其中之一,文本框和主窗體上的命令按鈕。將此文本框的 Text 屬性設置爲 “http://moneycentral.msn.com/”,將此命令按鈕的 Caption 屬性設置爲“瀏覽(&B)”。(見圖 2。)

    圖 2.

  3. 雙擊該命令按鈕,然後在事件處理器中放入下列代碼,導航至文本框中命名的 Web 站點:
    Private Sub Command1_Click()    WebBrowser1.Navigate Text1.TextEnd Sub
  4. 保存並運行該程序。試着按瀏覽按鈕,導航到文本框中指定的站點。您已經創建了一個基本的 Web 瀏覽器 — 就其本身而言沒什麼用,甚至沒什麼意義,但它卻是邁向 Web 拆取技術的第一步。

  5. 回到工程中,在代碼窗口中選擇 WebBrowser1 對象,然後選擇 DocumentComplete 的事件處理器。一旦整個 Web 頁下載到此瀏覽器中,即觸發該事件:
    Private Sub WebBrowser1_DocumentComplete_ (ByVal pDisp As Object, URL As Variant)End Sub

    傳遞到該事件中的 URL 就是我們導航所至的位置,它在日後確定瀏覽器所在的頁面時將更爲有用。WebBrowser 控件有一個屬性稱爲 Document(文檔),可將其視爲 IHTMLDocument 來處理:

    Private Sub WebBrowser1_DocumentComplete(_ ByVal pDisp As Object, URL As Variant)    Dim Doc As IHTMLDocument2    Set Doc = WebBrowser1.Document    //下一步:分析該文檔End Sub

    較新的 IHTMLDocument2 具有 IHTMLDocument 中無法使用的特性。可對系統使用 IHTMLDocument 替代老版本的 Internet Explorer,如果您有勇氣的話,甚至可以使用 IHTMLDocument3。補充說明一下,我們假設您已經導航到 Word 文檔或 XML 文檔,而非 HTML 文檔。不要將變量 doc 聲明爲 IHTMLDocument2,可將其聲明爲 Word 的文檔或 XML 的 DOMDocument

    在進行下一步之前,理解 HTML 文檔的結構是非常重要的。和 XML 不一樣,HTML 文檔的組合有一定的自由度。例如,您會遇到未關閉標記的 HTML 文檔。HTML 文檔確實有某種結構。結構好的 HTML 文檔通常具有下列元素:

    <HTML>   <HEAD>       header information like the <TITLE>   </HEAD>   <BODY>       elements like <TABLE> and <A> and <IMG>   </BODY></HTML>

    請注意 HTML 的樹狀結構。標記包含標記又包含標記,如此等等。特別是,每一個標記元素都包含一個 0 到 n 個標記元素的集合。<TABLE> 標記可以包含 <TR> 標記。每個 <TR> 標記可以包含 <TD> 標記,後者又可以包含其他標記如錨或圖像等。

  6. 現在,分析整個 http://moneycentral.msn.com/,並在帶 MSFT 符號的頁填上第二個 <INPUT> 標記。然後,調用此窗體上的提交
    Private Sub WebBrowser1_DocumentComplete(ByVal pDisp As Object, URL As Variant)    Dim doc As IHTMLDocument2    Set doc = WebBrowser1.Document        If URL = _    "http://moneycentral.msn.com/home.asp" Then        '填充帶輸入標記的元素集合        Dim Inputs As IHTMLElementCollection        Set Inputs = doc.All.tags("INPUT")        '選擇第一個輸入標記        Dim Element As IHTMLElement        Set Element = Inputs.Item(1, 1)                '使用正確的界面        Dim InputElement As IHTMLInputElement        Set InputElement = Element        InputElement.Value = Text1.Text                '調用此頁第一個窗體上的提交        doc.Forms.Item(0, 0).submitEnd Sub

    在此您會看到,標記集合如何包含可視爲其特定類型的標記。每一個標記都可用 IHTMLElement 界面表示,或用指定爲該標記類型的界面表示。例如,<TABLE> 標記可用 IHTMLTableElement 或 IHTMLElement 表示。

    標記的集合都包含下列重要的方法和屬性:

    • 長度。可將其理解爲計數,或集合中項目的數量。

    • 項目。用於選擇集合中的特殊元素。“項目”有兩個參數,第二個參數即命名的標記。

    • 標記。將要過濾的元素傳遞給標記。標記 ("A") 將返回集合內所有錨的集合。要想有效地拆取頁,就需要學會使用標記集合。

    現在可能您會問,“爲什麼不直接轉到 http://moneycentral.msn.com/scripts/webquote.dll?ipage=qd&Symbol=msft?”當然是可以的,但這個例子告訴大家如何在更復雜的情況下操縱 HTML 窗體。

    如果您未做進一步的改動即運行該程序,就會注意到它將陷入無休止的循環,沒完沒了地下載同一個頁面。程序不斷地尋找要填充的窗體,並反覆調用 DocumentComplete。要修正這個缺陷,應在 DocumentComplete 中置入一些邏輯,告訴分析器,只有在正確的頁面上才提交窗體。

  7. 接下來,讓我們放入這個邏輯,並引入實際的股票報價。另外,我們不捕獲文本框中的 URL,而是捕獲股票符號:
    Private Sub Command1_Click()    WebBrowser1.Navigate _     "http://moneycentral.msn.com/home.asp"End Sub Private Sub WebBrowser1_DocumentComplete(ByVal pDisp As Object, URL As Variant)    Dim doc As IHTMLDocument2    Set doc = WebBrowser1.Document        If URL = "http://moneycentral.msn.com/home.asp" Then        '填充帶輸入標記的元素集合        Dim Inputs As IHTMLElementCollection        Set Inputs = doc.All.tags("INPUT")        '選擇第一個輸入標記        Dim Element As IHTMLElement        Set Element = Inputs.Item(1, 1)                '使用正確的界面        Dim InputElement As IHTMLInputElement        Set InputElement = Element        InputElement.Value = Text1.Text                '調用該頁第一個窗體上的提交        doc.Forms.Item(0, 0).submit    ElseIf URL = _    "http://moneycentral.msn.com/scripts/webquote.dll?ipage=qd&Symbol=" _                 & Text1.Text Then        Dim Tables As IHTMLElementCollection        Set Tables = doc.All.tags("TABLE")        '獲得第 14 個表的第二個項目(基於 0)        Dim Quote As IHTMLElement        Set Quote = _        Tables.Item(14, 14).All.tags("TD").Item(2, 2)        '顯示開始標記和結束標記之間的文本        MsgBox Quote.innerText    End IfEnd Sub

    圖 3.

    到了這最後一步,自定義的瀏覽器已被轉入有效的 Web 拆取器。重要的是,要注意有了 IHTMLElement 之後獲得文本的可用選項。有 4 個屬性:

    • innerText:開始標記和結束標記之間的文本。

    • innerHTML:開始標記和結束標記之間的文本和 HTML。

    • outerText:對象的文本。

    • outerHTML:對象的文本和 HTML。

    還要注意從 4 個表(基於 0)的 11 個元素中檢索到的最終報價字符串。如果 MoneyCentral? 決定重新調整該頁怎麼辦?您最好的策略是根據合理的假定來查詢頁面。如果您知道報價幾乎總是放在新聞標題的前面,那麼就從新聞標題往回查詢那個表。還有一種策略是,當更改頁面的格式時,有一種簡單的方法來更新分析器。一種方法就是將分析的職能細分爲較小的組件。每個組件可以實現一個預定義的界面,接受要分析的 IHTMLDocument。與實際的 Web 頁失去同步的分析組件可被替換。這樣帶來的好處是,多個編程人員都可以編寫分析器,只需給定要實現的界面和要拆取的 Web 站點即可。

    爲了避免複雜,將 IHTMLDocument 從 DocumentComplete 函數傳遞 COM DLL,後者可以分析 IHTMLDocument 並返回想要的有效負載。這有利於程序的模塊化,並易於更新與 Web 站點失去同步的分析部分。它還使多個開發者能同時處理這個項目,因爲他們有一個乾淨的界面來編寫分析器。

在把新的程序推向市場以前,還有幾個實際問題要考慮。首先,很可能 MoneyCentral 和其他許多站點不願意別人下載他們的內容,也不喜歡看廣告。您可能得與摘取其內容的站點簽訂一份協議。

還有很重要的一點要注意,即如果您是 Web 站點的操作員,那麼還有更好的辦法將您的內容提供給其他系統。雖然可以讓其他人來拆取您的 Web 頁,但這仍很笨拙。還有一個更好的方法是,提供 XML 來表現內容。並且,隨着 XML 被廣泛採用,Web 站點開始提供其數據的 XML 表現形式以及 HTML 界面,也不值得大驚小怪。在這樣的時刻到來之前,您也許還得拆取 Web 頁。Web 頁的拆取往往失之笨拙,但 Microsoft HTML 分析器可令其稍微好一些。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章