實驗:用Unity抓取指定url網頁中的所有圖片並下載保存


突發奇想,覺得有時保存網頁上的資源非常麻煩,有沒有辦法輸入一個網址就批量抓取對應資源的辦法呢。

需要思考的問題:

1.如何得到網頁url的html源碼呢?

2.如何在浩瀚如海的html中匹配出需要的資源地址呢?

3.如何按照得到的資源地址集合批量下載資源呢?

4.下載的資源一般為文件流,如何生成指定的資源類型並保存呢?

 

需要掌握的知識:

1.網絡爬蟲的基礎知識,發送Http請求的方法

2.C# 正則表達式運用,主要是識別html中需要的rul網址

3.UnityWebRequest類文件流下載

4.C# File類和Stream類等基礎文件操作

 

下面分項來進行實現:

關於爬蟲這里就不進行介紹了,網上其他的地方有很多資料,簡而言之就是采集網頁信息和數據的程序。

第一步,就是要發送一個Web請求,也可以說是Http請求。

這跟你打開瀏覽器輸入一個url地址然后回車產生的效果基本是類似的,網頁上之所以能顯示出正確的信息和數據,是因為每一個網頁有對應的html源碼,像很多瀏覽器例如谷歌瀏覽器都是支持查看網頁源碼的功能,例如下面是我經常去的喵窩的主頁的html的<head>部分:

 

 

html源碼中可以查看到網頁當前的很多隱藏信息和數據,其中還有大量的資源鏈接和樣式表等。值得注意的是,html源碼只有在網頁全部加載完成之后很可以顯示和查看,這意味着一個url地址的Web請求響應成功;有成功的情況當然就會有各種各樣失敗的情況,例如我們經常輸入一個rul地址后出現404的提示,這種就是一個Http請求出現錯誤的情況,404表示服務器未找到請求的網頁。其他的錯誤類型還有很多。為什么要了解這一點呢,因為之后在發送Http請求時要想辦法對錯誤進行處理或跳過執行下一任務。

我們可以有很多方式來發送Http請求,Unity也更新了Web請求的方式:(以后代碼我就直接截圖了,這個插入代碼功能都不能自動排整齊真的難受)

 

主要用到的類就是UnityWebRequest,和Unity中以前的類WWW有些類似,主要用於文件的下載與上傳。

要引入以下命名空間:

 

UnityAction作為參數主要是用於請求結束后可以自動返回一個html源碼。它本質上就是個泛型委托:

 

泛型的參數可以從沒有到多個,是一個非常好用的類(尤其是在協程的回調中,可以很方便的延時參數傳遞)

當然了,除了Unity內置的發送Web請求的方法,C#也封裝了好幾個類,你可以隨便挑一個使用,例如 HttpWebRequest,WebClient,HttpClient等:

比如這樣:

 

如果成功通過Web請求得到了指定url地址的html源碼,那就可以執行下一步了。

第二步,收集html中所需要的數據信息,本例中就是要從這些源碼中找出圖片的鏈接地址。

例如可能會有下面這幾種情況:

 

 

 

總結一下,首先利用html的常用標簽<img>來找可以找到大部分的圖片,但還是有部分圖片並不在這些標簽之內。而且有時候,即使是在<img>標簽之內的圖片地址,還是有可能出現內鏈或是外鏈的區別,外鏈的話直接作為合法的url地址執行即可,但如果是內鏈的話就還要補全域名地址,所以我們還需要想辦法識別一個url的正確域名。

 

關於如何識別匹配以上所說的字符串內容,目前最有效的方法就是正則表達式,下面就列舉在本例中需要使用到的正則表達式:

1.匹配url域名地址:

private const string URLRealmCheck = @"(http|https)://(www.)?(\w+(\.)?)+";

2.匹配url地址:

private const string URLStringCheck = @"((http|https)://)(([a-zA-Z0-9\._-]+\.[a-zA-Z]{2,6})|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(:[0-9]{1,4})*(/[a-zA-Z0-9\&%_\./-~-]*)?";

3.匹配html中<img>標簽內的url地址:(不區分大小寫,其中分組<imgUrl>中為所需的url地址)

private const string imgLableCheck = @"<img\b[^<>]*?\bsrc[\s\t\r\n]*=[\s\t\r\n]*[""']?[\s\t\r\n]*(?<imgUrl>[^\s\t\r\n""'<>]*)[^<>]*?/?[\s\t\r\n]*>";

4.匹配html中<a>標簽內href屬性的url地址:(不區分大小寫,主要用於深度檢索,其中分組<url>中為所需的url地址)

private const string hrefLinkCheck = @"(?i)<a\s[^>]*?href=(['""]?)(?!javascript|__doPostBack)(?<url>[^'""\s*#<>]+)[^>]*>";

5.指定圖片類型的匹配:(主要用於外鏈)

private const string jpg = @"\.jpg";
private const string png = @"\.png";

關於正則表達式的具體匹配用法,網上也有很多教程,這里就不說了。

 

給定一個html源碼,下面從兩個方向對圖片進行匹配,先匹配外鏈,這里指定了匹配的文件類型:

下面是內鏈的匹配,先要匹配出域名地址:

 

有了域名地址之后就可以輕松匹配內鏈地址了:

 

使用正則表達式需要引入以下命名空間:

 

利用正則表達式匹配出所有的imgLinks后就可以對其中的圖片進行依次下載了。

第三步,對有效的圖片url進行下載傳輸:

 你也可以對這些url進行同步下載傳輸,但這樣可能需要增加額外的最大線程數,而且比較難控制整體的下載進度。

具體的傳輸協程如下:

 值得注意的是,並非只有成功下載時才調用Complete方法,即使發生了錯誤,也需要調用,這樣避免了一發生錯誤,自動下載就自行終止的情況。正常情況下是即使發生了錯誤,也要跳過執行下一文件的下載任務。

 

最后一步就是將下載的數據文件流轉化為指定類型的文件並保存,這里方法有很多,下面提供一種:

 

 

擴展:

有時單個html中的所有圖片鏈接不能完全滿足我們的需求,因為html中的子鏈接中可能也會有需要的url資源地址,這時我們可以考慮增加更深層次的遍歷。那就需要先匹配出html中的link地址,然后再得到該link地址的子html源碼,如此進行關於深度匹配的循環。

匹配html中的子鏈接可以通過查找<a>標簽的屬性href,上面已經給出過該屬性的正則匹配表達式,這里只深度匹配了一層以供參考:

 

 

測試:這里用深度匹配抓取喵窩主頁為jpg格式的圖片鏈接並下載,存到D盤中。(UI就隨便做的不用在意)

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM