HtmlAgilityPack + Fizzler
HtmlAgilityPack + Fizzler
这两天在做个爬虫, 一次任务要下载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接口, 所以, 也就没有释放不释放这一说.
HtmlAgilityPack + Fizzler的更多相关文章
- c#中的解析HTML组件 -- (HtmlAgilityPack,Jumony,ScrapySharp,NSoup,Fizzler)
做数据抓取,网络爬虫方面的开发,自然少不了解析HTML源码的操作.那么问题来了,到底.NET如何来解析HTML,有哪些解析HTML源码的好用的,有效的组件呢? 作者在开始做这方面开发的时候就被这些 ...
- C#爬虫(04):HtmlAgilityPack解析html文档
原文链接 https://www.cnblogs.com/springsnow/p/13278283.html 目录 一.爬虫概述 1.使用浏览器获取页面源码 2.HTML解析组件 二.HtmlAgi ...
- .NET解析HTML库集合
CsQuery AngleSharp Jumony HtmlAgilityPack Fizzler ScrapySharp NSoup
- .NET下各种可用的HTML解析组件
做数据抓取,网络爬虫方面的开发,自然少不了解析HTML源码的操作.那么问题来了,到底.NET如何来解析HTML,有哪些解析HTML源码的好用的,有效的组件呢? 作者在开始做这方面开发的时候就被这些 ...
- 抓取网站数据不再是难事了,Fizzler(So Easy)全能搞定
首先从标题说起,为啥说抓取网站数据不再难(其实抓取网站数据有一定难度),SO EASY!!!使用Fizzler全搞定,我相信大多数人或公司应该都有抓取别人网站数据的经历,比如说我们博客园每次发表完文章 ...
- FizzlerEx —— 另一个HtmlAgilityPack的CSS选择器扩展,
之前我介绍过HtmlAgilityPack的CSS选择器扩展——ScrapySharp,它可以非常方便的实现通过CSS选择器表达式来查询HtmlNode.今天在使用的过程中,发现它不支持nth-chi ...
- c# & Fizzler to crawl web page in a certain website domain
使用fizzler [HtmlAgilityPackExtension]和c#进行网页数据提取:fizzler是HtmlAgilityPack的一个扩展,支持jQuery Selector: 提取数据 ...
- Fizzler
Fizzler 抓取网站数据不再是难事了,Fizzler(So Easy)全能搞定 首先从标题说起,为啥说抓取网站数据不再难(其实抓取网站数据有一定难度),SO EASY!!!使用Fizzler全搞定 ...
- csharp: using HtmlAgilityPack and ScrapySharp reading Url find text
https://github.com/exaphaser/ScrapySharp https://github.com/zzzprojects/html-agility-pack https://gi ...
随机推荐
- jQuery整理笔记9----函数形式发展
在一些照片中使用演示样本.插入.样式文件下载:点我进入下载 过去在开发过程中关于table方面的jquery应用不过局限于使用jquery操作table添加一行.删除一列等等操作.今天整理的跟过去用的 ...
- JVM的参数详解(转)
12年毕业到先在处理第一年外这几年纯属于打酱油,当初自学Java然后就出来找工作了,还有第一家面试就通过了挺幸运的 但之后的这段时间一直是处于吃老本的状态.最近心情真的很不好,各种黄老邪!一直处于堕落 ...
- CSS不常见问题汇总
写css有一段时间了,其间也遇到一些问题,跟大家分享一下 IE10+滚动条自动以藏问题,导致滚动部分页面看起来不正常 html, body {-ms-overflow-style: scrollbar ...
- 【代码实现】PHP生成各种随机验证码
原文地址:http://www.phpthinking.com/archives/531 验证码在WEB应用中很重要,通经常使用来防止用户恶意提交表单,如恶意注冊和登录.论坛恶意灌水等.本文将通过实例 ...
- 如何成功实施SDL提供的官方Android平台Demo
如何成功实施SDL提供的官方Android平台Demo 作者:雨水 日期:2014-4-30 编写说明:SDL的官方提供了一个Anroid的demo模板SDLActivity,无法直接执行,依照官方 ...
- SWI-Prolog
上个月突然看到Prolog这门语言,它特殊的语法吸引了我,但是经过我一段时间的学习,发现它也不像网络上传说的那样神奇,不过我依然对它很感兴趣,有前辈说Prolog本身并不强大,但是用来作为一门辅助语言 ...
- CoffeeScript NgComponent
Angular遇上CoffeeScript - NgComponent封装 CoffeeScript是基于JavaScript的一门扩展小巧语言,它需要编译成JavaScript,然后再运行与浏览器或 ...
- HTML5分析实战WebSockets一个简短的引论
HTML5 WebSockets规范定义了API,同意web页面使用WebSockets与远程主机协议的双向通信. 介绍WebSocket接口,并限定了全双工通信信道,通过套接字网络. HTML5 W ...
- android工程实现换壁纸功能(转)
最近工作要实现换壁纸小功能,将代码做成demo发出来 没有采用zip格式换肤,因为只是更换一张图片背景 1.将三张图放入drawable-hdpi,我放的是480*800的 2.用sharedPref ...
- 探测器 C++ Singleton(辛格尔顿)
一.静态模式不是单一的情况下, 刚开始学习的人可能误, 误以为所有的成员变量和成员方法用于 static , 就是单例模式了: class Singleton { public: /* sta ...