坑爹货 AngleSharp

这两天在做个爬虫, 一次任务要下载3万多个页面, 然后从这3万多个页面提取数据.

以前写过两年的类似的东西, 基本都是写正则表达式, 速度快, 就是写正则表达式老费劲了, 目标网页稍微改动一点就要重写正则.

后来我用了 HtmlAgilityPack + Fizzler, 很轻松的就处理了.

昨天, 我找了两个类似 HtmlAgilityPack 的东西:CsQuery 和 AngleSharp

翻了翻它们的API和说明文档, CsQuery 说能实现 jQuery 的 selector 语法, 我试了试,还真是, :even 这个东西也能使用, 但是在 AngleSharp 里就不支持这个了, HtmlAgilityPack 没有试, 应该也不支持.

看 AngleSharp , 它给出了这三个东西的性能对比:

https://github.com/FlorianRappl/AngleSharp/wiki/Performance

从其中列出的对比结果来看, 确实比 CsQuery 和 HtmlAgilityPack 快不少.

于是,我放弃了 CsQuery 的牛逼的 selector 和 HtmlAgilityPack 的口碑, 直接在项目中使用了 AngleSharp.

没想到它是个坑爹货:

今天中午利用吃饭时间, 我运行了这个任务, 回来后发现 这货吃了快 11G 内存, 没看错, 11G! 因为这台电脑总共只有 12G内存!

为留证据, 我又跑了一下, 3分20秒, 占用内存高达 1.8G.

怕冤枉好人, 我把所有自己写的东西都运行了一遍代码分析, 确保没有任何未释放的对象.

结果这货还是这样吃内存.

换成 HtmlAgilityPack 后:

3分20秒的时候, 也不过才 270M 而已. 而且是一边增加,一边释放, 到现在运行了差不多半个小时了, 内存还在 180M 左右徘徊。

以下是用 HtmlAgilityPack 的代码:

 1 public override IEnumerable<DIRTY_SCHEDULE> Fetch(string ctx, string url = "") {
 2     var doc = new HtmlDocument();
 3     doc.LoadHtml2(ctx);
 4     var root = doc.DocumentNode;
 5     var trs = root.QuerySelectorAll("#accordion2>.accordion-group>.accordion-heading>table>tbody>tr")
 6         .ToList();
 7     for (var i = 0; i < trs.Count(); i = i + 2) {
 8         var tr = trs[i];
 9         var tds = tr.QuerySelectorAll("td").ToList();
10         var entry = new DIRTY_SCHEDULE {
11             CARRIER = tds[0].InnerText.Clear(),
12             ROUTE = tds[1].InnerText.Clear(),
13             VESSEL = tds[2].InnerText.Clear(),
14             VOYAGE = tds[3].InnerText.Clear(),
15             ORGIN = tds[4].InnerText.Clear(),
16             ETD = tds[5].InnerText.Clear().ToDateTime("yyyy-MM-dd", DateTime.Now),
17             DEST = tds[6].InnerText.Clear(),
18             ETA = tds[7].InnerText.Clear().ToDateTime("yyyy-MM-dd", DateTime.Now),
19             TT = tds[8].InnerText.Clear().ToDecimalOrNull(),
20             DIRTY_SCHEDULE_TRANSF = this.FetchTransf(trs[i + 1]).ToList(),
21             SOURCE = url,
22             APP = "Fetcher.Soushipping",
23         };
24
25         entry.UNQTAG = entry.GetUNQTag();
26
27         yield return entry;
28     }
29 }
30
31
32 private IEnumerable<DIRTY_SCHEDULE_TRANSF> FetchTransf(HtmlNode tr) {
33     var tbls = tr.QuerySelectorAll("table.widget").ToList();
34     //第一个列出的是起始地
35     for (var i = 1; i < tbls.Count(); i++) {
36         var rows = tbls[i].QuerySelectorAll("tr").ToList();
37         if (rows.Count == 3)
38             yield return new DIRTY_SCHEDULE_TRANSF {
39                 VESSEL = rows[0].InnerText.Clear(),
40                 AT = rows[1].QuerySelector("td").InnerText.Clear(), //rows[1].FirstChild.Text().Trim(),
41                 VOYAGE = rows[2].InnerText.Clear(),
42                 SEQ = i - 1
43             };
44     }
45 }

下面是用 AngleSharp 的代码:

 1 public override IEnumerable<DIRTY_SCHEDULE> Fetch(string ctx, string url = "") {
 2     var dom = DocumentBuilder.Html(ctx);
 3     //不支持 even
 4     //var trs = dom.QuerySelectorAll("#accordion2 table tbody tr:even");
 5     var trs = dom.QuerySelectorAll("#accordion2>.accordion-group>.accordion-heading>table>tbody>tr");
 6     for (var i = 0; i < trs.Length; i = i + 2) {
 7         var tr = trs[i];
 8         var tds = tr.QuerySelectorAll("td");
 9         var entry = new DIRTY_SCHEDULE {
10             CARRIER = tds[0].Text(),
11             ROUTE = tds[1].Text().Trim(),
12             VESSEL = tds[2].Text().Trim(),
13             VOYAGE = tds[3].Text().Trim(),
14             ORGIN = tds[4].Text().Trim(),
15             ETD = tds[5].Text().Trim().ToDateTime("yyyy-MM-dd", DateTime.Now),
16             DEST = tds[6].Text().Trim(),
17             ETA = tds[7].Text().Trim().ToDateTime("yyyy-MM-dd", DateTime.Now),
18             TT = tds[8].Text().Trim().ToDecimalOrNull(),
19             DIRTY_SCHEDULE_TRANSF = this.FetchTransf(trs[i + 1]).ToList(),
20             SOURCE = url,
21             APP = "Fetcher.Soushipping",
22         };
23
24         entry.UNQTAG = entry.GetUNQTag();
25
26         yield return entry;
27     }
28 }
29
30 private IEnumerable<DIRTY_SCHEDULE_TRANSF> FetchTransf(IElement tr) {
31     var tbls = tr.QuerySelectorAll("table.widget");
32     //第一个列出的是起始地
33     for (var i = 1; i < tbls.Length; i++) {
34         var rows = tbls[i].QuerySelectorAll("tr");
35         if (rows.Length == 3)
36             yield return new DIRTY_SCHEDULE_TRANSF {
37                 VESSEL = rows[0].Text().Trim(),
38                 AT = rows[1].QuerySelector("td").Text().Trim(), //rows[1].FirstChild.Text().Trim(),
39                 VOYAGE = rows[2].Text().Trim(),
40                 SEQ = i - 1
41             };
42     }
43 }

基本一模一样.

看一下 IElement , 这货跟本就没有继承 IDisposable接口, 所以, 也就没有释放不释放这一说.

时间: 2024-10-07 01:58:32

坑爹货 AngleSharp的相关文章

[乐意黎原创] 百度统计这个坑爹货

今天因为一时兴起,想看看个网的统计量. 打开百度的统计:http://tongji.baidu.com 令人惊奇的结果出现了,这是百度的水准么?使用IISserver!! .. 好吧.打开站长平台. 訪问结果: 更奇妙的事情出现了,简直是起了我一身鸡皮疙瘩. 奇妙的百度统计啊,开发百度统计项目.这个团队是个什么水准?架IIS server,会出这样的低智商问题!!!! 无力吐槽啦,再怎么模仿,跟GOOGLE仍是一个天下,一个地下的服务和团队水准啊------ 差CNZZ也不是一两个级别的哇. h

妈蛋:kinMaxShow轮播图异常,WebUploader图片上传坑爹,图片被压缩了

今天晚上在改造轮播图. 原来的代码是这样的: <div> <img src="${static}/image/index/banner/`.jpg" /> </div> <div> <img src="${static}/image/index/banner/2.jpg" /> </div> <div> <img src="${static}/image/index/

妈蛋:kinMaxShow旋转木马异常,WebUploader图片上传坑爹,图像被压缩

今天晚上在改造轮播图. 原来的代码是这种: <div> <img src="${static}/image/index/banner/`.jpg" /> </div> <div> <img src="${static}/image/index/banner/2.jpg" /> </div> <div> <img src="${static}/image/index/b

独自handle一个数据库大程有感

这学期数据库课程,最后的大程是写一个MiniSQL的数据库实现,要求很简单,建删表,建删单值索引,支持主键和unique定义,支持最简单的select,只要支持3个类型:int,float,char(0~255).最开始,考虑到数据库的运行时确定类型的特点,选择了运行时强大的C#,还能顺便集成进Linq.但是一周后发现C#操作对象二进制结构的能力几乎为0,在写BufferManager的时候也发现完全不能自由的控制对象生命周期,并且IDisposable的实现也过于迷,与强大运行时和linq相比

iOS block-base 动画简单用法+关键帧动画设置线性变化速度的问题

本文转载至 http://www.tuicool.com/articles/aANBF3m 时间 2014-12-07 20:13:37  segmentfault-博客原文  http://segmentfault.com/blog/alan/1190000002411296 iOS的各种动画相漂亮,相信这是吸引很多人买iPhone的原因之一.不仅如此,这还是吸引我做iOS开发的一大原因,因为在iOS上给界面实现一些像样的动画实在是太轻松了! 这里就介绍一下iOS的block-based an

【Visual Basic】vb6的ListView控件,对Access2003数据库的增删改查,判断是否有中文、多窗体操作

vb6对Access2003数据库的增删改查并不复杂,可以通过ado对象轻松完成,下面举个小例子,同时说明vb6中的ListView控件的使用.虽然在<[Visual Basic]列表控件ListView的增删改查.模态对话框.禁止窗口调整大小>曾经对VB.NET的ListView控件进行详细的说明,但是证明微软就是个坑爹货,vb6对于ListView实现的代码居然跟VB.NET有着彻底的不同,似乎换了一门语言似得的.改代码什么的最讨厌的. 首先,在vb6生成的工程文件夹中有着一个db1.md

微信赚钱:10万100万1000万级利润玩法尽在此

逐鹿出品!必属精品!看完这篇文章,可以把操蛋的微信书仍了...在 机场候机无聊的时候经常去书店看看畅销书,有关微信营销的书一堆,随便买了一本,耐着性子看了20分钟直接扔了,纯粹浪费时间,这个时代最不缺的就是海量 垃圾信息,正因为如此真正高效有价值和直达本质的信息显得越发重要,真希望以后写书的人书越写越薄,个人认为100页内的书是最好的,为了字数页数而写书 写那么厚浪费读者时间,这是谋财害命...不提微 商,不提各种概念,只提用微信怎么赚钱!(PS:谁说玩淘宝就不能玩微信了?我个人经历从最早的搜狗

iOS App 上架流程-新版本1.0上架

本文转自:http://ios.jobbole.com/84643/  感谢作者,解决了燃眉之急 题记 麻痹起来嗨!看网上那么多的教程,依然在我心爱的爱屁屁在上架的时候遇到各种 J8 问题,最大的问题就是:Xcode 证书什么的,Provisioning Profile 什么的,Debug 什么的,Production 和Distribution 什么乱 78 糟的都把我搞糊涂了,网上很多教程都是好旧的(虽然思路一样,但是不够详细),所以我打算把我今年已经上架的干货儿(下载地址,介绍地址)的上架

.NET Web API 新手遇到的那些“坑”

以前一直做web项目,用的mvc.最近公司需要上线APP,准备用webAPI做接口,用习惯了MVC,API还是有好多细节的地方感觉很“坑”... 第一个坑,webAPI的默认路由规则不一样,通过命名来匹配调用方式,只匹配controller和参数,不匹配action...偶,NO!叫我这个使用了快两年MVC的小码农如何能承受如此重的打击!!!二话不说,咔咔咔,路由配置加上了action...心情瞬间舒畅了不少,再望望窗外的灰蒙蒙的天,我分明看见了蓝天与白云. 第二个坑,一个简单参数的POST方法