天天看點

第一個爬蟲程式執行個體——初學者

原博文位址——初學者們爬起來啊http://blog.sina.com.cn/s/blog_49b6bc490101estr.html

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

public class DownLoadTalkBox {

	/*算法思路:
	 * 1.設定url集,通路過的url不再繼續通路
	 * 2.設定網站的正規表達式模式
	 * 3.資料流中的連結分為三種情況:
	 * 	3.1帶協定頭的可以直接通路的絕對位址
	 * 	3.2不帶協定頭的相對位址:使用基位址加上資源位址組成絕對位址再通路
	 * */
	
	private static Set<String> urlSet = new HashSet<String>();
	//将map定義成treemap,友善導出的檔案時排好序的
	private static Map<String,String> voiceMap = new TreeMap<String,String>();
	
        //隻是針對本次需求,設定了音頻檔案的正規表達式,隻讓我的爬蟲抓取該音頻檔案
	private static Pattern p = Pattern.compile(
			"^(http://)" + "((/|.)*([a-z]*[1-9]*)+)" + ".wma $"  , Pattern.CASE_INSENSITIVE);
        //設定相對位址的正規表達式
        private static Pattern nextPage = Pattern.compile(
			"^(/Apps/Live/)" + "(/|.)*[a-zA-Z]*[1-9*]", Pattern.CASE_INSENSITIVE);
	
	private static void getVoice(String baseUrl ,String exUrl){
		//生成絕對路徑
		if(baseUrl.endsWith("/") && exUrl.startsWith("/")){
			baseUrl = baseUrl.substring(0, baseUrl.length()-1);
		}
                //這是比較糾結的地方,每次遞歸之後得到的相對路徑總是加了這麼長一段字元串
                //我對網絡程式設計比較菜,不明白是什麼原因,為了避免死循環,隻要暫時将這個子串删掉

                String newUrl = baseUrl + exUrl;
		if(newUrl.contains("%2FApps%2FLive%2F%3Fs%3D%2FProgram%2Findex%2Fid%2F41")){
			newUrl = newUrl.replace("%2FApps%2FLive%2F%3Fs%3D%2FProgram%2Findex%2Fid%2F41", "");
		}
		//爬過的節點就不要再爬了,不然就死循環了
		if(urlSet.contains(newUrl)){
			return ;
		}
		
		try {
			urlSet.add(newUrl);//記錄爬過的節點
			Elements links = getElements(newUrl);//調用getElements方法(這是我自己定義的方法)得到網頁中表示連結的元素集合
			for(Element link: links){
				//得到元素的連結内容(音頻位址) 以及 文本内容(音頻名字)
				String ref = link.attr("href");
				String name = link.ownText();
				
				Matcher matcher = p.matcher(ref);
				if(matcher.matches()){//如果元素的連結内容比對我們定義的音頻的正規表達式,則記錄連結内容和音頻的名字
					if(!voiceMap.containsKey(ref)){
						voiceMap.put(ref, name);
					}
					
				}else{//不比對的話,看看該元素連結内容符不符合相對路徑的正規表達式
					if(nextPage.matcher(ref).matches()){
						getVoice(baseUrl,ref);//如果這個連結内容是相對路徑,則往下爬(大家猜猜這是深度搜尋還是廣度搜尋)
					}
				}
			}
			
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	private static Elements getElements(String url) throws IOException{
		urlSet.add(url);
		Document doc = Jsoup.connect(url).get();
		return doc.select("a[href]");
	} 
	
	public static void main(String[] args) {
                //這個url代表,我将爬蟲放在哪裡,即讓它從哪兒開始爬。
                String url = "http://t.am774.com/Apps/Live/?s=/Program/index/id/41";
		getVoice(url,"");
		
		writeTxt(voiceMap);//這個方法是後面順手加的,導出文本
	}

	private static void writeTxt(Map<String, String> map){
		File f = new File("E:/map.txt");

		OutputStream os;
	
		Set keysSet = map.keySet();
		Iterator iterator = keysSet.iterator();
		
		try {
			os = new FileOutputStream(f);
			
			while(iterator.hasNext()){
				String key = (String) iterator.next();
				String name = (String) map.get(key);
				String b = key + "\t" + name + "\r\n";//不是很明白\r\n和\n\r的差別,本來是用的\n\r但是text文本中出現亂碼,囧rz
				System.out.print(b);
				os.write(b.getBytes());
			}
			
			if(!f.exists()){
				f.mkdir();
			}
			os.flush();
			os.close();
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		
	}
	
}