這一篇咱們聊聊在頁面抓取時應該注意到的幾個問題。html
一:網頁更新web
咱們知道,通常網頁中的信息是不斷翻新的,這也要求咱們按期的去抓這些新信息,可是這個「按期」該怎麼理解,也就是多長時間須要瀏覽器
抓一次該頁面,其實這個按期也就是頁面緩存時間,在頁面的緩存時間內咱們再次抓取該網頁是沒有必要的,反而給人家服務器形成壓力。緩存
就好比說我要抓取博客園首頁,首先清空頁面緩存,性能優化
從Last-Modified到Expires,咱們能夠看到,博客園的緩存時間是2分鐘,並且我還能看到當前的服務器時間Date,若是我再次服務器
刷新頁面的話,這裏的Date將會變成下圖中 If-Modified-Since,而後發送給服務器,判斷瀏覽器的緩存有沒有過時?cookie
最後服務器發現If-Modified-Since = Last-Modifined的時間,服務器也就返回304了,不過發現這cookie信息真是賊多啊。。。工具
在實際開發中,若是在知道網站緩存策略的狀況下,咱們可讓爬蟲2min爬一次就行了,固然這些都是能夠由數據團隊來配置維護了,性能
好了,下面咱們用爬蟲模擬一下。優化
1 using System;
2 using System.Net;
3
4 namespace ConsoleApplication2
5 {
6 public class Program
7 {
8 static void Main(string[] args)
9 {
10 DateTime prevDateTime = DateTime.MinValue;
11
12 for (int i = 0; i 10; i++)
13 {
14 try
15 {
16 var url = http://cnblogs.com;
17
18 var request = (HttpWebRequest)HttpWebRequest.Create(url);
19
20 request.Method = Head;
21
22 if (i 0)
23 {
24 request.IfModifiedSince = prevDateTime;
25 }
26
27 request.Timeout = 3000;
28
29 var response = (HttpWebResponse)request.GetResponse();
30
31 var code = response.StatusCode;
32
33 //若是服務器返回狀態是200,則認爲網頁已更新,記得當時的服務器時間
34 if (code == HttpStatusCode.OK)
35 {
36 prevDateTime = Convert.ToDateTime(response.Headers[HttpResponseHeader.Date]);
37 }
38
39 Console.WriteLine(當前服務器的狀態碼:{0}, code);
40 }
41 catch (WebException ex)
42 {
43 if (ex.Response != null)
44 {
45 var code = (ex.Response as HttpWebResponse).StatusCode;
46
47 Console.WriteLine(當前服務器的狀態碼:{0}, code);
48 }
49 }
50 }
51 }
52 }
53 }
二:網頁編碼的問題
有時候咱們已經抓取到網頁了,準備去解析的時候,tmd的所有是亂碼,真是操蛋,好比下面這樣,
或許咱們依稀的記得在html的meta中有一個叫作charset的屬性,裏面記錄的就是編碼方式,還有一個要點就是
response.CharacterSet這個屬性中一樣也記錄了編碼方式,下面咱們再來試試看。
艹,竟然仍是亂碼,蛋疼了,此次須要到官網上面去看一看,到底http頭信息裏面都交互了些什麼,憑什麼瀏覽器能正常顯示,
爬蟲爬過來的就不行。
查看了http頭信息,終於咱們知道了,瀏覽器說我能夠解析gzip,deflate,sdch這三種壓縮方式,服務器發送的是gzip壓縮,到這裏
咱們也應該知道了經常使用的web性能優化。
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading;
6 using HtmlAgilityPack;
7 using System.Text.RegularExpressions;
8 using System.Net;
9 using System.IO;
10 using System.IO.Compression;
11
12 namespace ConsoleApplication2
13 {
14 public class Program
15 {
16 static void Main(string[] args)
17 {
18 //var currentUrl = http://www.mm5mm.com/;
19
20 var currentUrl = http://www.sohu.com/;
21
22 var request = WebRequest.Create(currentUrl) as HttpWebRequest;
23
24 var response = request.GetResponse() as HttpWebResponse;
25
26 var encode = string.Empty;
27
28 if (response.CharacterSet == ISO-8859-1)
29 encode = gb2312;
30 else
31 encode = response.CharacterSet;
32
33 Stream stream;
34
35 if (response.ContentEncoding.ToLower() == gzip)
36 {
37 stream = new GZipStream(response.GetResponseStream(), CompressionMode.Decompress);
38 }
39 else
40 {
41 stream = response.GetResponseStream();
42 }
43
44 var sr = new StreamReader(stream, Encoding.GetEncoding(encode));
45
46 var html = sr.ReadToEnd();
47 }
48 }
49 }
三:網頁解析
既然通過千辛萬苦拿到了網頁,下一個就要解析了,固然正則匹配是個好方法,畢竟工做量仍是比較大的,可能業界也比較推崇
HtmlAgilityPack這個解析工具,可以將Html解析成XML,而後能夠用XPath去提取指定的內容,大大提升了開發速度,性能也
不賴,畢竟Agility也就是敏捷的意思,關於XPath的內容,你們看懂W3CSchool的這兩張圖就OK了。
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading;
6 using HtmlAgilityPack;
7 using System.Text.RegularExpressions;
8 using System.Net;
9 using System.IO;
10 using System.IO.Compression;
11
12 namespace ConsoleApplication2
13 {
14 public class Program
15 {
16 static void Main(string[] args)
17 {
18 //var currentUrl = http://www.mm5mm.com/;
19
20 var currentUrl = http://www.sohu.com/;
21
22 var request = WebRequest.Create(currentUrl) as HttpWebRequest;
23
24 var response = request.GetResponse() as HttpWebResponse;
25
26 var encode = string.Empty;
27
28 if (response.CharacterSet == ISO-8859-1)
29 encode = gb2312;
30 else
31 encode = response.CharacterSet;
32
33 Stream stream;
34
35 if (response.ContentEncoding.ToLower() == gzip)
36 {37 stream = new GZipStream(response.GetResponseStream(), CompressionMode.Decompress);38 }39 else
40 {
41 stream = response.GetResponseStream();
42 }
43
44 var sr = new StreamReader(stream, Encoding.GetEncoding(encode));
45
46 var html = sr.ReadToEnd();
47
48 sr.Close();
49
50 HtmlDocument document = new HtmlDocument();
51
52 document.LoadHtml(html);
53
54 //提取title
55 var title = document.DocumentNode.SelectSingleNode(//title).InnerText;
56
57 //提取keywords
58 var keywords = document.DocumentNode.SelectSingleNode(//meta[@name='Keywords']).Attributes[content].Value;
59 }
60 }
61 }