上次写过爬虫的初篇,我们已经能爬到基本的数据了。但是一张网页的数据是有限的,从我们上次的程序来看,能抓到的图片才不过十来张。很显然不能满足我们的需求。
接下来,我们继续完善我们的项目,来满足这个需求吧。
必备工具
- 联接网络的Mac,
- 浏览器,推荐用Google Chrome,
- Xcode开发工具,
- 用Objective-C写一个简单的爬虫(一) 的源码
必备技能
建议看完 用Objective-C写一个简单的爬虫(一) ,明白一些简单的知识,虽然我写的很烂,但也不至于看这篇文章的时候一头雾水。
本篇目标
深度抓取更多的数据
如图:
分析
在上篇中,我们给定一个url
抓取完图片之后直接就结束了,那么如何不让程序结束,而继续抓取别的ur
呢?总不能给SpiderOption
定义一个url
数组,程序的输入是有限的,这种办法解决不了问题。聪明的你一定想到了,在爬虫爬取图片的时候,不也是可以爬到这个页面的跳转页面么,如果我们在把跳转页面的图片爬下来,甚至把跳转页面里面的跳转页面爬下来,这样一直往深层次的抓取数据,就不是源源不断的图片爬到手了么?😎下面我们就开始吧!!!
编码
准备
首先我们改造一下Spider
类,给Spider
添加几个变量:
1、_finashUrl
用来存放已经爬取过的url
,防止重复抓取,导致重复循环。
2、_session
用来进行获取html
的网络请求;在第一篇中我们直接在方法里面定义了相同的变量,这里我们把它声明成变量,防止重复创建对象.
3、_urlExpression
用来匹配url
的正则表达式.
4、_imgExpression
用来匹配img
的正则表达式.
5、fetchHtmlQueue
正则匹配的队列.
6、operationQueue
网络请求的队列.
定义上面变量之后并且在init
方法中初始化:
1 | @interface Spider()<NSURLSessionDataDelegate> |
改写方法
由于我们用了多线程的技术,每次加载一个url
都要放到队列去,所以我们需要修改一下loadUrl
方法:
1 | - (void)loadUrl:(NSURL*)url{ |
上一步请求成功之后,会调用session
的代理方法,所有我们需要实现session
的代理方法:
1 | ///MARK:- NSURLSessionDataDelegate |
我们在修改一下fetchImgWithHtml
方法,匹配img
也要放到队列里,匹配成功后回调即可:
1 | - (void)fetchImgWithHtml:(NSString*)html{ |
同理我们修改fetchUrlWithHtml
方法,并且把需要请求的url
放到_finashUrl
里面,在请求之前判断一下是否请求过即可:
1 | - (void)fetchUrlWithHtml:(NSString*)html{ |
最后附上fetchStringsWithHtml
方法:
1 | - (NSArray<NSString*>*)fetchStringsWithHtml:(NSString*)html |
运行
接下来运行一下程序,我们能看到程序不停的抓取图片,越来越多。
可视化
为了更好的浏览我们获取的图片,我们需要在控制器里面用UICollectionView
展现出来,直接上代码:
1 |
|
至此,我们就算完成了我们的目标;看到程序不停的有图片加载出来,是不是有点小兴奋呢。😄
现在我们写的程序会无限循环的爬取,但是怎么能控制爬取深度呢?
控制深度
我的做法是给url
创建一个分类,添加一个属性depth
表示此url
的深度值,初始的url
深度为0,在此页面上爬取的url
深度为1,这样以此类推,直到我们指定深度停止为止。
NSURL+depth.h
1 | @interface NSURL (depth) |
NSURL+depth.m
1 |
|
然后在我们的 start
方法里面给第一个url
的深度赋值:
1 | - (void)start{ |
在session
回调的方法里面我们判断一下此url
的深度是否需要继续爬取:
1 | - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data{ |
然后改下fetchUrlWithHtml
方法,给下个url
赋值深度:
1 | - (void)fetchUrlWithHtml:(NSString*)html depth:(NSUInteger)depth{ |
ok,在控制器里面给定最大的深度,最好不要太大,运行一下吧!!!
相关链接: