本文展示一個經典的 VB6 應用程式,透過 WebBrowser 控制項瀏覽中央氣象局網站,解析 HTML 取得各縣市鄉鎮的天氣預報資料,並下載天氣圖示顯示於介面上。雖然 VB6 已停止支援,但其 HTTP 抓取、HTML 解析、二進位下載、UI 綁定的完整流程,對理解早期 Web 爬蟲架構仍有參考價值。
Weather 型別儲存地點、日期、圖片路徑、天氣描述、風向、未來 10 筆細節。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
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, " ", " ")
todayTime(0).Caption = Replace$(Weatherday(index).strDate, " ", " ")
TodayTP(0).Caption = Replace$(Weatherday(index).strWeather, " ", " ")
TodayTP(1).Caption = Replace$(Weatherday(index).strWind, " ", "")
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 記錄 |
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 範例完整呈現了「瀏覽→解析→下載→顯示」的爬蟲閉環,雖技術棧已過時,但其事件驅動流程、狀態機設計、資料綁定邏輯在現代非同步架構中依然映射得上。重構時建議:
HttpClient + HtmlAgilityPack / AngleSharp。