高效地提取网页数据(一)

作者:jcmp      发布时间:2021-05-10      浏览量:1
知乎代码渲染有些瞎眼,可查看原文(

知乎代码渲染有些瞎眼,可查看原文( Efficient Scraper - 李晨曦的博客 | Hexi Blog )。

前几个月打算开个爬虫的坑,然后开出了一坨新坑。

其实最早的坑很容易: 拿到 HTML -> 解析 HTML ,但总觉得前人的做法过于原始,要糊一堆模板代码。于是我构思了一下,我只要能做到这两件事,就能高效地完成我的工作。

目前来看,最接近我第一个需求的项目就是 retrofit ,而能满足第二个需求的好像并找不到。

找不到就只能自己造咯,由于最早不想写 Java ,我两个月前造出了 unhtml (见 上一篇文章 )和 gotten 。

unhtml 就不多介绍了, gotten 大概用法如下。

用起来还不错,我用它写了个练手项目 box-go-sdk 。但总觉得 API 不是很优美而且有额外的运行时开销,于是我又糊出了 http-service ,大概这么用:

先安装 go get github.com/rady-io/http-service ,然后确保它在 PATH 里再:

再执行 go generate ,然后同目录下就会出现 service_impl.go 文件,里面有个 serviceImpl 结构体和 NewService 方法,直接拿来用就好了。

看起来挺优雅的,我又糊了个练手项目 box-go-sdk-v2 。

但毕竟 go 没有 annotation 更没有 annotation processor ,解析注释也不过是旁门左道。

“还是去写 Java 吧” —— 我发出了真香的声音。

当然并不能就这样向 Java 屈服,我选择了写 Kotlin 。然后我糊出了 unhtml.kt 。

这个专门给 Kotlin data class 用的 HTML Deserializer ,由于比较屎我近期不打算维护/重写所以我没有给文档也没有上传到任何一个包仓库。这里给个例子,感兴趣的人可以去看 test。

1、所以我说它屎到底屎在哪儿呢?

主要问题是泛型擦除,其次是基础类型的封装类没有实现同一个 FromString 之类的 interface ,我得一个个特判并用相应的 String.toXXX 方法(这个问题在 go 里面更严重)。

第一个问题貌似可以用 annotation processor 解决 ,但我不是很喜欢那个接口而且 —— 既然要代码生成我为什么不写宏呢?

于是就有了 unhtml.rs ,这个项目用起来大概是这样:

这个不管从结果和实现上来说都比较让我满意。主要是 rust 给所有的 buildin type 实现了 FromStr ,并且支持包外 impl trait 。过程宏现在也 stable 了,还有逐渐 stable 的 nll (不过貌似没人关心它是不是 stable),非常稳。

先说这么多吧, rust 的 http client 还有一坨坑等着踩呢......