C# 爬取靜態網頁入門
目錄
爬蟲分為兩種,靜態網頁爬蟲和動態網頁爬蟲,相比較於動態網頁爬蟲而言很簡單,靜態網頁的爬取不需要執行如JavaScript類似的程式碼,只需要獲取頁面Html程式碼,並解析目標內容即可,本文介紹了靜態網頁爬取的基本流程。
確定目標內容和目標站點
明確需求,比如本文中需要爬取北京過去一段時間內的所有天氣,首先找一個合適的網站,比如http://www.tianqihoubao.com,在該網站中,可以找到北京歷史天氣的站點http://www.tianqihoubao.com/lishi/beijing.html
分析目標站點結構
在瀏覽器中開啟北京歷史天氣站點後,不能直接獲得天氣,而是獲得了許多超連結,其中有指向不同時間段的天氣連結,因此,需要解析這個頁面以分析出目標連結。
目標站點中有兩類連結,一類是目標連結,另一類是其他連結。接下來在瀏覽器中按F12檢視網頁的原始碼,檢查目標連結的特點,這些特點有可能是Html節點或者Html屬性,總之需要找到一個特點來區分目標連結和其他連結。
Html程式碼中,可以看到連結的兩個區別
- 兩種連結的節點層次是不一樣的,目標連結中有div#content 其他連結中沒有,因此可以根據節點的不同來選取連結,即選取有id屬性值為content的節點;
- 最後的<a>節點中屬性href的取值是不同的,目標連結總是含有"month",而其他連結中沒有,因此可以根據最後一個節點的屬性href的值含有"month"來選取連結。
網頁獲取
位於System.Net空間下的WebClient可以方便地獲取網頁,主要程式碼如下
public static string GetHtml(string url) { string res = ""; WebClient client = new WebClient(); Stream stream = client.OpenRead(url); StreamReader sr = new StreamReader(stream, Encoding.Default); res = sr.ReadToEnd(); sr.Close(); client.Dispose(); return res; }
網頁節點解析
這裡有一個大名鼎鼎的庫HtmlAgilityPack來輔助我們將字串的網頁html程式碼生成Dom樹,並且讓我們可以快速方便選取Dom樹的節點,以完成在上節中的思路。VS開啟工具->NuGet包管理器->管理解決方案的Nuget包,從這裡可以搜尋HtmlAgilityPack包進行相應的安裝。在使用這個庫時,需要引入HtmlAgilityPack名稱空間。
using HtmlAgilityPack;
接下來,採取上節中的第二種思路來解析出目標連結。
- 選擇Dom樹中所有含有href屬性的<a>節點,這會把所有超連結的節點都選擇出來,包括目標連結和其他連結;
- 遍歷所有連結節點,檢查href屬性的值是否以"/lishi/beijing/month"開頭,是則加入連結集合
public static List<string> ParseLink(string html)
{
List<string> res = new List<string>();
var doc = new HtmlDocument();
doc.LoadHtml(html);
var linkNodes = doc.DocumentNode.SelectNodes("//a[@href]");
foreach (var linkNode in linkNodes)
{
string link = linkNode.GetAttributeValue("href", "");
if (link.StartsWith("/lishi/beijing/month"))
{
res.Add(link);
}
}
return res;
}
至此已經解析出該站點所有含有過去時間段的連結了,接下來需要分析每一個連結對應的具體網頁的結構,從中獲取天氣資訊。
分析天氣網頁結構
之前的連結http://www.tianqihoubao.com/lishi/beijing.html是一個站點連結,在上節中已經分析了具體的天氣網頁對應的連結集合,如http://www.tianqihoubao.com/lishi/beijing/month/201101.html。
現在需要從該頁面中分析出天氣,和解析站點結構中的目標連結一樣,在瀏覽器中觀察Html程式碼,發現天氣這個目標內容在一個表格中,因此我們只需要選出<tr>節點就可以,因為一個<tr>節點表示某一天的天氣(天氣狀況、氣溫和風力方向)。
public static void ParseDailyWeather(string html)
{
var doc = new HtmlDocument();
doc.LoadHtml(html);
var rows = doc.DocumentNode.SelectNodes("//tr");
StringBuilder sb = new StringBuilder();
rows.RemoveAt(0);
foreach (var row in rows)
{
var cols = row.SelectNodes("td");
foreach (var col in cols)
{
string temp = col.InnerText.Replace("\r\n", "").Replace(" ", "").Trim();
sb.Append(temp + ",");
}
sb.Append("\r\n");
}
FileStream fs = new FileStream("output.csv", FileMode.Append, FileAccess.Write);
StreamWriter sw = new StreamWriter(fs, Encoding.GetEncoding("gbk"));
sw.WriteLine(sb);
sw.Close();
fs.Close();
}
最後,為了實現站點的爬取,需要一個迴圈來實現所有網頁的爬取
public static void ParseWebsite(string url)
{
string html = Weather.GetHtml(url);
var links = Weather.ParseLink(html);
foreach (var link in links)
{
url = "http://www.tianqihoubao.com" + link;
html = Weather.GetHtml(url);
Weather.ParseDailyWeather(html);
}
}
總結
靜態網頁的爬取比較簡單,分為以下幾個步驟就可以
- 確定內容和站點。
- 分析站點結構。從站點結構中找出目標連結的特點,分析出所有目標連結。
- 分析網頁結構。在目標連結的網頁中找出目標內容的特點,提取目標內容。