当我们说到爬虫时我们在说什么呢(上)
当我们说到爬虫时我们在说什么呢?Spider?Robots?Python?网络协议?黑产?
上边都可能会说到吧,但是我觉得这些都是表层现象,没有触及现代爬虫技术的核心。我认为爬虫的核心在于
- 调度框架,包括但不限于任务发现、去重和重试,延时调度,补偿机制,分布式多队列等等
- 逆向工程,包括但不限于抓包分析,反编译,插桩,动态调试等等
- 反爬对策,这个就是让你去对抗一个团队(笑
个人认为以上三项的麻烦(e xin)程度依次递增
我们先看下最简单的调度框架,和比较简单的逆向工程,下一篇中在看下最麻烦的反爬对策(注意这里的最麻烦不是技术上最困难)
调度框架
分布式多队列在技术实现上当然不能说非常简单,但这个真心是最可控的部分了,只需要提升自己技术实力即可,不行还可以改嘛
这里我不会讨论具体的技术实现,只是泛泛的谈下
任务发现、去重和重试
调度框架的基本能力,举个栗子
- 在爬到一个文章列表时,需要将每个链接提交队列;这个队列在框架层面必须是易于操作的
- 假设一个文章任务已经提交过了,或者在一定时间内不想抓取第二次;这就需要去重,而这时最好是由框架基于配置自动完成(当然这里去重不需要特别精确,一个任务就算多爬几次也不会有太大问题)
- 文章任务在执行过程中因为外部因素或者结果错误失败了;这时需要重试,重试是必须而且非常重要的,框架必须能提供灵活的重试方案,比如:直接重试、一定次数后结束、递进的延时重试等
延时调度和持久化
大部分的爬虫任务都不会在添加时立刻执行,通常会间隔一定时间,通常要满足以下几点
- 代码层面提交的任务延时
- 周期性任务,这里是指每天定点抓文章列表
- 延时任务持久化,确保不丢失
- 最好给每个任务一个唯一id,队列里只有这个id,方便之后的补偿
说下持久化,还是举个栗子
- 延时任务不能仅存在于内存,必须持久化,哪怕延时再短甚至不延时;这要求任务必须是易于序列化的
- 在分布式场景下,每个worker都会自己的负载内,拉取在30s內要执行的任务到自己内存,来确保任务按时执行;如果此时worker正常关闭要注意任务的add back
补偿机制
任务会以你想像不到的方式丢失,做好业务上补偿机制。下面列举几个常见的任务丢失原因
- 处理过程异常导致add back未执行
- 远端异常导致add back失败
- 去重机制导致add back失效
- worker被杀导致拉取任务未及时add back
兼容性处理
- 当HTML上没有想要的东西时,妥善处理
- 强类型语言不需要相信JSON里的数字
- 能妥善处理掉JSONP
- 注意重定向
- 注意超时时间
逆向工程
逆向是一个很宽泛同时技术要求上限很高的地方(相信我有手就行),而且吃力不讨好、巨费神、加剧脱发
这里同样泛泛的谈下
抓包
好吧抓包看起来人人都会,下个软件、设置个代理嘛,有手就行
但事实是很多APP你根本抓不到包,这个时候你只能求助hook了,具体情况具体分析
- SPDY这个已经被放弃的协议
- JustTrustMe可以解决的SSL Pinning
- JustTrustMe不能解决的SSL Pinning
反编译
这个是不是看起来很高大上(并不,常用的工具就那么几种,解决的问题很有限
- PC上用好浏览器调试
- APP可以使用jadx之类的
浏览器调试在一定程度上确实是神器,断点步进都方便;但是在特别复杂的JS上需要耐心,而且乱七八糟的跳转容易看晕
jadx是用来反编译apk的,但是可能会有很多代码出不来,推荐加上–show-bad-code
插桩
插桩应该是我的误用,换成hook(🐶
- PC端去替换js
- APP端使用xposed或frida
替换js比浏览器调试简单粗暴非常多,但也是真的好用,追踪打印日志,能大幅缩短分析时间
frida是极力推荐的hook工具,简单易用,语法不复杂,支持命令行,注意下attach和spawn
动态调试
到这里你真的要上IDA了,咱也不熟
这里一般都到了公司的核心资产了,你通常是处理APP里so里混淆的签名或加密算法,但通常是无解的,你需要买买买或者使用迂回手段
逆向总结
所以逆向是干什么的呢?
它是一种找漏洞的手段,就跟你去扫肉鸡一样
为什么爬虫行业有很多看上去很魔法的产品?
因为人家深入扫了对方的产品(大部分网页、大部分APP甚至小程序)
大家要知道,一个大团队也是慢慢发展起来,但在初期可能会很挫(暴漏了不该有的数据、未做权限校验等),而你的机会就在很挫的这部分