写这个纯属个人爱好,前两天想玩爬虫,但是百度了一大圈也没发现有好一点的帖子,所以就自己研究了下,亲测小点的网站还是能随随便便爬完的
最新github地址:https://github.com/xietiansheng/spider-demo
(github为maven项目,拉取下来直接运行即可)
先上几张效果图
需要用到的知识点
- 网络请求(至于用哪个嘛,看个人喜好,文章用的是okhttp)
- File文件读写
- Jsoup框架(html解析器)
需要的jar包
注意:okhttp内部依赖okio,别忘了同时导入okio
难点
- 如图(随便弄了个草图)
- 要说技术难点的话,无非就是如何遍历整个网站了,首先,要考虑到的是抓取到一个链接后,这个链接里面肯定还有好几十甚至上百个链接,接下来这几十个链接里面又有链接,链接里面有链接一层一层嵌套,该如何去获取这些链接?
实现思路
-
1.链接存储
- 使用文件操作储存所有链接,至于为什么不用集合存储,这是由于集合有一定的大小限制,网站内容多容易导致内存溢出。所以不推荐使用集合进行储存。 2.链接读取
- 将每次读到的链接存入.txt文本文件中,这里要注意的是每次存入链接的时候要在后面加上\r\n(换行),也就是让每个链接各占一行,这样有利于后期以行的形式读取链接。 3.链接遍历
- ①、获取首页链接中的子链接,存入文件中,已行为单位存储。
- ②、定义一个变量num(默认为-1),用于记录当前读的是第几条链接,每次遍历完一条链接后 判断如果(num<链接文件行数 )则 num++。
- ③、遍历解析链接的方法,每一次遍历的目标链接等于 文件内的第num行
这样基本就实现了链接的遍历
举个栗子
假设index.html页面内有5个子链接分别对应 ae.html,解析index.html页面后将该页面中的5个链接存入文件中,num++(此时num=0),文件中的15行就分别对应这5个链接,第二次调用读取方法的时候用到的链接就是文件中的第num行,也就是a.html。
接着解析a.html,将a.html中的所有超链接追加进文件中。
上图:
图中的遍历方式似乎有点像一个横放着的wifi信号
接下来贴代码:
-
首先创建两个类
- HttpUtil.java (网络请求类,用于获取网页源代码)
- Spider.java (爬虫主代码)
HttpUtil.java 类
import java.io.IOException;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
import okhttp3.Call;
import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
/**
* Created by XieTiansheng on 2018/3/7.
*/
public class HttpUtil {
private static OkHttpClient okHttpClient;
private static int num = 0;
static{
okHttpClient = new OkHttpClient.Builder()
.readTimeout(1, TimeUnit.SECONDS)
.connectTimeout(1, TimeUnit.SECONDS)
.build();
}
public static String get(String path){
//创建连接客户端
Request request = new Request.Builder()
.url(path)
.build();
//创建"调用" 对象
Call call = okHttpClient.newCall(request);
try {
Response response = call.execute();//执行
if (response.isSuccessful()) {
return response.body().string();
}
} catch (IOException e) {
System.out.println("链接格式有误:"+path);
}
return null;
}
}
这个就不多写注释了 百度有一大堆okhttp教程
Spider.java 类
首先定义要爬的网站首页与储存链接的文件对象:
public static String path = "http://www.yada.com.cn/"; //雅达公司官网
public static int num = -1,sum = 0;
/**
* 定义四个文件类(链接存储,图片储存,文件存储,错误链接存储)
*/
public static File aLinkFile,imgLinkFile,docLinkFile,errorLinkFile;
解析html页面的方法:
/**
*
* @param path 目标地址
*/
public static void getAllLinks(String path){
Document doc = null;
try{
doc = Jsoup.parse(HttpUtil.get(path));
}catch (Exception e){
//解析出的错误链接(404页面)
writeTxtFile(errorLinkFile, path+"\r\n"); //写入错误链接收集文件
num++;
if(sum>num){
//如果文件总数(sum)大于num(当前读取位置)则继续遍历
getAllLinks(getFileLine(aLinkFile, num));
}
return;
}
//获取html代码中所有带有href属性的a标签,和图片
Elements aLinks = doc.select("a[href]");
Elements imgLinks = doc.select("img[src]");
System.out.println("本次抓取的链接:"+path);
for(Element element:</