刚刚写了一个爬虫,尝试读取豆瓣电影的评价及相关信息,并下载电影的一个海报图片,因为我自己的电脑是双核,所以,为了提高效率,利用cluster开了两个进程来跑,效率还可以,其中遇到了几个问题:
1、是关于链接地址的问题,因为之前没有写过类似的程序,所以没思路,当时我有两种想法(包括现在).第一种就是固定住一个链接地址,然后不听的变换页面的id,比如:http://movie.douban.com/subject/10485647/
每次只要替换掉id就可以了,但是这样的话,貌似效率不高,所以我舍弃了这种方法。第二种方法就是以一个固定的链接地址作为程序的入口,在读取完该页面的信息之后,再查找这个页面的所有的链接,找到有跟当前页面一样的链接,然后存入一个数组,接着循环爬这些地址页面,这样,避免了猜测链接地址和不必要的请求,但是带来的问题是因为每个页面的链接数不定,所以每爬到一个页面,盛放链接地址的数组就会增加很多,最终导致这个数组无限大,而内存又有点不够用了,所以这里不知道大家有没有什么好的想法。
2、关于访问受限的问题,因为知道很多网站为了防止爬虫爬取,如果发先在短时间内有大量的来自于同一ip的请求的话,这时该网站一般都是禁止ip访问。我这里的做法是每次请求都去换useragent,来达到尽量模仿浏览器行为的目的。其次是每次请求的时候都去伪造ip,这个伪造ip的方法就是在request的header里面加入x-forward-for属性,其实这么做完全是寄希望于对方的网站在做ip检查时的bug。其实如果还是担心ip被禁止的话,还可以限制爬取的频率,即多长时间发送一次请求,但这又在一定程度上影响了效率。在这里也想问问大家,在这个问题上都是怎么处理的。
3、遇到的地三个问题,可能是因为我没有做请求频率的限制,即同一时间发送了很多的请求出去(如前所说,将所有链接存入数组,然后循环这个数组发送请求。但是却没有发现豆瓣封掉我的ip).加上每个请求都会下载该页面的电影的一张海报下来,所以必然导致了我的I/O开销的增大。以至于后来我发现程序报错:Error: connect EMFILE,这明显是因为系统文件最大连接数限制造成的。所以按照网上的说法,是改掉这个值。但是我觉得这不能从根本上解决问题,所以,这里也想问问大家,这个问题应该如何解决。
4、综上:希望大家多多指点。
就一句,不要同时发送很多请求,最好是使用async来控制请求一个一个的处理,不要一股脑的全部发出去,
我也做过一个爬虫,https://github.com/dlutwuwei/CrawlerX ,可以设置并发请求数和爬网页的深度,首先没必要用cluster,nodejs,io是并发的,一个进程足够,处理返回的页面。网站防抓取都是通过IP地址,你也伪造不了,因为你改了源地址,ip包就返不回来了。
谢谢 @xiuxu123 @dlutwuwei 两位的回复,目前我的解决办法比较笨,要抓取的url直接硬编码了一个范围然后setTimeout 了两秒,每次请求动态修改了useragent和x-forward-for 目前还没有啥异常情况,两位的代码我再研究研究
更改IP可以用代理的。正常的过程是做一个agent pool 然后随机选用代理来发送请求。
当然如果有条件和网络能用Tor 那就更好了。 随机匿名P2P代理,不过天朝各种被封。
我记得scrapy建议2秒左右的抓取间隔。user-agent一般也都够用了,抓数据不用太效率吧,如果不是像知道创宇那种做网页安全性扫描需要对速度有要求的话,慢点抓,数据总会来的。何况知道创宇为了提高速度也是用代理池的方式来实现的,一方面保证速度,一方面不被封掉,那只能一直变换着ip来搞。 做的再深点的话,可以再写一个爬虫用来搜集代理,然后测试代理的可用性,然后动态筛选和维护代理池。
你可以用redis,抓取页面后分析的url放置到redis中,以集合的方式来存储在A中。
不想抓重复页面的话,redis中对抓过的url以集合的形式在B中做个记录就行了。每次抓到的url要存到redis中之前先查询一下B中是否有该url,如果没有的话则存入到A中。
每次从A中pop一个数据进行页面抓取
总之,如果仅仅为了抓豆瓣的一些影评神马的,你说的这些问题都不是大问题。
@wh1100717 好建议,谢谢