非常草草的实现,能够完美实现对ecnu主页图片的抓取【跑,其他的都会报错或有缺失。
究其原因还是在对img标签上的解析上碰到了非常大的困难,正则表达式也不顶用,下一步考虑使用jsoup进行处理。
同时,对于图片的读写也较慢,可能与我是一字节一字节写入文件的有关,可以考虑使用imagio包进行处理。
还有一点可以改进的是对异常的处理,这个等看了coreJava相关章节再说,不急。
初步先实现给定网址,爬取图片至指定路径。之后考虑使用邮件发送(似乎不实用)
最终目标是架在服务器上,前端接收用户要求,后端进行爬取处理。
************************************************************************************************************
下载器类
package just4test;
import java.net.*;
import java.io.*;
import java.util.*;
import java.util.regex.*;
public class Downloader {
private Queue <String> col;//用队列,更加真实
private String base,path;
public Downloader (String abase,String apath) {
base=abase;
path=apath;
col = new LinkedList<>();//不能直接构造queue对象,用LinkedList作为其实现类,优先队列也可
}
/*
* @return html代码
* 获取网页html,这里默认utf8编码
*/
public String getHtml() throws Exception {
URL url = new URL(base);
HttpURLConnection connection= (HttpURLConnection)url.openConnection();
String res="";
Scanner cin = new Scanner (connection.getInputStream());
while (cin.hasNextLine())//一行一行读入
res += cin.nextLine()+'\n';
cin.close();
return res;
}
/*
* 辅助函数,从html中筛出图片,放进队列中,更好的方法是使用jsoup,等学习了再用
*/
public void filter () throws Exception {
String res = this.getHtml();
String homepage = base;
int pos0= base.indexOf("//");
int pos1 = base.indexOf('/',pos0+2);
if (pos1!=-1)
homepage = base.substring(0,pos1);
Pattern p = Pattern.compile("<img.*src=\"(.*?)\"");//正则表达式捕获图片url
Matcher m = p.matcher(res);
while (m.find()){//每找到一次图片就放进队列中
String tmp = m.group(1);
if (tmp.indexOf('.')!=-1) //是图片一定得有dot
if (tmp.substring(0,2).equals("//"))
col.add("http:"+tmp);
else if (tmp.charAt(0)=='/')
col.add(homepage+tmp);
else
col.add(tmp);
}
}
public Queue<String> getCol() {
return col;
}
/*
* 下载图片至指定路径,这里用的是最朴素的方法,可以用花哨点的imageIO,一会再研究
* 如果文件同名会自动覆盖,需修正
*/
public void download()throws Exception {
filter();
File fp = new File(path);
if (!fp.exists())
fp.mkdirs();//如果该路径不存在,创建它
int i=0;
InputStream cin = null;
OutputStream cout = null;
while (col.size()!=0) {//遍历整个队列
String tmp = col.remove();
String filename = tmp.substring(tmp.lastIndexOf('/'));//找出文件名
URL url = new URL(tmp);
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
cin = connection.getInputStream();
File file =new File (fp+filename);//这里默认fp最后不带/,文件名前面带/
cout = new FileOutputStream (file);//输出流
while ((i=cin.read())!=-1) //将其当作普通二进制文件进行处理,read到头时返回-1
cout.write(i);//写入文件
cin.close();//关闭输入输出流
cout.close();
}
}
}
测试类
package just4test;
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) {
try {
Scanner cin = new Scanner (System.in);
System.out.println("输入要抓取的网页");
String base = cin.next();
System.out.println("输入存放路径");
String path = cin.next();
cin.close();
Downloader down = new Downloader(base,path);
/*System.out.println(down.getHtml());
down.filter();
Queue<String> que = down.getCol();
for (String z:que)
System.out.println(z);*/
down.download();
System.out.println("下载成功!");
}
catch (FileNotFoundException e) {//关于异常的代码写得真的很偷懒,下次补上
e.printStackTrace();
System.out.println("小错误,不慌");
}
catch(Exception e) {
e.printStackTrace();
System.out.println("下载失败");
}
}
}
以上