首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

VB6 爬蟲實戰:從氣象局網站抓取天氣預報資料

     編輯:關於C++

本文展示一個經典的 VB6 應用程式,透過 WebBrowser 控制項瀏覽中央氣象局網站,解析 HTML 取得各縣市鄉鎮的天氣預報資料,並下載天氣圖示顯示於介面上。雖然 VB6 已停止支援,但其 HTTP 抓取、HTML 解析、二進位下載、UI 綁定的完整流程,對理解早期 Web 爬蟲架構仍有參考價值。

程式架構概覽

  • 資料結構:Weather 型別儲存地點、日期、圖片路徑、天氣描述、風向、未來 10 筆細節。
  • UI 流程:Combo1 選縣市 → Combo2 顯示鄉鎮 → 按鈕觸發 WebBrowser 導向查詢網址 → DownloadComplete 事件解析 HTML → 顯示資料與圖片。
  • 核心技術:字串擷取(InStr/Mid$)、Inet 控制項下載圖片、WebBrowser 事件驅動。

關鍵程式碼片段

資料結構定義

Private Type Weather
    strAdd As String      ' 地點名稱
    strDate As String     ' 日期
    strPicPath As String  ' 圖片 URL
    strWeather As String  ' 天氣描述
    strWind As String     ' 風向
    strSM(10) As String   ' 未來細節陣列
End Type

Public Weatherday(2) As Weather ' 三天預報

縣市/鄉鎮兩級下拉選單聯動

Private Sub Combo1_Click()
    Combo2.Clear
    Select Case Combo1.Text
        Case "台北市": Combo2.AddItem "台北"
        Case "台中市": Combo2.AddItem "台中"
        Case "高雄市": Combo2.AddItem "高雄"
        ' ... 其餘 300+ 行各縣市鄉鎮硬編碼 ...
    End Select
    Combo2.ListIndex = 0
End Sub

現代化建議:將縣市/鄉鎮對應表存為 JSON/資料庫,啟動時動態載入,避免硬編碼維護惡夢。

觸發查詢與導向

Private Sub Command1_Click()
    If Combo2.Text = "" Then
        MsgBox "請選擇城市!", vbOKOnly + vbInformation, "提示"
        Exit Sub
    End If
    strHTML = ""
    lblTitle.Caption = Combo2.Text & "天氣"
    StaFlag = 0
    WebBrowser1.Navigate "https://php.weather.sina.com.cn/search.php?city=" & Combo2.Text
    Label1.Caption = "請 稍 後 …"
End Sub

HTML 解析核心(DownloadComplete 事件)

Private Sub WebBrowser1_DownloadComplete()
    On Error Resume Next
    If Len(strHTML) = 0 Then
        strHTML = WebBrowser1.Document.documentElement.innerHTML
        If Len(strHTML) <> 0 Then
            For j = 0 To 2 ' 三天
                i = InStr(strHTML, "<DIV class=City_Data>")
                strHTML = Mid$(strHTML, i)
                Weatherday(j).strAdd = GetData("<H3>", "</H3>", strHTML)
                Weatherday(j).strDate = GetData("<P>", "</P>", strHTML)
                Weatherday(j).strPicPath = GetData("src=" & Chr$(34), Chr$(34) & "></DIV>", strHTML)
                Weatherday(j).strWeather = GetData("Weather_TP>", "</DIV>", strHTML)
                Weatherday(j).strWind = GetData("Weather_W>", "</DIV>", strHTML)
                i = InStr(strHTML, "<DIV class=Weather_SM")
                strHTML = Mid$(strHTML, i)
                intTemp = IIf(j = 0, 9, 5)
                For k = 0 To intTemp
                    Weatherday(j).strSM(k) = GetData("<P>", "</P>", strHTML)
                Next
            Next
            Call DisPlayData(StaFlag)
            Label1.Caption = "下載完成"
        End If
    End If
End Sub

通用字串擷取函式

Public Function GetData(StartFlag As String, EndFlag As String, strSource As String) As String
    Dim lngStart As Long, lngEnd As Long, strTemp As String
    lngStart = InStr(1, strSource, StartFlag)
    lngEnd = InStr(lngStart, strSource, EndFlag)
    strTemp = Mid(strSource, lngStart + Len(StartFlag), lngEnd - lngStart - Len(StartFlag))
    strSource = Mid(strSource, lngEnd + Len(EndFlag)) ' 修正:原碼未更新 strSource 導致後續擷取錯誤
    GetData = strTemp
End Function

圖片二進位下載

Private Function DownBinData(ByVal sURL As String) As Boolean
    On Error GoTo ExitHead
    Dim m_vBinData() As Byte
    m_vBinData = Inet1.OpenURL(sURL, icByteArray)
    DoEvents
    If UBound(m_vBinData) <> 0 Then DoEvents
    If Inet1.StillExecuting Then DoEvents: GoTo EntryBegin
    DownBinData = True
    If Dir(App.Path & "\imag.gif") <> "" Then Kill App.Path & "\imag.gif"
    Open App.Path & "\imag.gif" For Binary As #1
    Put #1, 1, m_vBinData
    Close #1
    Exit Function
ExitHead:
    DownBinData = False
End Function

資料顯示與圖片載入

Public Sub DisPlayData(index As Byte)
    On Error GoTo ToExit
    Frame1(0).Caption = Replace$(Weatherday(index).strAdd, "&nbsp;", " ")
    todayTime(0).Caption = Replace$(Weatherday(index).strDate, "&nbsp;", " ")
    TodayTP(0).Caption = Replace$(Weatherday(index).strWeather, "&nbsp;", " ")
    TodayTP(1).Caption = Replace$(Weatherday(index).strWind, "&nbsp;", "")
    For i = 0 To 9
        TodayTP(i + 2).Caption = Mid$(Replace$(Weatherday(index).strSM(i), "</SPAN>", ""), 7)
    Next
    Call DownBinData(Weatherday(index).strPicPath)
    DoEvents
    Image1.Picture = LoadPicture(App.Path & "\imag.gif")
    ' 輪播下一筆
    index = index + 1: If index >= 3 Then index = 0
ToExit:
End Sub

技術債與現代化重構方向

問題影響現代替代方案
硬編碼 300+ 行縣市鄉鎮對應維護極難、擴充性零JSON/資料庫 + 動態載入
字串解析 HTML(InStr/Mid$)網頁結構微調即失效、無法處理巢狀/屬性變化HTML Agility Pack / AngleSharp / 正規表示式
WebBrowser 控制項(IE 內核)相容性差、安全性低、已淘汰HttpClient + HTML 解析器 / Headless Chrome (Puppeteer/Playwright)
Inet 控制項下載圖片僅支援 HTTP/1.0、無非同步、錯誤處理弱HttpClient / WebClient / WinHTTP
同步阻塞 UI、DoEvents 處理重入介面凍結、重入 Bug 難除錯async/await、Task、非同步模式
錯誤處理僅 On Error Resume Next吞沒例外、無日誌、難除錯結構化例外處理、Serilog/NLog 記錄

現代 C#/.NET 6 重構骨架

public record WeatherInfo(
    string Location, string Date, string ImageUrl, 
    string Condition, string Wind, string[] Details);

public class WeatherService {
    private readonly HttpClient _http = new();
    private readonly HtmlDocument _doc = new(); // HtmlAgilityPack
    
    public async Task<WeatherInfo[]> GetForecastAsync(string city) {
        var html = await _http.GetStringAsync($"https://api.weather.gov/gridpoints/{city}/forecast");
        // 若無官方 API,改用 HtmlAgilityPack 解析網頁
        return ParseHtml(html);
    }
    
    private WeatherInfo[] ParseHtml(string html) {
        _doc.LoadHtml(html);
        // 使用 XPath/CSS Selector 穩健擷取
        return _doc.DocumentNode.SelectNodes("//div[@class='City_Data']")
            .Select(node => new WeatherInfo(...)).ToArray();
    }
}

總結

此 VB6 範例完整呈現了「瀏覽→解析→下載→顯示」的爬蟲閉環,雖技術棧已過時,但其事件驅動流程、狀態機設計、資料綁定邏輯在現代非同步架構中依然映射得上。重構時建議:

  1. 採用官方開放 API(如中央氣象署 OpenData)優於網頁爬蟲。
  2. 若必須爬蟲,使用 HttpClient + HtmlAgilityPack / AngleSharp。
  3. 全面非同步、結構化錯誤處理、單元測試覆蓋解析邏輯。
  4. 資料與 UI 分離(MVVM/Blazor/Razor Pages),避免程式碼耦合在 Form 中。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved