[VBNET] 抓取網頁部分內容

很多網頁砍站軟體支援續傳、多線下載,多線下載觀念比較簡單,就是同一個檔利用多緒分別抓某個部分,再用二進位檔存取方式將抓得的結果直接寫入指定的範圍即可。
 
要知道怎樣做,可以先看規格書:
HTTP 1.0: RFC2068 14.36 節 Range
HTTP 1.1: RFC2616 14.35 節 Range
 
也就是說在 通訊協定中,檔頭加入:
Range: bytes=開始-結束
省略開始時,從 0 開始,省略結束時,自動抓到結尾。
 
我是認為寫程式前,應該先了解低階運作方式,通訊協定自然就是利用命令提示字元測試,例如輸入:

telnet tlcheng.twbbs.org 80
GET / HTTP/1.0
Range: bytes=100-199

傳回:

HTTP/1.1 206 Partial Content
Content-Length: 100
Content-Type: text/html
Content-Location: http://192.168.2.10/index.htm
Content-Range: bytes 100-199/3162
Last-Modified: Thu, 16 Oct 2008 08:32:25 GMT
Accept-Ranges: bytes
ETag: "e2437db7692fc91:1518"
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
Date: Thu, 16 Oct 2008 17:08:55 GMT
Connection: close
-equiv="Page-Exit" content="RevealTrans(Duration=0.5,Transition=23)">
<title>憸函此蝘凵?撽ⓗ??毡
遺失與主機的連線。
C:>

由上可知,很明確的傳回指定的範圍。
 
我們可以選擇的類別有 WebClient / WebRequest / HttpWebRequest ,在屬性 Headers 中的註解有提到:

WebHeaderCollection 類別通常是經由 WebRequest.HeadersWebResponse.Headers 來存取。某些通用標頭會視為受限制的,並會直接由 API 公開 (例如,Content-Type) 或是由系統保護,而且無法變更。

受限制的標頭有:

  • Range
所以只剩 HttpWebRequest.AddRange 可以使用,其它情形就是自己用 TcpClient / Socket 類別自行實作,或是繼承 HttpWebRequest 類別加以覆寫。使用 HttpWebRequest.AddRange 時,因為不能直接指定 Range 字串,所以出現了很白目的四種判斷方式,開始位元組、結束位元組是否有值,讓人覺得這樣有點白目,範例:

Dim strStartByte,strEndByte As String

Dim wRequest As Net.HttpWebRequest = Net.WebRequest.Create(strUrl)

wRequest.Method = "GET"

If strStartByte = "" Then

     If strEndByte = "" Then

     Else

          wRequest.AddRange(-CInt(strEndByte))

     End If

Else

     If strEndByte = "" OrElse CInt(strEndByte) < CInt(strStartByte) Then

          wRequest.AddRange(CInt(strStartByte))

     Else

          wRequest.AddRange(CInt(strStartByte), CInt(strEndByte))

     End If

End If

 

Dim wResponse As Net.HttpWebResponse = wRequest.GetResponse()

Response.HeaderEncoding = System.Text.Encoding.GetEncoding("big5")

Response.AddHeader("Content-disposition", "attachment; filename=" & IO.Path.GetFileName(Request("txtUrl")))

 

Dim m_NetworkStream As System.IO.Stream

m_NetworkStream = wResponse.GetResponseStream

Dim nBuffer, nBytes As Integer

nBuffer = 512

Dim tBytes(nBuffer – 1) As Byte

 

Do

     System.Threading.Thread.Sleep(1)

Try

          nBytes = m_NetworkStream.Read(tBytes, 0, nBuffer)

          Dim byteOutput(nBytes – 1) As Byte

          Array.Copy(tBytes, 0, byteOutput, 0, nBytes)

          Response.BinaryWrite(byteOutput)

     Catch

          nBytes = 0

     End Try

Loop Until nBytes = 0

Response.End()


測試位置:
 
另外,在支援透過 http 下載超過 2 GB 檔案的網站上, HttpWebRequest.AddRange 限制為 Int32 ,所以不能大於 2 GB ,要處理 2 GB 以上的檔案就是上面說的:其它情形就是自己用 TcpClient / Socket 類別自行實作,或是繼承 HttpWebRequest 類別加以覆寫。

廣告
Categories: 技術分享 | 4 則迴響

文章分頁導航

4 thoughts on “[VBNET] 抓取網頁部分內容

  1. 小朱

    建議在下載的程式中,自動加上 .txt 比較好,不然:
    測試 http://www.microsoft.com —> 下載 .com (MS-DOS 程式)
    測試 http://tlcheng.twbbs.org/Tools/Network/httpRange.aspx —&gt; 下載 .aspx 檔案 …

    按讚數

  2. 子璉

    小朱:
    因為上面程式碼我的檔名是用這個規則:IO.Path.GetFileName(Request("txtUrl"))
    我又懶得寫很長去判斷…
    我當初有想過用 output.txt / output.bin 當作預設檔名,最後還是挑個懶方法,反正這頁是測試網頁,你的建議就當成附注來看待好了。
     

    按讚數

  3. 子璉

    另外補充的是,有些網站有特別擋,所以可以先用 Head 來測試判斷,如果 Head 傳回結果中不包含:
    Range: bytes=xxx-xxx/xxxxx
    時,就表示不支援,或是該命令被過濾了。

    按讚數

  4. 引用通告: [VBNET] 抓取網頁部分內容 | 資訊與工作

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com Logo

您的留言將使用 WordPress.com 帳號。 登出 / 變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 / 變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 / 變更 )

Google+ photo

您的留言將使用 Google+ 帳號。 登出 / 變更 )

連結到 %s

在 WordPress.com 建立免費網站或網誌.

%d 位部落客按了讚: