網絡采集軟件核心技術剖析系列(3)---如何使用C#語言下載博文中的全部圖片到本地並可以離線瀏覽


一 本系列隨筆概覽及產生的背景

本系列開篇受到大家的熱烈歡迎,這對博主是莫大的鼓勵,此為本系列第三篇,希望大家繼續支持,為我繼續寫作提供動力。

自己開發的豆約翰博客備份專家軟件工具問世3年多以來,深受廣大博客寫作和閱讀愛好者的喜愛。同時也不乏一些技術愛好者咨詢我,這個軟件里面各種實用的功能是如何實現的。

該軟件使用.NET技術開發,為回饋社區,現將該軟件中用到的核心技術,開辟一個專欄,寫一個系列文章,以饗廣大技術愛好者。

本系列文章除了講解網絡采編發用到的各種重要技術之外,也提供了不少問題的解決思路和界面開發的編程經驗,非常適合.NET開發的初級,中級讀者,希望大家多多支持。

很多初學者常有此類困惑,“為什么我書也看了,C#相關的各個方面的知識都有所了解,但就是沒法寫出一個像樣的應用呢?”

這其實還是沒有學會綜合運用所學知識,鍛煉出編程思維,建立起學習興趣,我想該系列文章也許會幫到您,但願如此。

開發環境:VS2008

本節源碼位置:https://github.com/songboriceboy/GetWebAllPics

源碼下載辦法:安裝SVN客戶端(本文最后提供下載地址),然后checkout以下的地址:https://github.com/songboriceboy/GetWebAllPics.git

系列文章提綱如下:

二 第三節主要內容簡介(如何使用C#語言下載博文中的全部圖片到本地並可以離線瀏覽)

網頁的抓取主要分為3步:

1.通過分頁鏈接抓取到全部文章鏈接集合(第一節內容)

2.通過每一個文章鏈接獲取到文章的標題及正文(第二節內容)

3.從文章正文中解析出全部圖片鏈接,並將文章的全部圖片下載到本地(本節內容)

這3步有了,之后你就想怎么折騰就怎么折騰了,各種加工處理,生成pdf,chm,靜態站點,遠程發布到其他站點等等。

如何使用C#語言下載博文中的全部圖片到本地並可以離線瀏覽的解決方案演示demo如下圖所示:可執行文件下載

 

點擊下載正文全部圖片按鈕后,會在可執行程序所在目錄生成一個文件夾(文字為該網頁的標題),文件夾中包含一個html文件(網頁正文)以及網頁正文中的全部圖片。該html文件對最初正文html文件進行了處理,其中的圖片鏈接均修改成了本地圖片文件。

三 基本原理

下載博文中的全部圖片可以分解成3步:

1.下載網頁正文,找出其中的全部圖片鏈接地址;

2.對於每一個圖片鏈接地址,下載該圖片到本地(起一個文件名),同時替換原來的圖片地址為我們剛剛起的文件名;

3.第二步全部圖片下載完成后,將所有圖片鏈接替換后的網頁正文保存為一個新的html文件(index.html)。

接下來我們就一步一步來看一下如何做:

 1.下載網頁正文,找出其中的全部圖片鏈接地址;

 如何下載網頁正文請參考第二節內容,下面咱們看一下如何來獲取網頁正文中的全部圖片鏈接:

private void GetSrcLinks()
        {
            HtmlNodeCollection atts = m_Doc.DocumentNode.SelectNodes("//*[@src]");
            if (Equals(atts, null))
            {
                return;
            }

            Links = atts.
                SelectMany(n => new[]
                    {
                        ParseLink(n, "src"),

                    }).
                Distinct().
                ToArray();
        }

通過HtmlAgilityPack中的HtmlDocument類找出全部src屬性的節點,再通過linq提取出其中的網頁地址。

2.對於每一個圖片鏈接地址,下載該圖片到本地,如下代碼所示:

 DocumentWithLinks links = htmlDoc.GetSrcLinks();
            int i = 1;
            string baseUrl = new Uri(strLink).GetLeftPart(UriPartial.Authority);

            foreach (string strPicLink in links.Links)
            {
                if (string.IsNullOrEmpty(strPicLink))
                {
                    continue;
                }
          
                try
                {
                    string strExtension = System.IO.Path.GetExtension(strPicLink);

                    if (strExtension == ".js" || strExtension == ".swf")
                        continue;
                  
                    if (strExtension == "")
                    {
                        strExtension = ".jpg";
                    }

                    string normalizedPicLink = GetNormalizedLink(baseUrl, strPicLink);
                    strNewPage = DownLoadPicInternal(wc, strNewPage, strPageTitle, strPicLink, normalizedPicLink, strExtension, ref i);
                }
                catch (Exception ex)
                {
                } //end try
            }

其中 DownLoadPicInternal的實現代碼如下:

protected string DownLoadPicInternal(WebClient wc, string strNewPage, string strPageTitle, string strPicLink
                               , string strTureLink, string strExtension, ref int i)
        {
            strPageTitle = strPageTitle.Replace("\\", "").Replace("/", "").Replace(":", "").Replace("*", "").Replace("?", "")
            .Replace("\"", "").Replace("<", "").Replace(">", "").Replace("|", "");
            strPageTitle = Regex.Replace(strPageTitle, @"[|•/\;.':*?<>-]", "").ToString();
            strPageTitle = Regex.Replace(strPageTitle, "[\"]", "").ToString();
            strPageTitle = Regex.Replace(strPageTitle, @"\s", "");

            if (!Directory.Exists(Application.StartupPath + "\\" + strPageTitle))//判斷是否存在
            {
                Directory.CreateDirectory(Application.StartupPath + "\\" + strPageTitle);//創建新路徑
            }
           
            int[] nArrayOffset = new int[2];
            nArrayOffset = m_bf.getOffset(strPicLink);
            strNewPage = strNewPage.Replace(strPicLink, nArrayOffset[0].ToString() + nArrayOffset[1].ToString() + strExtension);
            string strSavedPicPath = Path.Combine(strPageTitle, nArrayOffset[0].ToString() + nArrayOffset[1].ToString() + strExtension);
        

            PrintLog(" 開始下載文章 [" + strPageTitle + "] 的第" + i.ToString() + "張圖片\n");
            strTureLink = HttpUtility.UrlDecode(strTureLink);
            wc.DownloadFile(strTureLink, Application.StartupPath + "\\" + strSavedPicPath);
            PrintLog(" 下載完成文章 [" + strPageTitle + "] 的第" + i.ToString() + "張圖片\n");
            System.Threading.Thread.Sleep(300);
            i++;
            return strNewPage;

        }

其中粉色代碼部分m_bf變量是BloomFilter類型的一個對象,BloomFilter是一個網頁去重的強大工具,這里是為了將圖片鏈接轉化為一個獨一無二的文件名。

strNewPage = strNewPage.Replace(strPicLink, nArrayOffset[0].ToString() + nArrayOffset[1].ToString() + strExtension);

此行代碼是用新的圖片文件名替換原網頁中的圖片鏈接。其他部分的代碼之前章節均有解釋,請自行參考。

 3.第二步全部圖片下載完成后,將所有圖片鏈接替換后的網頁正文保存為一個新的html文件(index.html),主要代碼如下:

  strPageTitle = strPageTitle.Replace("\\", "").Replace("/", "").Replace(":", "").Replace("*", "").Replace("?", "")
             .Replace("\"", "").Replace("<", "").Replace(">", "").Replace("|", "");
            strPageTitle = Regex.Replace(strPageTitle, @"[|•/\;.':*?<>-]", "").ToString();
            strPageTitle = Regex.Replace(strPageTitle, "[\"]", "").ToString();
            strPageTitle = Regex.Replace(strPageTitle, @"\s", "");


            File.WriteAllText(Path.Combine(strPageTitle, "index.html"), strNewPage, Encoding.UTF8);

上面的一堆替換是因為windows對文件夾名有要求---不能包含一些特殊字符,這里我們通過正則替換去掉這些特殊字符。

到此為止,我們就實現了將任意網頁中的正文中的圖片下載到本地的功能,並同時修改了原來網頁正文中的圖片鏈接,以達到可以離線瀏覽的目的。

以后的生成pdf,chm均以此為基礎,這一節是重中之重,有興趣的同學可以擴展我提供的代碼,將它改造成某個站點的圖片采集器應該也是一件簡單的事情。

四 下節預告

使用C#語言如何將html網頁轉換成pdf(html2pdf)。

作者: 宋波
出處: http://www.cnblogs.com/ice-river/
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接。
正在看本人博客的這位童鞋,我看你氣度不凡,談吐間隱隱有王者之氣,日后必有一番作為!旁邊有“推薦”二字,你就順手把它點了吧,相得准,我分文不收;相不准,你也好回來找我!


免責聲明!

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



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