写这个纯属个人爱好,前两天想玩爬虫,但是百度了一大圈也没发现有好一点的帖子,所以就自己研究了下,亲测小点的网站还是能随随便便爬完的,由于是单线程所以速度嘛~~你懂的
(多线程没学好,后期再慢慢加上多线程吧)
先上几张效果图
注意:okhttp内部依赖okio,别忘了同时导入okio
这样基本就实现了链接的遍历
举个栗子
假设index.html页面内有5个子链接分别对应 a~e.html,解析index.html页面后将该页面中的5个链接存入文件中,num++(此时num=0),文件中的1~5行就分别对应这5个链接,第二次调用读取方法的时候用到的链接就是文件中的第num行,也就是a.html。
接着解析a.html,将a.html中的所有超链接追加进文件中。
图中的遍历方式似乎有点像一个横放着的wifi信号
接下来贴代码:
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教程
public static String path = "http://www.yada.com.cn/"; //雅达公司官网
public static int num = -1,sum = 0;
/**
* 定义四个文件类(链接存储,图片储存,文件存储,错误链接存储)
*/
public static File aLinkFile,imgLinkFile,docLinkFile,errorLinkFile;
/**
*
* @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:aLinks){
String url =element.attr("href");
//判断链接是否包含这两个头
if(!url.contains("http://")&&!url.contains("https://")){
//不是则加上 例:
//则需要加上前缀 http://www.yada.com.cn/xitongshow.php?cid=67&id=113
//否则下次解析该链接的时候会报404错误
url = Spider.path+url;//网站首页加上该链接
}
//如果文件中没有这个链接,而且链接中不包含javascript:则继续(因为有的是用js语法跳转)
if(!readTxtFile(aLinkFile).contains(url)
&&!url.contains("javascript")){
//路径必须包含网页主链接--->防止爬入别的网站
if(url.contains(Spider.path)){
//判断该a标签的内容是文件还是子链接
if(url.contains(".doc")||url.contains(".exl")
||url.contains(".exe")||url.contains(".apk")
||url.contains(".mp3")||url.contains(".mp4")){
//写入文件中,文件名+文件链接
writeTxtFile(docLinkFile, element.text()+"\r\n\t"+url+"\r\n");
}else{
//将链接写入文件
writeTxtFile(aLinkFile, url+"\r\n");
sum++; //链接总数+1
}
System.out.println("\t"+element.text()+":\t"+url);
}
}
}
//同时抓取该页面图片链接
for(Element element:imgLinks){
String srcStr = element.attr("src");
if(!srcStr.contains("http://")&&!srcStr.contains("https://")){//没有这两个头
srcStr = Spider.path+srcStr;
}
if(!readTxtFile(imgLinkFile).contains(srcStr)){
//将图片链接写进文件中
writeTxtFile(imgLinkFile, srcStr+"\r\n");
}
}
num++;
if(sum>num){ //如果文件总数(sum)大于num(当前读取位置)则继续遍历
getAllLinks(getFileLine(aLinkFile, num));
}
}
该方法用于解析html页面,取到所有链接,存入文件
/**
* 读取文件
* @param file 文件类
* @return 文件内容
*/
public static String readTxtFile(File file){
String result = ""; //读取結果
String thisLine = ""; //每次读取的行
try {
BufferedReader reader = new BufferedReader(new FileReader(file));
try {
while((thisLine=reader.readLine())!=null){
result += thisLine+"\n";
}
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return result;
}
/**
* 写入内容
* @param file 文件类
* @param urlStr 要写入的文本
*/
public static void writeTxtFile(File file,String urlStr){
try {
BufferedWriter writer = new BufferedWriter(new FileWriter(file,true));
writer.write(urlStr);
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
简单的文件操作方法,用于储存每次解析出来的链接
/**
* 获取文件指定行数的数据,用于爬虫获取当前要爬的链接
* @param file 目标文件
* @param num 指定的行数
*/
public static String getFileLine(File file,int num){
String thisLine = "";
int thisNum = 0 ;
try {
BufferedReader reader = new BufferedReader(new FileReader(file));
while((thisLine = reader.readLine())!=null){
if(num == thisNum){
return thisLine;
}
thisNum++;
}
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
这个方法很重要,用于获取文件中的第几条链接
package com.xietiansheng.shangmao.cn;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import okio.ForwardingTimeout;
public class Spider {
public static String path = "http://www.yada.com.cn/"; //雅达公司官网
public static int num = -1,sum = 0;
/**
* 定义四个文件类(链接存储,图片储存,文件存储,错误链接存储)
*/
public static File aLinkFile,imgLinkFile,docLinkFile,errorLinkFile;
/**
*
* @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;
}
Elements aLinks = doc.select("a[href]");
Elements imgLinks = doc.select("img[src]");
System.out.println("开始链接:"+path);
for(Element element:aLinks){
String url =element.attr("href");
//判断链接是否包含这两个头
if(!url.contains("http://")&&!url.contains("https://")){
//不是则加上 例:
//则需要加上前缀 http://www.yada.com.cn/xitongshow.php?cid=67&id=113
//否则404
url = Spider.path+url;
}
//如果文件中没有这个链接,而且链接中不包含javascript:则继续(因为有的是用js语法跳转)
if(!readTxtFile(aLinkFile).contains(url)
&&!url.contains("javascript")){
//路径必须包含网页主链接--->防止爬入别的网站
if(url.contains(Spider.path)){
//判断该a标签的内容是文件还是子链接
if(url.contains(".doc")||url.contains(".exl")
||url.contains(".exe")||url.contains(".apk")
||url.contains(".mp3")||url.contains(".mp4")){
//写入文件中,文件名+文件链接
writeTxtFile(docLinkFile, element.text()+"\r\n\t"+url+"\r\n");
}else{
//将链接写入文件
writeTxtFile(aLinkFile, url+"\r\n");
sum++; //链接总数+1
}
System.out.println("\t"+element.text()+":\t"+url);
}
}
}
//同时抓取该页面图片链接
for(Element element:imgLinks){
String srcStr = element.attr("src");
if(!srcStr.contains("http://")&&!srcStr.contains("https://")){//没有这两个头
srcStr = Spider.path+srcStr;
}
if(!readTxtFile(imgLinkFile).contains(srcStr)){
//将图片链接写进文件中
writeTxtFile(imgLinkFile, srcStr+"\r\n");
}
}
num++;
if(sum>num){
getAllLinks(getFileLine(aLinkFile, num));
}
}
/**
* 读取文件内容
* @param file 文件类
* @return 文件内容
*/
public static String readTxtFile(File file){
String result = ""; //读取結果
String thisLine = ""; //每次读取的行
try {
BufferedReader reader = new BufferedReader(new FileReader(file));
try {
while((thisLine=reader.readLine())!=null){
result += thisLine+"\n";
}
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return result;
}
/**
* 写入内容
* @param file 文件类
* @param urlStr 要写入的文本
*/
public static void writeTxtFile(File file,String urlStr){
try {
BufferedWriter writer = new BufferedWriter(new FileWriter(file,true));
writer.write(urlStr);
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 获取文件指定行数的数据,用于爬虫获取当前要爬的链接
* @param file 目标文件
* @param num 指定的行数
*/
public static String getFileLine(File file,int num){
String thisLine = "";
int thisNum = 0 ;
try {
BufferedReader reader = new BufferedReader(new FileReader(file));
while((thisLine = reader.readLine())!=null){
if(num == thisNum){
return thisLine;
}
thisNum++;
}
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
/**
* 获取文件总行数(有多少链接)
* @param file 文件类
* @return 总行数
*/
public static int getFileCount(File file){
int count = 0;
try {
BufferedReader reader = new BufferedReader(new FileReader(file));
while(reader.readLine()!=null){ //遍历文件行
count++;
}
} catch (Exception e) {
e.printStackTrace();
}
return count;
}
public static void main(String[] args) {
aLinkFile = new File("D:/Spider/ALinks.txt");
imgLinkFile = new File("D:/Spider/ImgLinks.txt");
docLinkFile = new File("D:/Spider/DocLinks.txt");
errorLinkFile = new File("D:/Spider/ErrorLinks.txt");
//用数组存储四个文件对象,方便进行相同操作
File[] files = new File[]{aLinkFile,imgLinkFile,docLinkFile,errorLinkFile};
try {
for(File file: files){
if(file.exists()) //如果文件存在
file.delete(); //则先删除
file.createNewFile(); //再创建
}
} catch (IOException e) {
e.printStackTrace();
}
long startTime = System.currentTimeMillis(); //获取开始时间
Spider.getAllLinks(path); //开始爬取目标内容
System.out.println(""
+ "——————————————————爬取结束——————————————————"
+ "\n目标网址:"+path
+ "\n链接总数:"+sum+"条"
+ "\n图片总数:"+getFileCount(imgLinkFile)+"张"
+ "\n文件总数:"+getFileCount(docLinkFile)+"份");
writeTxtFile(aLinkFile, "链接总数:"+getFileCount(aLinkFile)+"条");
writeTxtFile(imgLinkFile, "图片总数:"+getFileCount(imgLinkFile)+"张");
writeTxtFile(docLinkFile, "文件总数:"+getFileCount(docLinkFile)+"份");
writeTxtFile(errorLinkFile, "问题链接总数:"+getFileCount(errorLinkFile)+"条");
long endTime = System.currentTimeMillis(); //获取结束时间
System.out.println("\n程序运行时间:" + (endTime - startTime) + "ms"); //输出程序运行时间
}
}
结束
代码比较初级
爬爬小网站就可以了
纯属娱乐而已
有问题可以给我留言或者在下面评论
可以用于服务端于安卓客户端结合达到想要的效果