设计爬虫Hawk背后的故事
本文写于圣诞节北京下午慵懒的午后。本文偏技术向,不过应该大部分人能看懂。
五年之痒
2016年,能记入个人年终总结的事情没几件,其中一个便是开源了Hawk。我花不少时间优化和推广它,得到的评价还算比较正面,因为负面评价也没什么渠道进我耳朵。
不过你知道我写这个东西花了多久吗? 掐头去尾,这是第五个年头了。
读研究生伊始,实验室开始做数据挖掘,但我发现大家做研究,都是一段段的代码,遇到新问题,就不得不再拷贝一份修改,很少想过复用。于是我便花了一年的时间,开发了一款现在看起来配色丧心病狂的“数据挖掘软件”:
它居然能在上面刷微博,能把任何一个学姐学妹在微博的蛛丝马迹全扒出来,渲染出配色更丧病的绚丽图表(这里有更详细的细节)。实验室老师最喜欢拿这套软件给参观的领导演示了。
我多少有点偏执,想用纯图形化的方式构建数据挖掘的全部流程:从获取清洗数据,建模,训练到最后可视化。但以我当时的算法和软件水平,这样的东西根本就不可能做完善,我还意淫着能把它商业化。最终结果,是它跟着我一起毕业,除了我和几个学弟之外,没人用过。
工作后,靠业余时间维护它有很大的困难。数不清的bug和时间花销,让它成了拖后腿的包袱。一些考虑不周的接口,设计于几年之前,后来想修改却花费巨大。更重要的是,它的未来在哪里?
时值2015年,桌面软件已死,web都已过时,移动端才是兵家必争之地。这种大杂烩和复杂度,普通人不可能会用,程序员没有文档不爱用,大神不屑于用。
我也不想让它扔在历史的故纸堆里无人问津,索性就开源吧!
在开源之前,我做了一件事,将它改名为Hawk,寓意为驰骋天空的鹰;把我自己用的次数少于10次的组件全部删掉,连3D可视化,统计和预测模块也不幸免:只保留爬虫和数据清洗,因为分析和挖掘已经有其他工具做得更好了,比如Python那无比强大的工具链。我认识到,只做一件事,并将其做好是多么重要。
老司机送它上路了,那一天,它正式出现在GitHub上。
我对Hawk的评价
我就是用程序员的思路去设计Hawk的,好玩有趣是最重要的。
先说优点:起码它能用,几乎没接触过编程的人,也能在看过教程后,做出他自己的设计,熟练后效率会很高。
我最喜欢的是手气不错,升级Hawk2.0之后,绝大多数网页都可以通过一键提取数据。其实原理很简单,就是树结构的模板匹配。
其次便是那个所见即所得的数据清洗,在调试模式下快速设计任务,在执行模式下并行执行。恕我孤陋寡闻,这种基于流式管线思路,在其他软件上用的并不多。
最后便是子任务,再复杂的需求,都可以通过子任务分而治之,比如多次定向跳转。这东西让八爪鱼和火车头去试试看?
Hawk最大的价值,是将复杂的逻辑链条化和可视化了,你可以将代码变得不那么耦合,像搭积木一样方便地组合。当然这些都拜于函数式编程的思想所赐。
再说缺点:Hawk有很多的bug,没单元测试,功能不完善。但这都不是最根本的缺点,最根本是难于实现条件判断和循环,你很难写出if,switch和while。 这也是函数式语言的共同问题,你不得不逼迫自己用另外的思路去解决。虽然通过引入子任务,能“不够优雅”地解决它,但依旧要花费不少脑筋。
有的人觉得Hawk不够强,这是因为它是图形化软件。为什么具备UI的软件很难和命令行相比?因为设计UI的新功能时,不仅需要考虑它的算法,更要考虑它如何在UI上呈现。有些功能非常有用,比如爬虫常见的BFS和DFS(深度和广度优先遍历),但在UI上配置会异常繁琐,我不得不将它们抛弃掉,只保留最常用的功能。
为什么呢?轻松写BFS的人,会想用Hawk吗?应该不会,他们也许会直接敲代码。
Python版本的Hawk: etlpy
因为图形界面和C#本身的诸多不足,我开始发展了Python的Hawk,称为etlpy (Extract-Transform-Load in Python)
最初的想法,是将Hawk生成的配置文件(xml)交给etlpy去执行,初看很酷,但这种思路被证明不靠谱,两种语言,使用不同类库,对同一个任务流,就因为在底层的细微偏差,会导致结果的完全不同。我花了大量的时间在解决兼容性问题上,发现难度不小,两者互相制约牵绊。
最终,我放弃了所谓的兼容性,之后etlpy功能日新月异,甩了Hawk有10条街不止。Hawk的5分钟拖拽,在etlpy上只要一句话:
url='www.cnblogs.com/p{0}'
t=task().let('p').range('1:20').format(url).detect().let('dignum').split('_')[0].num().write('cnblogs.json')
介绍etlpy的语法超过了本文的范畴,但它拥有Hawk的一切优点,同时能够分布式并行抓取,任务队列,超级代理,定时更新,与任意函数库集成。执行引擎(etlpy)的全部源代码,也就1000行出头。
也许你都没有听过Lisp这门语言,不过没有关系:Hawk是用C#写的,手敲的代码大概有1万行,用Python大概是1000行左右,用Lisp只要300行就能实现它的全部功能!当然,没有图形界面。由此可见编程语言在表现力上的巨大差别。Hawk本质上是个可视化的Lisp设计器。
我喜欢语言的纯粹和精妙,用简洁的语法就能代表复杂的逻辑。Hawk其实定义了一种爬虫语言,对诸多常用操作进行了模块抽象,在拖拖拽拽中,你构建了一张图(Graph),数据在图上流动,被生成,清洗和消费。最近大热的Tensorflow不也是一样的思路吗? 这张图,既是数据,也是代码。
当然,不论是Hawk和etlpy,你都不能把它们当成厨子,给它指令,就能做出一道菜来。而应当成一套顺手的厨具,而真正做菜的那个人还是你。自动化只是解决了部分问题,而巧妙设计的源泉还是来自于操作者本人。最强大的工具,是自己。
我们用语言表达概念,模式和流程,在此之上构建抽象。我假定每个用Hawk的人都能触类旁通,因此通过一些通用的介绍,他应该就能理解绝大多数的功能。那如果还是不懂呢?那不好意思,请用八爪鱼,否则Hawk的很多设计,对他来说就变得没有意义。我自己从来不愿意把Hawk和etlpy定义为爬虫,它们提供的是一组环境,语言和工具,爬虫只是它的一个不错的应用场景而已。
为什么要开源?
有人肯定会问,为什么不把Hawk商业化,去赚一笔钱呢?
理想状态下,成立公司去完善推广和销售软件,那么应该行得通,否则单枪匹马是不可能的。那我是不是值得为这套软件成立公司呢?应该不会,因为它只是个工具,还不值得我去开一家公司去完善它。
我相信,这也是很多程序员面临的类似困境,想靠卖软件盈利,就像路上的煎饼摊一样简单朴素,问题是放在10年前还有可能(记不记得30元一套的金山词霸?)而服务化盛行的今天,可能很低。到处推广,最终只可能沦为某天我在咖啡厅里的几句谈资,不可能有什么大气候。
有朋友说,为什么你要开源,对自己来说是不是有点像代码外泄?谷歌的TensorFlow都开源了。前面的路还有很远,大家都要忙着赶路呢。保护代码最好的方式就是开源,没开源时有人还想着破解研究,开源了大家fork一下然后就没有然后了,“得不到的才是最好的”。
不得不说,开源才是最贵的。大家看到开源,欢欣雀跃,以为在路上捡到了钱,其实不是的,如果你真想用起来,一定会花更多的时间来学习它,因为开源者没有义务像商业软件那样,提供完整的支持。时间和钱总是矛盾的,既想省钱还想省时间,天下没有这样的好事。
我以前天真地以为,开源的全部就是把源代码公开在网上。之后难道不是理所应当的声望,一帮牛人帮你优化功能修复bug吗?
哈哈,开源怎么可能那么简单。
如果软件写得不错,但没有宣传,那挂在网上完全无人问津,没人知道那是什么鬼;写得足够好,宣传也到位,那也很难有人帮忙贡献开发: 往上看,大神们都忙着造轮子;往下看一大帮实用主义者,抄起轮子就上路,谁顾得上看轮子是不是圆的呢?
开源不意味着坐视不管,依旧需要大量的精力去培养完善它和它的社区环境,通过邮件和论坛方式提供一定的服务。这件事情如果不用心,则一事无成。
如果pandas和ipython不开源,我现在也可能无法进入数据分析的殿堂,没有Linux和众多开源工具,世界也不会发展成这个样子。我明白了为什么开源是一种哲学,它是一种“共赢”。对程序员来说,名誉和成长比卖软件带来的价值更大,那是认可感和成就感。对其他人来说,开源带来了时间的节省和实际的财富。这样做必然是有价值的。
你肯定会问,那为什么etlpy后来不更新了?
第一它不稳定,现在释放出来可能砸招牌。其次,如果释放出etlpy,能量和Hawk完全不是一个数量级,它可能会让网站变本加厉地防爬虫。
请理性使用爬虫
开发完Hawk的那段时间,我也和很多人一样,看到一个网站就想去试试。以我的熟练程度,20分钟数据就都被下载下来了。然而数据保存在硬盘上,几乎不产生价值。
Google的工程师,可以下载它的全部源代码。可是为什么没有另外一家Google,甚至另外一家百度(又黑了百度)出现呢? 因为更重要的是人才,资源和商业模式,代码在这件事情中最不重要了。拿到源代码都没用,更遑论挂在网上供大众阅读的数据呢?
爬虫是灰色区域,所以大公司从来不公布任何爬虫框架,但内部用的比谁都多。两年以来,网络发生了巨大的变化,ajax化,SEO变成了关键词广告位,大量的网站开始强硬地反爬虫,之前能随便抓取的网站,现在都变得很困难。我相信这里有相当一部分是Hawk的功劳。让人郁闷的是,不少人抓数据仅仅用来玩。
可以想象,一小部分标榜大数据和AI的公司,把Hawk的代码弄下来改改,添一点数据报表功能,就可以盗走别人网站数据,自立门户,去到处忽悠。虽然Hawk开源协议是GPL(使用开源代码的必须开源),但这完全限制不了,毕竟是中国嘛。可能他们不知道,数据,工具和算法根本不值钱,理解,洞见和执行才是最重要的,可是这部分却需要真刀真枪的本事。
总之,稍微理性一些,适可而止吧。
为什么不继续优化?
很简单,因为没有时间。爬虫本身没太多技术含量,再深入就进入了异构Web数据集成的领域,大部分人根本用不到。这是个拥有数不清trick和dirty技巧的领域,是与网站设计者的攻防战争,玩到最后,你的能力曲线就像log函数一样,被压制在一个确定的上界。
现在是人工智能和深度学习的天下,以我所在的团队为例,身边的大神们都在努力地优化Tensorflow,改造算法的底层来提升效率,在有趣的数据集上做大规模并行训练。
几年之前,如果我没有去做爬虫和Hawk,没有去设计正则解析器tnpy,而是紧跟潮流去做大规模机器学习的话,眼界和身价可能就完全不一样了呢?
当然,我不后悔去做Hawk,它是实实在在的能让大众用起来东西。或许在万里之外,有个一样戴着眼镜充满激情的和我一样的nerd,看到我的代码开心地拍了桌子,大喊“f**king nice work!”到那个时候,其他事情还重要么?
如果说我后悔没做什么,是我没有把软件做成英文,曾经有一段时间我个人非常崇尚中文编程,从而酿成了现在软件国际化异常困难的后果;再者,没有直接开发Python或者js这种能跨平台语言的版本,Hawk只能局限于Windows桌面应用,而不同的社群就风气又不一样了。
它的设计有不少问题,不过更多来自于多种因素的妥协。它注定是不完美的。因为职业生涯的关系,我无法像前几年那样,花大把的时间去优化它。既然开源了,我希望有人能把它做得更好。
其实还是个程序员
我之前从来没想过自己会成为一名程序员。
高中时候理科不错,语文巨差。高考完,老妈扯着嗓子问我,报哪所学校什么专业吧? 正在打游戏的我根本无暇顾及,不耐烦地说,随便你们吧! 糊里糊涂地进了通信工程,几年后通信稍显疲软,就自学计算机,然后一点都不偶然地成了一名程序员。
网上黑程序员的段子太多了。我都一笑而过。但最近几年我坚决不买任何尺寸和颜色的格子衫。如果看到我穿,好吧,那一定是我本科时候买的。
你知道那帮每天不苟言笑,整天盯着显示屏的怪人每天在想什么吗?
也许看“沙漠之鹰”能稍微解决一下这个问题吧。不过,敲完这些文字的时候,九点半我还在杭州的酒店里睡眼惺忪,谁让昨天夜里11点才回来的呢?
总之,欢迎使用Hawk,欢迎和我交流有关它的各种问题和建议。
设计爬虫Hawk背后的故事的更多相关文章
- 终于等到你: 图形化开源爬虫Hawk 3发布!
超级图形化爬虫Hawk已经发布两年半时间了,2015年升级到第二版,收到上千条用户反馈(tucao),100多个红包,总共666块五毛~一直想攒着这笔钱,去北境之王天通苑的龙德商场买最心爱的阿迪王! ...
- 120项改进:开源超级爬虫Hawk 2.0 重磅发布!
沙漠君在历时半年,修改无数bug,更新一票新功能后,在今天隆重推出最新改进的超级爬虫Hawk 2.0! 啥?你不知道Hawk干吗用的? 这是采集数据的挖掘机,网络猎杀的重狙!半年多以前,沙漠君写了一篇 ...
- DbUtility v3 背后的故事
DbUtility v3 背后的故事 时间 DbUtility v3构思了差不多大半年,真正开发到第一个版本发布到NuGet却只花了50天.中途大量时间在完善 Jumony 3,只有三周来开发DbUt ...
- Mac OS X 背后的故事
Mac OS X 背后的故事 作者: 王越 来源: <程序员> 发布时间: 2013-01-22 10:55 阅读: 25840 次 推荐: 49 原文链接 [收藏] ...
- 联想手机#P1来了#P1背后的故事系列
http://bbs.lenovo.com/forum.php?mod=viewthread&fid=928&tid=560992&extra=page%3D1 联想手机#P1 ...
- 你好,C++(4)2.1.3 我的父亲母亲:编译器和链接器 2.1.4 C++程序执行背后的故事
2.1.3 我的父亲母亲:编译器和链接器 从表面上看,我是由Visual Studio创建的,而实际上,真正负责编译源代码创建生成可执行程序HelloWorld.exe的却是Visual Studi ...
- 腾讯技术分享:微信小程序音视频技术背后的故事
1.引言 微信小程序自2017年1月9日正式对外公布以来,越来越受到关注和重视,小程序上的各种技术体验也越来越丰富.而音视频作为高速移动网络时代下增长最快的应用形式之一,在微信小程序中也当然不能错过. ...
- Flappy Bird背后的故事
更多有价值的互联网文章:晓煦分享(http://www.ihuxu.com/share) 由越南游戏工程师阮哈东(Nguyen Ha Dong)开发的Flappy Bird这款游戏,画面不算精致且看起 ...
- 更好的 java 重试框架 sisyphus 背后的故事
sisyphus 综合了 spring-retry 和 gauva-retrying 的优势,使用起来也非常灵活. 今天,让我们一起看一下西西弗斯背后的故事. 情景导入 简单的需求 产品经理:实现一个 ...
随机推荐
- Python编码记录
字节流和字符串 当使用Python定义一个字符串时,实际会存储一个字节串: "abc"--[97][98][99] python2.x默认会把所有的字符串当做ASCII码来对待,但 ...
- excel 日期/数字格式不生效需要但双击才会生效的解决办法
原因: Excel2007设置过单元格格式后,并不能立即生效必须挨个双击单元格,才能生效.数据行很多.效率太低. 原因:主要是一些从网上拷贝过来的日期或数字excel默认为文本格式或特殊-中文数字格式 ...
- Hyper-V3:虚拟机的配置
在Hyper-V成功新建一台虚拟机,在正式使用之前,必须配置VM使用的硬件资源,并授予用户访问VM的权限等,本文罗列出一些常见的配置,供读者参阅. 一,为虚拟机分配使用的内存 在Hyper-V Man ...
- OpenCASCADE BRep Projection
OpenCASCADE BRep Projection eryar@163.com 一网友发邮件问我下图所示的效果如何在OpenCASCADE中实现,我的想法是先构造出螺旋线,再将螺旋线投影到面上. ...
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(75)-微信公众平台开发-用户管理
系列目录 前言 本节主要是关注者(即用户)和用户组的管理,微信公众号提供了用户和用户组的管理,我们可以在微信公众号官方里面进行操作,添加备注和标签,以及移动用户组别,同时,微信公众号也提供了相应的接口 ...
- python与c互相调用
虽然python开发效率很高,但作为脚本语言,其性能不高,所以为了兼顾开发效率和性能,通常把性能要求高的模块用c或c++来实现或者在c或c++中运行python脚本来处理逻辑,前者通常是python中 ...
- pandas基础-Python3
未完 for examples: example 1: # Code based on Python 3.x # _*_ coding: utf-8 _*_ # __Author: "LEM ...
- 使用Git Bash远程添加分支和简单部署你的静态页面
新建一个分支:git branch mybranch(mybranch你的分支名字) 切换到你的新分支: git checkout mybranch 将新分支发布在github上: git push ...
- Java虚拟机 JVM
finalize();(不建议使用,代价高,不确定性大) 如果你在一个类中覆写了finalize()方法, 那么你可以在第一次被GC的时候,挽救一个你想挽救的对象,让其不被回收,但只能挽救一次. GC ...
- iOS开源项目周报1215
由OpenDigg 出品的iOS开源项目周报第一期来啦.我们的iOS开源周报集合了OpenDigg一周来新收录的优质的iOS开发方面的开源项目,方便iOS开发人员便捷的找到自己需要的项目工具等. PY ...