一 本系列随笔概览及产生的背景html
本系列开篇受到你们的热烈欢迎,这对博主是莫大的鼓励,此为本系列第三篇,但愿你们继续支持,为我继续写做提供动力。git
本身开发的豆约翰博客备份专家软件工具问世3年多以来,深受广大博客写做和阅读爱好者的喜好。同时也不乏一些技术爱好者咨询我,这个软件里面各类实用的功能是如何实现的。github
该软件使用.NET技术开发,为回馈社区,现将该软件中用到的核心技术,开辟一个专栏,写一个系列文章,以飨广大技术爱好者。数据库
本系列文章除了讲解网络采编发用到的各类重要技术以外,也提供了很多问题的解决思路和界面开发的编程经验,很是适合.NET开发的初级,中级读者,但愿你们多多支持。编程
不少初学者常有此类困惑,“为何我书也看了,C#相关的各个方面的知识都有所了解,但就是无法写出一个像样的应用呢?”windows
这其实仍是没有学会综合运用所学知识,锻炼出编程思惟,创建起学习兴趣,我想该系列文章也许会帮到您,希望如此。网络
开发环境:VS2008框架
本节源码位置:https://github.com/songboriceboy/GetWebAllPics工具
源码下载办法:安装SVN客户端(本文最后提供下载地址),而后checkout如下的地址:https://github.com/songboriceboy/GetWebAllPics.gitpost
系列文章提纲以下:
二 第三节主要内容简介(如何使用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)。