Java爬取晋江书城的某个分类下小说的简介和评论

写在前面,一开始是因为书荒又找不到自己喜欢的,就打算去晋江书城看看,结果排在前面的也不是我的菜,一本本挑又嫌太麻烦就打算把数据爬下来慢慢的看。分析了一下晋江的网页,发现可以爬下来的数据有书名、作者、类型、简介、标签、收藏、下载、点赞数、评论等,而我已经在晋江的网页上做过分类筛选,且萝卜白菜各有所爱,收藏和下载量高的也不能代表就是我喜欢的,所以我最后选择爬取简介、评论和第一章的内容,简介是一本书大体的概要,可以筛选不喜欢的设定,评论可以筛选一些文笔不好或太狗血的文章,第一章内容可以大致了解一个人的文风····当然后来我因为觉得数据太多的原因没有爬第一章内容。最后的成果是把每一页的小说的名字、简介和评论抓取出来,并生成一个txt文件,然后供自己手动筛选。

 

1.准备好需要爬取的网页URL

http://www.jjwxc/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/"+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/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,找到了评论的请求链接:

http://s8.static.jjwxc/comment_json.php?jsonpCallback=commnet_onebook_140421&novelid=2487981&chapterid=   

其中onebook_后边的数字不知道是啥,找了几个小说的评论请求链接看都是一样的就没管了,novelid是小说id,小说链接上就有,截取出来就行了。之后需要用http请求得到数据,发送http请求前边有说过

Java如何发起httphttps请求:java如何发起http和https请求

要注意network上边说的请求方式是get,但是!其实是用POST才能取到数据,get是乱码,它这个数据是ascll码,不需要转码,输出就是中文了。这个得到的一串调整一下就是json,之后解析json就行了。这个我前边也有教程:

Json解析:json和java对象的相互转换

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) {
		thisment = 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/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/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/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.HttpURLConnection;
import java.URL;
//import java.URLEncoder;
import java.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/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/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);
	}

结果除了第一页其他的都抓不到了,就消失了消失了消失了····我也不知道为啥。







更多推荐

超简单的JAVA爬虫爬取晋江小说的简介和评论