1. 程式人生 > >超簡單的JAVA爬蟲爬取晉江小說的簡介和評論

超簡單的JAVA爬蟲爬取晉江小說的簡介和評論

Java爬取晉江書城的某個分類下小說的簡介和評論

寫在前面,一開始是因為書荒又找不到自己喜歡的,就打算去晉江書城看看,結果排在前面的也不是我的菜,一本本挑又嫌太麻煩就打算把資料爬下來慢慢的看。分析了一下晉江的網頁,發現可以爬下來的資料有書名、作者、型別、簡介、標籤、收藏、下載、點贊數、評論等,而我已經在晉江的網頁上做過分類篩選,且蘿蔔白菜各有所愛,收藏和下載量高的也不能代表就是我喜歡的,所以我最後選擇爬取簡介、評論和第一章的內容,簡介是一本書大體的概要,可以篩選不喜歡的設定,評論可以篩選一些文筆不好或太狗血的文章,第一章內容可以大致瞭解一個人的文風····當然後來我因為覺得資料太多的原因沒有爬第一章內容。最後的成果是把每一頁的小說的名字、簡介和評論抓取出來,並生成一個txt

檔案,然後供自己手動篩選。

1.準備好需要爬取的網頁URL

http://www.jjwxc.net/bookbase.php?fw0=0&fbsj=0&ycx0=0&ycx1=1&xx1=1&sd2=2&sd3=4&lx1=1&lx6=6&lx10=10&lx13=13&lx16=16&fg2=2&sortType=0&isfinish=2&collectiontypes=ors&searchkeywords=&page=1";

2.eclipse新建Dynamic專案JingjiangSpider;

3.WEB-INF/lib下引入需要的包。

 

其實不太確定是不是必須的····

4.src下新建一個包com.guozi.spider,並在包下新建java檔案JinjiangSpider.java

5.先把本頁的小說名和連結爬出來封裝到map中去。

主要是解析,需要開啟網頁按F12去看element那部分原始碼,對著網頁找到我們需要提取的那部分節點的id或者class甚至是標籤,通過這些我們才能提取到我們所需要的資訊。Id唯一所以是我們的第一選擇。最後輸出測試一下是否得到需要資訊。

JinjiangSpider.java

//把小說名和連結整出來裝到map裡面去。
		public static Map getPageurl(String url){
			Map<String,String> nm=new HashMap<String,String>();
			try {
				//從網頁獲取得到HTML  jsoup是網頁解析工具
				Document document = Jsoup.connect(url).get();   
				Element body=document.body();                    
				//cytable是分析網頁原始碼得到的節點  通過class得到element
				Elements links1 = body.getElementsByClass("cytable");   
				//得到所有<a>標籤的element
				Elements links = links1.get(0).getElementsByTag("a");   
				for (Element link : links) {
						//過濾連結 只有以onebook開頭才是我需要的
						if(link.attr("href").startsWith("onebook")){    
						//弄到map裡面去存著 得到的連結只是相對連結記得加上前邊的
						nm.put(link.text(), "http://www.jjwxc.net/"+link.attr("href"));   
						}
				}
				for(String key : nm.keySet()){     //迴圈map輸出來測試一下
					 System.out.println( key + "----" + nm.get(key));
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block bn
				e.printStackTrace();
			}
			return nm;
		}
public static void main(String[] args) {
		String url="http://www.jjwxc.net/bookbase.php?fw0=0&fbsj=0&ycx0=0&ycx1=1&xx1=1&sd2=2&sd3=4&lx1=1&lx6=6&lx10=10&lx13=13&lx16=16&fg2=2&sortType=0&isfinish=2&collectiontypes=ors&searchkeywords=&page=1";
		getPageurl(url);
		
	}


結果:


6.第五步已經把每本小說的連結拿出來了,這一步就是通過這個連結進到小說的詳情頁抓取小說的簡介和評論。此外我們還需要建立一個物件來儲存小說的這些資訊。最後我們把抓取到的小說資訊儲存到一個List中。

因為評論是非同步載入的,不能和簡介同時抓,所以我F12後分析了一下network,找到了評論的請求連結:

其中onebook_後邊的數字不知道是啥,找了幾個小說的評論請求連結看都是一樣的就沒管了,novelid是小說id,小說連結上就有,截取出來就行了。之後需要用http請求得到資料,傳送http請求前邊有說過

要注意network上邊說的請求方式是get,但是!其實是用POST才能取到資料,get是亂碼,它這個資料是ascll碼,不需要轉碼,輸出就是中文了。這個得到的一串調整一下就是json,之後解析json就行了。這個我前邊也有教程:

NovelEntity.java:

package com.guozi.entity;

public class NovelEntity {
	private String name;  //書名
	private String introduction;   //介紹
	private String comment;   //評論
	private String content;   //第一章內容
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getIntroduction() {
		return introduction;
	}
	public void setIntroduction(String introduction) {
		this.introduction = introduction;
	}
	public String getComment() {
		return comment;
	}
	public void setComment(String comment) {
		this.comment = comment;
	}
	public String getContent() {
		return content;
	}
	public void setContent(String content) {
		this.content = content;
	}
	
}


JinjiangSpider.java

//把每一頁小說的簡評和評論弄出來
			public static List<NovelEntity> getNovel(Map<String,String> map){    //引數就是上一步返回的map
				List<NovelEntity> noli=new ArrayList<NovelEntity>();           
				for(String key : map.keySet()){
					NovelEntity novel=new NovelEntity();
					Document document;
					try {
						String introduction="沒有簡評";
						document = Jsoup.connect(map.get(key)).get();   //小說詳情頁的html
						Element body=document.body();
						//解析簡評,如果簡評存在就輸出
						Element e=body.getElementById("marknovel_message");   //marknovel_message是簡評的id
						if(e!=null){
						introduction=e.text();                      //抽取簡評
						}
						//評論的請求連結 http://s8.static.jjwxc.net/comment_json.php?jsonpCallback=commnet_onebook_140421&novelid=2487981&chapterid=
						String bookid=map.get(key).split("novelid=")[1];  //把小說的id弄出來
						String baseurl="http://s8.static.jjwxc.net/comment_json.php?jsonpCallback=commnet_onebook_140421&novelid=NOVELID&chapterid=";    //得到評論json的url
						baseurl=baseurl.replace("NOVELID",bookid);
						String s=CommonUtil.httpRequest(baseurl,"POST",null);      //通過http請求得到評論json 得到的json不標準解析不出來,需要稍微整理一下
						s=s.split("\\(\\{")[1];
						s=s.split("\\}\\)")[0];
						s="{"+s+"}";
						JSONObject jo1=JSONObject.fromObject(s); 
						JSONArray bodyy=(JSONArray) jo1.get("body");  //解析評論
						StringBuffer ss=new StringBuffer();
						for(int i=0;i<bodyy.size();i++){  
						    JSONObject j=(JSONObject) bodyy.get(i);  
						    String p=j.getString("commentbody");
						    p=p.split("<br>")[0];
						    p=p.replaceAll("\\<img.*?\\>","");
						    ss.append(p+"【^__^】");          //把所有評論弄到一起,然後分隔一下
						}  
						String comment=ss.toString();     //得到評論
						novel.setName(key);
						novel.setIntroduction(introduction);
						novel.setComment(comment);
						noli.add(novel);
						System.out.println(key);
						System.out.println("【簡介】"+introduction);
						System.out.println("【評論】"+comment);
						
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}	
				return noli;
			}
public static void main(String[] args) {
String url="http://www.jjwxc.net/bookbase.php?fw0=0&fbsj=0&ycx0=0&ycx1=1&xx1=1&sd2=2&sd3=4&lx1=1&lx6=6&lx10=10&lx13=13&lx16=16&fg2=2&sortType=0&isfinish=2&collectiontypes=ors&searchkeywords=&page=1";
//getPageurl(url);
getNovel(getPageurl(url));

}

CommonUtil.java

package com.guozi.spider;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
//import java.net.URLEncoder;
import java.net.URLEncoder;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;



public class CommonUtil {
	
	//處理http請求  requestUrl為請求地址  requestMethod請求方式,值為"GET"或"POST"
	public static String httpRequest(String requestUrl,String requestMethod,String outputStr){
		StringBuffer buffer=null;
		try{
		URL url=new URL(requestUrl);
		HttpURLConnection conn=(HttpURLConnection)url.openConnection();
		conn.setDoOutput(true);
		conn.setDoInput(true);
		conn.setRequestMethod(requestMethod);
		conn.connect();
		//往伺服器端寫內容
		if(null!=outputStr){
			OutputStream os=conn.getOutputStream();
			os.write(outputStr.getBytes("utf-8"));
			os.close();
		}
		
		//讀取伺服器端返回的內容
		InputStream is=conn.getInputStream();

		InputStreamReader isr=new InputStreamReader(is,"utf-8");

		BufferedReader br=new BufferedReader(isr);
		buffer=new StringBuffer();
		String line=null;
		while((line=br.readLine())!=null){
			buffer.append(line);
		}
		}catch(Exception e){
			e.printStackTrace();
		}
		return buffer.toString();
	}
結果:


最後沒抓第一章內容就是因為簡介和評論就已經夠多的了,再加上第一章我會看不過來的。


7.把上邊list的內容弄成txt方便閱讀。

JinjiangSpider.java

//一頁弄出來的小說弄成txt
		public static void toTxt(List<NovelEntity> list){
			List<NovelEntity> li=list;
			try {
				 File file = new File("E:/jinjiang/"+li.get(0).getName()+".txt");    //弄一個不重名的檔名
				 if (file.exists()) {
				 file.delete();
					} 
				file.createNewFile();
				BufferedWriter bw = new BufferedWriter(new FileWriter(file));
				for(int i=0;i<li.size();i++){
				bw.write(list.get(i).getName()+"\r\n");     //記得換行
				bw.write(list.get(i).getIntroduction()+"\r\n");
				bw.write(list.get(i).getComment()+"\r\n");
						}
				bw.close();
				System.out.print("弄完了,寶寶去看文件吧");                 //提示一下,不然不知道完了沒
				} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
			}
public static void main(String[] args) {
		String url="http://www.jjwxc.net/bookbase.php?fw0=0&fbsj=0&ycx0=0&ycx1=1&xx1=1&sd2=2&sd3=4&lx1=1&lx6=6&lx10=10&lx13=13&lx16=16&fg2=2&sortType=0&isfinish=2&collectiontypes=ors&searchkeywords=&page=1";
		//getPageurl(url);
		//getNovel(getPageurl(url));
		toTxt(getNovel(getPageurl(url)));
		
	}

結果:



差不多到此為止了,只需要換一下baseurl裡面page=後邊的數字就能一頁一頁的把它弄出來啦!······什麼你問我為什麼不一次性把所有頁數的都弄出來?當然有啊,不過·····
8.把每一頁的小說全部抓出來。
JinjiangSpider.java:

//把分類下所有小說都弄出來
	public static void getAllNovel(String url){ 
		/*
		 * 晉江的bug,下一頁沒有盡頭啊,所以只能抓取頁數之後再來迴圈
		 * */
		String burl=url;
		int pagecount=1;
		try {
			Document document = Jsoup.connect(url).get();
			Element body=document.body();
			Element pagee=body.getElementById("pageArea").getAllElements().get(4);
			pagecount=Integer.valueOf(pagee.attr("href").split("page=")[1]);     //得到總頁數  
			System.out.println(pagecount);
			for(int i=1;i<pagecount;i++){     //從第一頁到最後一頁都抓取一遍
				burl=burl.replace(burl.split("page=")[1],String.valueOf(i));    //得到每一頁的連結
				toTxt(getNovel(getPageurl(burl)));     //把它弄出來
			}
			System.out.println("主人~我幹完活了~~~~");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

public static void main(String[] args) {
		String url="http://www.jjwxc.net/bookbase.php?fw0=0&fbsj=0&ycx0=0&ycx1=1&xx1=1&sd2=2&sd3=4&lx1=1&lx6=6&lx10=10&lx13=13&lx16=16&fg2=2&sortType=0&isfinish=2&collectiontypes=ors&searchkeywords=&page=1";
		//getPageurl(url);
		//getNovel(getPageurl(url));
		//toTxt(getNovel(getPageurl(url)));
		getAllNovel(url);
	}

結果除了第一頁其他的都抓不到了,就消失了消失了消失了····我也不知道為啥。