完整Java爬取起点小说网小说目录以及对应链接
完整Java爬取起点小说网小说目录以及对应链接
(第一次使用markdown写,其中的排版很不好,望大家理解)
?? 因为最近有一个比赛的事情,故前期看了看黄大神的webmagic框架,无奈之时用时不会正则表达式的使用,临近交作品时间节点,突击看了看Java自带的一个框架,JSOUP框架,大概是三天就写好了这个小爬虫。具体如下:
?时间的安排:
周六看了一天jsoup文档
周日用Java的三大框架敲了一天打代码
周一课余时间内改了改其中的bug,周一晚上完美运行了
?下面说说具体的思路安排
采用传统项目的三大框架,层层相扣,具有很高的扩展性,对后期项目的改进很好,这三层分别是:
Entity层(实体层)
Dao层(数据访问层)
Service层(业务逻辑层)
?用到的工具分别是:
eclipse
Maven
Mysql
? Entity层定义需要爬到的一些属性,比如小说中的id、小说的章节以及章节名、小说各个章节的链接等等。
package xuf.entity;
public class NovelAttribute {
private String id; // id
private String FictionName; // 小说名
private String FictionChapter; // 小说章节以及章节名
private String FictionUrl; // 章节链接
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getFictionName() {
return FictionName;
}
public void setFictionName(String fictionName) {
FictionName = fictionName;
}
public String getFictionChapter() {
return FictionChapter;
}
public void setFictionChapter(String fictionChapter) {
FictionChapter = fictionChapter;
}
public String getFictionUrl() {
return FictionUrl;
}
public void setFictionUrl(String fictionUrl) {
FictionUrl = fictionUrl;
}
public String toString() {
return "NovelAttribute [id=" + id + ",FictionName=" + FictionName + ", FictionChapter=" + FictionChapter + ","
+ " FictionUrl=" + FictionUrl + "]";
}
}
? dao层则是一些数据处理的内容,通过dao层将数据持久化到mysql数据库中.
package xuf.dao;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
//封装数据持久化类
public class NovelDao {
public static final String driver_class = "com.mysql.jdbc.Driver";
public static final String driver_url = "jdbc:mysql://127.0.0.1/tarantula?useunicode=true&characterEncoding=utf8";
public static final String user = "root";
public static final String password = "root";
private static Connection conn = null;
private PreparedStatement pst = null;
private ResultSet rst = null;
/**
* Connection
*/
public NovelDao() {
try {
conn = NovelDao.getConnInstance();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 单例模式 线程同步
*/
private static synchronized Connection getConnInstance() {
if (conn == null) {
try {
Class.forName(driver_class);
conn = DriverManager.getConnection(driver_url, user, password);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
System.out.println("连接数据库成功");
}
return conn;
}
/**
* close
*/
public void close() {
try {
if (conn != null) {
NovelDao.conn.close();
}
if (pst != null) {
this.pst.close();
}
if (rst != null) {
this.rst.close();
}
System.out.println("关闭数据库成功");
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* query
*/
public ResultSet executeQuery(String sql, List sqlValues) {
try {
pst = conn.prepareStatement(sql);
if (sqlValues != null && sqlValues.size() > 0) {
setSqlValues(pst, sqlValues);
}
rst = pst.executeQuery();
} catch (SQLException e) {
e.printStackTrace();
}
return rst;
}
/**
* update
*/
public int executeUpdate(String sql, List sqlValues) {
int result = -1;
try {
pst = conn.prepareStatement(sql);
if (sqlValues != null && sqlValues.size() > 0) {
setSqlValues(pst, sqlValues);
}
result = pst.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
return result;
}
/**
* sql set value
*/
private void setSqlValues(PreparedStatement pst, List sqlValues) {
for (int i = 0; i < sqlValues.size(); i++) {
try {
pst.setObject(i + 1, sqlValues.get(i));
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
?Service层则是对涉及到的业务逻辑的封装。保存以及处理爬取到的需要的内容。service层包括两个类,分别是:
INovel类:
package xuf.service;
import xuf.entity.NovelAttribute;
public interface INovel {
public int SaveAttribute(NovelAttribute attribute);
}
NovelImpl类:
package xuf.service;
import java.util.ArrayList;
import java.util.List;
import xuf.dao.NovelDao;
import xuf.entity.NovelAttribute;
public class NovelImpl implements INovel {
public int SaveAttribute(NovelAttribute attribute) {
NovelDao novelDao = new NovelDao();
StringBuffer sql = new StringBuffer();
sql.append("insert into novel (`id`,`FictionName`,`FictionChapter`,`FictionUrl`)")
.append("VALUES (? , ? , ? , ?)");
List sqlValues = new ArrayList();
sqlValues.add(attribute.getId());
sqlValues.add("" + attribute.getFictionName());
sqlValues.add("" + attribute.getFictionChapter());
sqlValues.add("" + attribute.getFictionUrl());
int result = novelDao.executeUpdate(sql.toString(), sqlValues);
return result;
}
}
? 最后还得有一个主函数来启动整个爬虫。
package xuf.main;
import java.util.Date;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import xuf.entity.NovelAttribute;
import xuf.service.INovel;
import xuf.service.NovelImpl;
public class SpiderNovel {
public static void main(String[] args) {
// 数据持久化对象,用于将信息存入数据库
INovel iNovel = new NovelImpl();
Long startTime, endTime;
System.out.println("小爬虫开始了。。。。。。。。。。。");
startTime = new Date().getTime();
Document document;
try {
document = Jsoup.connect("http://book.qidian.com/info/1006141474#Catalog").get();
//document = Jsoup.connect("http://book.qidian.com/info/1006693964#Catalog").get();
NovelAttribute novelAttribute = new NovelAttribute();
String fictionName = document.select("h1>em").text();
novelAttribute.setFictionName(fictionName);
Elements results = document.select("a[data-cid]");
for (Element e : results) {
String fictionChapter = e.text();
String fictionUrl = e.attr("abs:href");
novelAttribute.setFictionUrl(fictionUrl);
novelAttribute.setFictionChapter(fictionChapter);
iNovel.SaveAttribute(novelAttribute);
}
} catch (Exception e) {
e.printStackTrace();
}
endTime = new Date().getTime();
System.out.println("小爬虫结束了,用时" + (endTime - startTime) + "ms");
}
}
?最后给出爬到的数据库截图:
?完美的一次项目。最短时间,从接触到写出来,只要了三天时间,事实证明,一件事情,只要你想去做,完全是可以做出来的。这个项目还有一个不足的就是爬取的目标网址被写在代码里面写死了,不具有灵活性。最好是将这个部分的代码写在页面里面,然后通过dao层来处理页面输入的url。
完整Java爬取起点小说网小说目录以及对应链接相关教程