从指定的url抓取网页,思路很清晰,使用java.net.URL得到url对应的二进制流,然后就可以像操作普通文件那样操作这个流了。
下面的例子演示了从百度抓取一个搜索网页,将网页存入到文件当中;同时,还对网页进行了简单的分析,得到了检索结果的数量。
不过在分析网页内容的时候不可避免的要处理编码问题,因为从url读取的时候是字符流,网页上字符的编码是多样的,如果直接用java默认的字符集,十有八九会出现乱码。因此要在二进制流全部读取后,为其指定编码。
需要说明的是,从url读取的二进制流中既有控制信息(html标签,css,js等),又有文本信息(我们在网页上看到的文字),又有二进制信息(图片等),因此如论我们指定何种编码方式,有些信息始终是无法解析成文字的。但是对于简单分析来说,只要将原来的文本信息解析出来就行了。
如果想对得到的二进制文件作精确的分析,比如分别取出里面的图片、文字、样式等信息,恐怕需要不少工作,这个简单的小程序就做不到了。
下面是程序代码:
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.Arrays;
public class MySpider {
public static void main(String[] args) throws Exception{
String rscount = new MySpider().grepAndgetRSCount("http://www.baidu.com/s?wd=北京雾霾");
System.out.println("搜索结果的个数为:" + rscount);
}
private String grepAndgetRSCount(String urlstr) throws Exception{
URL url = new URL(urlstr);
InputStream inStm = url.openConnection().getInputStream();// 得到url对用的二进制流
File outFile = new File("C:/grep.html");// 把得到的网页写入到这个文件
if (!outFile.exists()) {
outFile.createNewFile();
}
OutputStream outStm = new FileOutputStream(outFile);
byte[] buffer = new byte[4096];
int bytes_read;
ByteArrayBuffer byteAbuf = new ByteArrayBuffer();
while ((bytes_read = inStm.read(buffer)) != -1) {
outStm.write(buffer, 0, bytes_read);// 把得到的二进制流写入到文件
byteAbuf.append(buffer, bytes_read);// 缓存一份,供后面分析结果使用
}
inStm.close();
outStm.close();
String rscount = "-1";
// 将得到的二进制流解析成文字,注意字符编码
String rsStr = new String(byteAbuf.getBytes(), 0, byteAbuf.getByteslen(), "utf-8");
if(rsStr.contains("百度为您找到相关结果约")){
try{
rscount = rsStr.split("百度为您找到相关结果约")[1].split("个")[0];
}catch(Exception e){
// do nothing
}
}
return rscount;
}
}
class ByteArrayBuffer{
/**
* 一个byte容器,存储读取的字节流
*/
private byte bytes[];
public byte[] getBytes() {
return bytes;
}
public int getByteslen() {
return byteslen;
}
private int byteslen;
public ByteArrayBuffer(){
bytes = new byte[1024];
byteslen = 0;
}
public ByteArrayBuffer append(byte[] bytesAppend, int len){
int freespace = bytes.length - byteslen;
if(freespace < len){
resize(len + byteslen);
}
System.arraycopy(bytesAppend, 0, bytes, byteslen, len);
byteslen += len;
return this;
}
private void resize(int newsize){
int newsize1 = 1;
while(newsize1 < newsize)
newsize1 <<= 1;
bytes = Arrays.copyOf(bytes, newsize1);
}
}