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

五年之痒

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. CSS的未来

    仅供参考 前言 完成<CSS核心技术与实战>这本书,已有一个多月了,而这篇文章原本是打算写在那本书里面的,但本章讲解的内容,毕竟属于CSS未来的范畴,而这一切都还不能够确定下来,所以这一章 ...

  2. ThreadLocal简单理解

    在java开源项目的代码中看到一个类里ThreadLocal的属性: private static ThreadLocal<Boolean> clientMode = new Thread ...

  3. Gradle配置APK自动签名完整流程

    转载请注明出处:http://www.cnblogs.com/LT5505/p/6256683.html 一.生成签名 1.命令行生成签名,输入命令keytool -genkey -v -keysto ...

  4. CSS3 3D立方体效果-transform也不过如此

    CSS3系列已经学习了一段时间了,第一篇文章写了一些css3的奇技淫巧,原文戳这里,还获得了较多网友的支持,在此谢过各位,你们的支持是我写文章最大的动力^_^. 那么这一篇文章呢,主要是通过一个3D立 ...

  5. MVC常遇见的几个场景代码分享

    本次主要分享几个场景的处理代码,有更好处理方式多多交流,相互促进进步:代码由来主要是这几天使用前端Ace框架做后台管理系统,这Ace是H5框架里面的控件效果挺多的,做兼容也很好,有点遗憾是控件效果基本 ...

  6. MongoDB集群配置

    本文演示:(一个主服务器,一个备份服务器,三个仲裁服务器) 官方推荐副本集的成员数量为奇数,最多12个副本集节点,最多7个节点参与选举. 本文演示基于本机,用端口区分服务(每个服务器下新建db文件夹用 ...

  7. Extjs 让combobox写起来更简单

    也已经写了很久时间的extjs ,每次都用到很多的combobox,配置很多东西觉得实在是太麻烦,所以根据常用到的情况写了一个简便的combobox,再次记录下来,以免放在某个地方忘记了找不到了. 定 ...

  8. Linux:将rhel yum 切换到centos yum

    Red Hat Enterprise Linux Server(RHEL) yum安装软件时This system is not registered with RHN. RHN support wi ...

  9. Win10连接远程桌面时提示“您的凭据不工作”

    我遇到这个问题的时候查找网上都给出一堆高大上的解决办法, 然而我的错误实际上是用户名的问题, 很多人以为远程用户名就一定是锁屏状态下的登录名, 其实不是,跟自己设置有关,所以首先应该检查远程用户名是否 ...

  10. 我的MYSQL学习心得(七) 查询

    我的MYSQL学习心得(七) 查询 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类 ...