前段时间一直在了解关于Http相关的知识,然后园子里时不时有园友发关于采集网页信息的文章,然后自己也想试试如何做网页的数据采集,便开始在网找查找相关资料,
方法有很多种,如 用开源的框架忘了叫什么名了,或者用.net Framework自带的HttpwebRequest对象与HttpwebResponse对象,当然也还有其它对象也可以做到如 WebClient 等,而我选择用HttpwebRequest 与HttpWebResponse来处理。
经过几个晚上的不断折腾终于把这东西折腾出来了,我的定位就只是用来练手所以不免会有BUG,这个小工具有两个BUG 一个在无限滚动这里,都以经按插件的参数配置了,可它就是不听使唤,老是会自动触发加载事件,不得以我来个限定最多只加载10页的数据。如果有熟悉这个插件的朋友,下载源码后帮忙修改下,我拿它真没折了.......先谢过了~~
第二个BUG在构造Http请求时有时正常,有时却出现请求超时 比如我在家里测试时,都可以正常运行,而同样的代码放到公司时却出现请求超时,这个问题真心不知道是什么原因引起的,
这是我写的第二个小工具
第一个在这里 文件夹管理工具(MVC+zTree+layer)(附源码)
本项目地址在这里 采集博客园文章工具
文章还涉及到正则表达示,我总结了一篇相关的文章
在这里 读懂正则表达式就这么简单
2.1工具截图
效果大至就是这样了,样式什么的就没细调了,大伙将就下吧,能看就行了,主要这段时间比较忙,所以匆匆收尾了,还望见谅
2.2 工具所用到插件
masonry:
是 一款非常强大的jQuery动态网格布局插件,可以帮助开发人员快速开发类似剪贴画的界面效果。和CSS中float的效果不太一样的地方在 于,float先水平排列,然后再垂直排列,使用Masonry则垂直排列元素,然后将下一个元素放置到网格中的下一个开发区域。这种效果可以最小化处理 不同高度的元素在垂直方向的间隙
infinitescroll
是一个无限循环滚动的插件,做自动分页加载是很好用的,再配合masonry 瀑布流就可以达到 类似于QQ空间自动加载的效果,
3.1 分析请求
先用Fiddler 抓取博客园的请求信息大至如下,因为只需要获取文章的信息,不需要做其它操作,所以Cookies部分就可以不考虑,
只要把请求头的相关信息Copy就行了然后添加到HttpWebRequest对象中
3.2 构造请求 并获取响应信息
通过HttpWebRequest创建一个请求,然后添加请求头信息,最后获取请求的响应信息到HttpWebResponse对象中,并读取出相应数据。
HttpWebRequest request = (HttpWebRequest) WebRequest.Create("http://www.cnblogs.com/"); request.Accept = "text/plain, */*; q=0.01"; request.Method = "GET"; request.Headers.Add("Accept-Language", "zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3"); request.ContentLength = 0; request.ContentType = "keep-alive"; request.Host = "www.cnblogs.com"; request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; rv:25.0) Gecko/20100101 Firefox/25.0"; HttpWebResponse response = (HttpWebResponse)request.GetResponse(); Stream responStream = response.GetResponseStream(); StreamReader reader = new StreamReader(responStream,Encoding.UTF8); string content = reader.ReadToEnd();
3.3 通过正则取文章基本信息
个人觉得最难的部分就在用正则匹配出指定数据,因为没有接触过正则,而且正则又不太容易理解,所以学习正则花了一部分时间,并把正则相关的知识总结成了一篇文章
读懂正则表达式就这么简单 感谢大家的支持。,这里只列取一部分,具体的项目中都有详细的代码
//取推荐 regex =new Regex( "<div class=\"digg\">.*<span.*>(?<digNum>.*)" + @"</span>" + ".*<div class=\"post_item_body\">", RegexOptions.Singleline); article.DiggNum = regex.Match(item.Value).Groups["digNum"].Value; //取文章标题 需要去除转义字符 regex = new Regex("<h3>(?<a>.*)</h3>", RegexOptions.Singleline); string a = regex.Match(item.Value).Groups["a"].Value; regex = new Regex("<a\\s.*href=\"(?<href>.*?)\".*>(?<summary>.*)</a>", RegexOptions.Singleline); article.AritcleUrl = regex.Match(a).Groups["href"].Value; article.AritcleTitle = regex.Match(a).Groups["summary"].Value; //取作者图片 先取html img标签再取Src regex = new Regex("<a.*>(?<img><img[^>].*>)</a>", RegexOptions.Singleline); string img = regex.Match(item.Value).Groups["img"].Value; regex = new Regex(@"<img.*src=(?<path>.*)\s+.*/>", RegexOptions.Singleline); article.AuthorImg = regex.Match(img).Groups["path"].Value.TrimEnd('"').TrimStart('"');
3.4 把数据返回给插件Masonry
具体的参数配置官网都有详细的解释,这里就不详细说了,
$('.container').masonry({ itemSelector: '.item', columnWidth: 230,//一列的宽度 Integer isAnimated: true,//使用jquery的布局变化 Boolean animationOptions: { Object :{ queue: false, duration: 500 } //jquery animate属性 渐变效果 }, gutterWidth: 10,//列的间隙 Integer isFitWidth: true,// 适应宽度 Boolean isResizableL: true,// 是否可调整大小 Boolean isRTL: false,//使用从右到左的布局 Boolean });
3.5 通过infinitescroll自动加载数据
通过触发这个插件infinitescroll的事件,来达到自动加载的效果,这里要注意的是自动加需要一个div 与a 标签,div是分页的容器初始化后会隐藏,而a标签的href属性则
是你要自动加载数据的地址,后面的参数 id=2 默认是从第二页开始,会自动累加。刚开始自己在网上找资料时,没人把这两个元素写出来,让我纠结了好久,我说不给地址
怎么去哪自动加载去啊,找了好久终于让我发现了.....
<div id="page-nav"> <a href="/GetArticle/GetArticles/?id=2"></a> </div>
template 的函数返回值就是自动加载后返回的数据可以在DataType属性设定返回的数据格式,注意插件的最后一个回调函数 function (newElements) 要把新的数据添加进瀑布流的布局里就是在这里处理的, 这里的 newElements 其实就是template的返回值,也就是自动加载后重新拼装的数据。
$('.container').infinitescroll({ navSelector: '#page-nav', nextSelector: '#page-nav a', //下一页选择器 itemSelector: ".item", //下一页中需要被加载进当前页的块 extraScrollPx: 150,//滚动条距离底部多少像素的时候开始加载,默认150 animate: true, maxPage:10,//最大页数 dataType: 'json', loading: { //加载效果 finishedMsg: 'No more pages to load', }, template: function (data) { //data表示服务端返回的json格式数据,这里需要把data转换成瀑布流块的html格式,然后返回给回到函数 var article = ''; for (var i in data) { article += "<li class='item'>" + "<a href=" + data[i].AritcleUrl + " target='_blank'><h3> " + data[i].AritcleTitle + "</h3></a>" + "<p>推荐<b> " + data[i].DiggNum + "</b> <a href=" + data[i].AuthorUrl + "><img src=" + data[i].AuthorImg + " alt='' /> </a></p>" + "<p style='text-indent: 2em'>" + data[i].AritcleSummary + "</p>" + "<p><a href=" + data[i].AuthorUrl + ">" + data[i].Author + "</a>" + data[i].PublishTime + "</p>" + "<p>" + data[i].CommentNum +" "+data[i].ReadNum + "</p></li>"; } return article; }, }, function (newElements) { //回调函数,用Masonry布局 // 当加载时隐藏所有新项目 var $newElems = $(newElements).css({ opacity: 0 }); // 现在可以显示所有的元素 $newElems.animate({ opacity: 1 }); $('.container').masonry('appended', $newElems, true); } );
通过上面5步就可以把数据正常的加载出来,具体的细节部分喜欢的朋友可以下载源码看看。
每次接触新的知识我都尽量会把所学的做一个工具出来,以加强自己的印象。我很享受从构思直到开发完成的这一个过程,在这个过程中收获的东西也很多。
不仅了解了Http相关的知识,还学习了正则与瀑布流和无限滚动,我会继续以这种方式一直走下去....
如果您觉得本文有给您带来一点收获,不妨点个推荐,为我的付出支持一下,谢谢~
如果希望在技术的道路上能有更多的朋友,那就关注下我吧,让我们一起在技术的路上奔跑