一面结束,总结爬虫的一些小问题,抛砖引玉

2016-04-18 15:59:51 +08:00
 hxndg

上午去面试了腾讯,然后问到了爬虫的问题,结果很多都想不起来了。所以写个帖子总结有关爬虫的种种问题,顺便也方便些其他找实习的同学,第一次笔试没想到会拿到面试,已经很好运了,再攒攒人品。

A 假设,要写一个爬虫,抓取新浪网的数据,那么需要怎样设计?

B 新浪网本身肯定是防爬虫的,那么常见防爬虫的方式有哪些?

C 如果使用 hash 来保证不会出现重复爬取的 url ,如果出现了 hash 碰撞的情况怎么办?

  • 针对问题B,常见网站防止爬虫的基本思路就是爬虫在某些方面比人强,某些方面比人差,因此,如果某些访问请求访问的频率大于某个阈值时,我就可以使用验证码来判断请求发起者是不是人,这一点我用 ss 翻墙的时候经常遇见 google 这么干,当然有的简单验证码是可以通过 python 一个光学识别的包来通过的,北邮教务处登录的验证码就属于这种比较弱的验证码,这种方法最直接的想法是降低请求频率。

针对问题A,首先估测新浪网的数据量,假设每天产生 1000 条新闻,那么单是新闻就是 1000365 条的量,打开新浪可以看到光是分站就是 60 个,整个新浪的 url 量就是 1000365 (天)60 (个分站)15 (年)=4.38*10^8 ,这里我忘了我是什么时候用的新浪,姑且从 2000 年开始计算,认为是 16 年,为方便计算认为是 15 年。新浪的数据只会比它多,而不会比它多,而不会比它少。为此直接的想法时使用多线程爬虫,多个爬虫同时爬取,除了使用多线程还可以使用分布式的大型爬虫,只有这个样子才可能爬完这么多( orz ),然而新浪必然有自己的频率反爬虫机制,因此我们的爬虫还得使用代理(也得限制频率),随着一段时间更换一个代理,降低爬虫被封的危险。 现在又有另外一个问题,我今天爬了一次新浪,存了数据,过了几天接着爬,还要再重新爬取一遍么? http 协议里我记得有个字段是 If-Modified-Since ,同样可以利用这已经缓存过的 url 网址是否改变过,改变了我们再从新爬去,没改变就不用从新爬取了。 会有这种问题,不同平台的爬虫可能会爬取同一个链解,造成资源的浪费,怎么办。这点我想的是某个爬虫必须自己保存已经访问过的 url 网址,同时还得有一个总的索引来保存所有已经访问过 url 网址,这点我直接想到的答案有点类似 dns 轮询了, master 爬虫靠 slave 爬虫爬取不同分站的 url ,当遇到其他分站的 url 时,不去访问,遇到同一个分站的时候先问 master 哪个主机可能存储了这个信息, master 给出另一台 slave 地址,然后我直接去问你访问了没?同时为了节省空间,每个爬虫直接存储 url 的 hash 值,而不是 url 网址。当然这个东西直接引出了问题 C

针对问题C,不同爬虫保存 hash 值,可能会遇见 hash 碰撞的情况,怎样应对这种情况呢?直接想法是在增加存储的信息,考虑的是我如果把 url 和 hash 值存到一起,那我不如直接存 url 呢,所以这个问题我没想到特别好的答案,个人比较觉得中意的想法类似给 url 每个字母在不同位置算加权,构成一个 hash 链,但是也觉得不是很好,这个确实没想到好的答案。期待大神的回复

发现面试还是有点喜欢问你在数据量大的思想下解决问题的能力,所以平时写程序时还是要跳开来看问题,不要被局限。

2393 次点击
所在节点    Python
35 条回复
feather12315
2016-04-18 21:12:41 +08:00
@murmur 我不知道为什么, github 上找到一 Sina 爬虫代码,已经运行了 3 天了,速度没降,没有收到任何跳转提示。(使用固定不变的 cookie , 12h 重新登录一次。没这样做以前会出现跳转。)
SlipStupig
2016-04-18 21:42:59 +08:00
我就不明白现在的人动不动就说 MD5,sha 容易发生碰撞, md5 和 sha 的碰撞率几乎正常情况下有生之年是遇不到,到底有没了解过 MD5 这类算法
@mornlight
murmur
2016-04-18 21:46:47 +08:00
@SlipStupig 问题 bloomfilter 是 hash 到位点上的。。撞起来不要太容易
SlipStupig
2016-04-18 21:54:40 +08:00
@murmur 我说 md5 你跟我说 bloom
murmur
2016-04-18 22:01:42 +08:00
@SlipStupig 这页我就没看到 md5 和 sha
firefox12
2016-04-18 22:36:51 +08:00
md5 的问题 不是碰撞 是存储 md5 值的空间太大
decaywood
2016-04-18 22:45:09 +08:00
分布式爬虫对于重复 url 我觉得可以这样:单独弄一个 url 收集服务器或进程称 A ,当各 slave 准备爬取某网页时都先调用 A 的 API 确认一下是否有重复,如果没有, A 将次 url 建立索引返回成功响应,否则失败。这样就省去了每个爬虫 hash 都存一份,且由于是网络 IO 密集型,对爬取速度影响不大。同时减少了同步负担。至于 url 的索引,直接内存数据库解决就行了,简单粗暴。
leoguo1314
2016-04-18 22:52:17 +08:00
可以马克吗?我是一个马克
binux
2016-04-18 23:07:42 +08:00
布隆过滤器不能解决碰撞,遇到 hash 碰撞,碰撞就碰撞了呗。有得是其他原因会导致你一个页面抓取失败的,不差碰撞这一个。
sicklife
2016-04-18 23:44:56 +08:00
同意 @binux
redis 有针对碰撞的解决方案, http://www.lai18.com/content/1400608.html , 所以,比较简单的方法,就是使用 redis ,不要自己造轮子。
5qwang
2016-04-19 07:46:20 +08:00
@feather12315 有具体 github 的网址吗?谢谢
feather12315
2016-04-19 08:03:22 +08:00
est
2016-04-19 09:05:53 +08:00
@binux 然后 B 大你去腾讯面,一样会跪。
ytmsdy
2016-04-19 10:23:44 +08:00
对 HASH 的问题比较有疑惑,碰到这样的问题,直接鸵鸟就好了。按照 HASH 的算法,碰撞的概率也是很小很小的。就算真的碰到了,直接忽略掉就好了。比如说在 1 亿条数据里面,万一碰到个十条八条的碰撞,这样的差错概率也是可以忍受的。
binux
2016-04-19 16:56:56 +08:00
@est 腾讯爬虫并不一定比我有经验。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/272000

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX