本文写于圣诞节北京下午慵懒的午后。本文偏技术向,不过应该大部分人能看懂。

五年之痒

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背后的故事的更多相关文章

  1. 终于等到你: 图形化开源爬虫Hawk 3发布!

    超级图形化爬虫Hawk已经发布两年半时间了,2015年升级到第二版,收到上千条用户反馈(tucao),100多个红包,总共666块五毛~一直想攒着这笔钱,去北境之王天通苑的龙德商场买最心爱的阿迪王! ...

  2. 120项改进:开源超级爬虫Hawk 2.0 重磅发布!

    沙漠君在历时半年,修改无数bug,更新一票新功能后,在今天隆重推出最新改进的超级爬虫Hawk 2.0! 啥?你不知道Hawk干吗用的? 这是采集数据的挖掘机,网络猎杀的重狙!半年多以前,沙漠君写了一篇 ...

  3. DbUtility v3 背后的故事

    DbUtility v3 背后的故事 时间 DbUtility v3构思了差不多大半年,真正开发到第一个版本发布到NuGet却只花了50天.中途大量时间在完善 Jumony 3,只有三周来开发DbUt ...

  4. Mac OS X 背后的故事

    Mac OS X 背后的故事 作者: 王越  来源: <程序员>  发布时间: 2013-01-22 10:55  阅读: 25840 次  推荐: 49   原文链接   [收藏]   ...

  5. 联想手机#P1来了#P1背后的故事系列

    http://bbs.lenovo.com/forum.php?mod=viewthread&fid=928&tid=560992&extra=page%3D1 联想手机#P1 ...

  6. 你好,C++(4)2.1.3 我的父亲母亲:编译器和链接器 2.1.4 C++程序执行背后的故事

    2.1.3  我的父亲母亲:编译器和链接器 从表面上看,我是由Visual Studio创建的,而实际上,真正负责编译源代码创建生成可执行程序HelloWorld.exe的却是Visual Studi ...

  7. 腾讯技术分享:微信小程序音视频技术背后的故事

    1.引言 微信小程序自2017年1月9日正式对外公布以来,越来越受到关注和重视,小程序上的各种技术体验也越来越丰富.而音视频作为高速移动网络时代下增长最快的应用形式之一,在微信小程序中也当然不能错过. ...

  8. Flappy Bird背后的故事

    更多有价值的互联网文章:晓煦分享(http://www.ihuxu.com/share) 由越南游戏工程师阮哈东(Nguyen Ha Dong)开发的Flappy Bird这款游戏,画面不算精致且看起 ...

  9. 更好的 java 重试框架 sisyphus 背后的故事

    sisyphus 综合了 spring-retry 和 gauva-retrying 的优势,使用起来也非常灵活. 今天,让我们一起看一下西西弗斯背后的故事. 情景导入 简单的需求 产品经理:实现一个 ...

随机推荐

  1. Python编码记录

    字节流和字符串 当使用Python定义一个字符串时,实际会存储一个字节串: "abc"--[97][98][99] python2.x默认会把所有的字符串当做ASCII码来对待,但 ...

  2. excel 日期/数字格式不生效需要但双击才会生效的解决办法

    原因: Excel2007设置过单元格格式后,并不能立即生效必须挨个双击单元格,才能生效.数据行很多.效率太低. 原因:主要是一些从网上拷贝过来的日期或数字excel默认为文本格式或特殊-中文数字格式 ...

  3. Hyper-V3:虚拟机的配置

    在Hyper-V成功新建一台虚拟机,在正式使用之前,必须配置VM使用的硬件资源,并授予用户访问VM的权限等,本文罗列出一些常见的配置,供读者参阅. 一,为虚拟机分配使用的内存 在Hyper-V Man ...

  4. OpenCASCADE BRep Projection

    OpenCASCADE BRep Projection eryar@163.com 一网友发邮件问我下图所示的效果如何在OpenCASCADE中实现,我的想法是先构造出螺旋线,再将螺旋线投影到面上. ...

  5. ASP.NET MVC5+EF6+EasyUI 后台管理系统(75)-微信公众平台开发-用户管理

    系列目录 前言 本节主要是关注者(即用户)和用户组的管理,微信公众号提供了用户和用户组的管理,我们可以在微信公众号官方里面进行操作,添加备注和标签,以及移动用户组别,同时,微信公众号也提供了相应的接口 ...

  6. python与c互相调用

    虽然python开发效率很高,但作为脚本语言,其性能不高,所以为了兼顾开发效率和性能,通常把性能要求高的模块用c或c++来实现或者在c或c++中运行python脚本来处理逻辑,前者通常是python中 ...

  7. pandas基础-Python3

    未完 for examples: example 1: # Code based on Python 3.x # _*_ coding: utf-8 _*_ # __Author: "LEM ...

  8. 使用Git Bash远程添加分支和简单部署你的静态页面

    新建一个分支:git branch mybranch(mybranch你的分支名字) 切换到你的新分支: git checkout mybranch 将新分支发布在github上: git push ...

  9. Java虚拟机 JVM

    finalize();(不建议使用,代价高,不确定性大) 如果你在一个类中覆写了finalize()方法, 那么你可以在第一次被GC的时候,挽救一个你想挽救的对象,让其不被回收,但只能挽救一次. GC ...

  10. iOS开源项目周报1215

    由OpenDigg 出品的iOS开源项目周报第一期来啦.我们的iOS开源周报集合了OpenDigg一周来新收录的优质的iOS开发方面的开源项目,方便iOS开发人员便捷的找到自己需要的项目工具等. PY ...