import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

class scraber implements Runnable


{
private String ss;
private String url;

/** *//**
*
* 該函數(shù)爬取網(wǎng)絡(luò)上跟所需查詢單詞想通的語(yǔ)句,并存取
* @param ss 流
* @param url 超鏈接
*/
public scraber(String ss,String url)

{
this.ss=ss;
this.url=url;

}
public void run()

{
String s=new String("不錯(cuò)");
if(ss.contains(s))

{

/** *//**
* 需要對(duì)字符串進(jìn)行一些必要裁剪,使得字符串更加簡(jiǎn)單,醒目
*/
int begin=ss.indexOf(s);
ss = ss.substring(begin);
int end = 30 < ss.length()? 30:ss.length();
ss=ss.substring(0, end);
System.out.println(url+" "+"begin:"+ss);
}
}
}

/** *//**
* @author Administrator
* 在廣度遍歷的每一個(gè)枝點(diǎn)安放一個(gè)機(jī)器人線程,該線程負(fù)責(zé)該枝點(diǎn)一下的搜索
*/
class irobot implements Runnable


{
private String ss;
public irobot(String ss)

{
this.ss=ss;
}
public void run()

{
MySearch ms=new MySearch();

/** *//**
* 線程獨(dú)立啟動(dòng)對(duì)該URL內(nèi)容的檢索
*/
try

{
ms.checkURL(ss);
}
catch(IOException e)

{
}
}
}

class MySearch
{

/** *//**
* 使用線程池來(lái)進(jìn)行大批量線程的管理,這里規(guī)定當(dāng)前最多線程數(shù)為10.可重用的線程
* 不斷嘗試著和newCachedThreadPool() 進(jìn)行比較,發(fā)現(xiàn)newCachedThreadPool() 比較容易崩潰,但是速度非常快
* 適合于快速的查詢,但是要對(duì)查詢的深度進(jìn)行嚴(yán)格限制。使用newFixedThreadPool(10)適度相對(duì)慢一些,但是查詢穩(wěn)定,因?yàn)?br>
* 查詢已經(jīng)限制好了在10個(gè)線程的范圍內(nèi),但是到一定程度也會(huì)崩潰,這個(gè)程度比前面深,最主要是由于內(nèi)存不足,算法本身對(duì)內(nèi)存的需求很大。
*/
ExecutorService exec = Executors.newFixedThreadPool(10);

/** *//**由于多線程公用該變量,直接設(shè)置它為靜態(tài)變量
* 使用hashMap使得對(duì)URL的重復(fù)性查詢檢索效率倍增
*/
static HashMap<String,Integer> hashList = new HashMap<String,Integer>();

/** *//**由于多線程公用該變量,直接設(shè)置它為靜態(tài)變量
* URL記錄在該文件中
*/
static File store=new File("d://link.txt");

/** *//**由于多線程公用該變量,直接設(shè)置它為靜態(tài)變量
* 文件流
*/
static FileWriter writeFile;
public void checkURL(String uu)throws IOException

{
if(uu.endsWith("/"))

{
uu=uu.substring(0,uu.length()-1);
}

try
{
URL u = new URL(uu);
InputStream inn =u.openStream();
if(hashList.containsKey(uu))

{
Integer numLink=hashList.get(uu);
hashList.put(uu, ++numLink);
return;
}
hashList.put(uu, 1);
writeFile.append(uu+"\n");
BufferedReader in = new BufferedReader(new InputStreamReader(inn,"ISO-8859-1"));
String ss;
ArrayList<String> tempList=new ArrayList<String>();
int sureOfCharset = 0;

/** *//**
* 當(dāng)前所搜索的文檔,查詢一遍,查找所需要查找的句子
* 并做超鏈接提取工作,存放到臨時(shí)鏈接隊(duì)列中。
*/
while((ss=in.readLine())!=null)

{

/** *//**
* 注意對(duì)文檔的字符編碼進(jìn)行轉(zhuǎn)換,一般是轉(zhuǎn)換成UTF-8格式
*/
ss= ss.trim();
if(sureOfCharset == 0)

{

/** *//**
* 用正則表達(dá)式匹配更加精準(zhǔn),效率更好
*/
if(ss.contains("charset"))

{
String pattern1="(utf-8|UTF-8)";
String pattern2="(gbk|GBK)";
String pattern3="(gb2312|GB2312)";
Pattern p1=Pattern.compile(pattern1);
Pattern p2=Pattern.compile(pattern2);
Pattern p3=Pattern.compile(pattern3);
Matcher m1=p1.matcher(ss);
Matcher m2=p2.matcher(ss);
Matcher m3=p3.matcher(ss);

/** *//**
* 匹配模式一成功,即文檔為utf8編碼方式
*/
if(m1.find())

{
sureOfCharset =1;
}

/** *//**
* 匹配模式二成功,即文檔為GBK編碼方式
*/
else if(m2.find())

{
sureOfCharset =2;
}

/** *//**
* 匹配模式三成功,即文檔為gb312編碼方式
*/
else if(m3.find())

{
sureOfCharset =3;
}

/** *//**
* 匹配模式失敗
*/
else

{
sureOfCharset = 4;
}
}
}
switch(sureOfCharset)

{

case 0:
{
ss = new String(ss.getBytes("ISO-8859-1"),"utf-8");
break;
}

case 1:
{
ss = new String(ss.getBytes("ISO-8859-1"),"utf-8");
break;
}

case 2:
{
ss = new String(ss.getBytes("ISO-8859-1"),"gbk");
break;
}

case 3:
{
ss= new String(ss.getBytes("ISO-8859-1"),"gb2312");
break;
}

default:
{
ss = new String(ss.getBytes("ISO-8859-1"),"utf-8");
break;
}
}

/** *//**
* 開啟爬蟲線程抓取和“***”有關(guān)的語(yǔ)句
*/
scraber buger=new scraber(ss,uu);
exec.execute(buger);

/** *//**
* 提取超鏈接
*/
check(ss,tempList);
}

/** *//**
* 對(duì)臨時(shí)超鏈接隊(duì)列進(jìn)行處理
*/
Iterator<String> it=tempList.iterator();

/** *//**
* 提取出臨時(shí)超鏈接隊(duì)列中的每一個(gè)鏈接
*/
while(it.hasNext())

{
String ref = (String)it.next();

/** *//**
* 啟動(dòng)一個(gè)機(jī)器人線程,處理該超鏈接
*/
irobot ir=new irobot(ref);
Thread robThread= new Thread(ir);
robThread.start();
}

/** *//**
* 清空臨時(shí)隊(duì)列
*/
tempList.clear();

/** *//**
* 關(guān)閉線程池
*/
exec.shutdown();
}
catch(IOException e)

{

/** *//**
* 無(wú)法連接
*
*/
}
}

/** *//**
* 從該行中提取出超鏈接
* @param s 該行字符串
* @param tempList 臨時(shí)超鏈接隊(duì)列
*
*/
void check(String s,ArrayList<String> tempList)

{
int i=s.indexOf("href=\"");
if(i>0)

{
String news=s.substring(i+6);
int j1= news.indexOf("\"");
if(j1>0)

{
String ref = news.substring(0,j1);
tempList.add(ref);
}
}

}

public static void main(String args[])throws IOException

{
MySearch t= new MySearch();
System.out.println("%searching start%");
t.go("http://www.shnenglu.com/");
}


void go(String uu)

{

try
{
writeFile= new FileWriter(store);
checkURL(uu);
writeFile.close();
}catch(IOException e)

{
}
}
}
