到了本系统的重点环节;
主要分为三步走:
1.获取所有图书
查询图书,图书名称,原图书位置,对图书名称进行处理,方便网站查询提高命中率
2.填充图书类型,根据图书名称获取图书列表,然后获取图书的详细内容中的图书类型编码,然后根据图书类型编码获取本地图书路径
3.根据图书源路径,目的路径移动图书
代码如下:
package com.gugu.book;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
public class MoveBook {
// 源文件储存基本路径
static String directoryPath = "F:\\book";
private static String sepa = java.io.File.separator;
// 图书查询失败(网站中图书不存在)
static int errCount = 0;
static Map<String, String> bookTypeMap = new HashMap<String, String>();
public static void main(String[] args) {
// 获取所有书名
List<Book> bookList = getAllBook(directoryPath);
// 获取图书分类号,清洗过图书列表
List<Book> bookList2 = filedBookTypeList(bookList);
// 根据图书类型编号,获取图书需要迁移的路径
List<Book> bookList3 = filedBookTargetPathList(bookList2);
copyFile(bookList3);
}
/**
*
* @Title: copyFile
* @Description: 将图书文件复制到对应路径下
* @param bookList:
* void
*/
private static void copyFile(List<Book> bookList) {
for(Book b : bookList) {
String sourcePath = b.getSourcePath();
String targetPath = b.getTargetPath(); // 没有包含文件名
if(targetPath != null) {
try {
String targetFileName = targetPath + sepa + b.fileName; // 添加文件名称
Files.copy(new File(sourcePath).toPath(), new File(targetFileName).toPath());
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
*
* @Title: filedBookTargetPathList
* @Description: 填充图书目的地址
* @param bookList 图书列表
*/
private static List<Book> filedBookTargetPathList(List<Book> bookList) {
List<Book> bookResultList = new ArrayList<Book>();
getBookTypePathMap(bookList);
for(Book b : bookList) {
String typeCode = b.getTypeCode();
if(bookTypeMap.containsKey(typeCode) && typeCode != null) {
b.targetPath = bookTypeMap.get(typeCode);
bookResultList.add(b);
}else {
// 图书归类失败
System.out.println("图书归类失败:" + b.toString());
}
}
return bookResultList;
}
/**
*
* @Title: getBookTypePathMap
* @Description: 根据图书类型获取图书需要迁移的路径
* @param bookList:
* void
*/
private static void getBookTypePathMap(List<Book> bookList) {
for (Book book : bookList) {
String bookCode = book.typeCode;
if(!bookTypeMap.containsKey(bookCode) && bookCode != null){
String typePath = findTargetPath(bookCode);
if(typePath == null) {
// 查询分类路径失败
System.out.println("查询分类路径失败:"+bookCode);
}else {
System.out.println("分类" + bookCode + ",分类路径:"+typePath);
bookTypeMap.put(bookCode, typePath);
}
}
}
}
/**
*
* @Title: findTargetPath
* @Description: 根据图书类别查询图书路径,由于网站获取图书类别编码比较详细,分类中没有那么详细的分类,使用模糊匹配,并且截取最后一位
* @param bookCode
* @return:
* String
*/
private static String findTargetPath(String bookCode){
String typePath = null;
String typeBasePath = "E:\\book";
List<String> typePathList = getAllTypeContent(typeBasePath);
//截取最后一位判断是否有分类
while(bookCode.length() > 0) {
for (String path : typePathList) {
if(path.contains(bookCode)) {
return path;
}
}
// 截取字符串
bookCode = bookCode.substring(0, bookCode.length()-1);
}
return typePath;
}
/**
*
* @Title: getAllTypeContent
* @Description: 获取图书分类内容,原先已经创建好的路径
* @param typeBasePath
* @return:
* List<String>
*/
private static List<String> getAllTypeContent(String typeBasePath){
List<String> typePathList = new ArrayList<>();
File baseFile = new File(typeBasePath);
if (baseFile.isFile() || !baseFile.exists()) {
return null;
}
File[] files = baseFile.listFiles();
for (File file : files) {
if (file.isDirectory()) {
typePathList.add(file.getAbsolutePath());
typePathList.addAll(getAllTypeContent(file.getAbsolutePath()));
}
}
return typePathList;
}
/**
*
* @Title: filedBookTypeList
* @Description: 填充图书类型
* @param bookList
* @return:
* List<Book>
*/
private static List<Book> filedBookTypeList(List<Book> bookList) {
List<Book> bookResultList = new ArrayList<Book>();
for (Book book : bookList) {
String bookName = book.getName();
String bookTypeCode = getBookTypeCode(bookName);
if(null != bookTypeCode) {
book.setTypeCode(bookTypeCode);
bookResultList.add(book);
// System.out.println("查询图书:" + bookName+",编码:"+ bookTypeCode);
}else {
errCount++;
// System.out.println("查询图书类型失败:" + bookName);
}
}
System.out.println(errCount);
return bookResultList;
}
// 模拟浏览器抓取图书信息,第一次获取图书列表,第二次获取图书内容(主要是图书类型)
private static String getBookTypeCode(String bookName) {
String bookTypeCode = null;
// 获取检索的图书列表
String url = "http://find.nlc.cn/search/doSearch?"
+ "query=" + bookName + "&"
+ "secQuery=&"
+ "actualQuery=" + bookName + "&"
+ "searchType=2&"
+ "docType=%E5%85%A8%E9%83%A8&"
+ "isGroup=isGroup&"
+ "targetFieldLog=%E5%85%A8%E9%83%A8%E5%AD%97%E6%AE%B5&"
+ "fromHome=true";
try {
Document document = Jsoup.connect(url).timeout(3000000).get();
Element listE = document.getElementById("searchresult-items").selectFirst("a"); // 获取图书列表
String bookId = listE.attr("onclick").toString().split("', '")[1];
bookTypeCode = getBookDetailCode(bookName, bookId);
} catch (IOException e) {
e.printStackTrace();
}catch (Exception e) {
// e.printStackTrace();
}
return bookTypeCode;
}
// 获取图书详细信息
private static String getBookDetailCode(String bookName, String bookId) {
String bookTypeCode = null;
// 获取检索的图书列表
String url = "http://find.nlc.cn/search/showDocDetails?"
+ "docId=" + bookId + "&"
+ "dataSource=ucs01&"
+ "query="+bookName;
try {
Document document = Jsoup.connect(url).timeout(3000000).get();
Element listE = document.getElementById("detail-info"); // 获取图书列表
bookTypeCode = listE.toString().split("中图分类")[1].split("<")[0].replace(" ", "").replace(":", "");
} catch (IOException e) {
e.printStackTrace();
}
return bookTypeCode;
}
/**
*
* @Title: getAllBook
* @Description: 获取所有图书,并清除特殊字符
* @param directoryPath
* @return:
* List<Book>
*/
public static List<Book> getAllBook(String directoryPath) {
List<Book> list = new ArrayList<Book>();
File baseFile = new File(directoryPath);
if (baseFile.isFile() || !baseFile.exists()) {
return list;
}
File[] files = baseFile.listFiles();
for (File file : files) {
if (file.isDirectory()) {
list.addAll(getAllBook(file.getAbsolutePath()));
} else {
String sourcePath = file.getAbsolutePath();
String fileName = file.getName();
String bookName = fileName.split(".pdf")[0];
// 处理书名包含版本导致查询不到
if(bookName.contains("(第")) {
bookName = bookName.split("\\(第")[0];
}
bookName = bookName.replace("(中文版)", "");
bookName = bookName.replace("(上册)", "");
bookName = bookName.replace("(下册)", "");
bookName = bookName.replace("(2)", "");
// # 编码导致
bookName = bookName.replace("#", "%23");
Book book = new Book(sourcePath, bookName, fileName);
list.add(book);
}
}
return list;
}
}
// 图书类
class Book{
String sourcePath;// 图书源路径
String name;// 图书名称
String fileName;// 文件名
String typeCode; // 图书类型编码
String targetPath;// 图书目的路径
public Book(String sourcePath, String name, String fileName) {
super();
this.sourcePath = sourcePath;
this.name = name;
this.fileName = fileName;
}
public Book(String sourcePath, String name, String fileName, String typeCode, String targetPath) {
super();
this.sourcePath = sourcePath;
this.name = name;
this.fileName = fileName;
this.typeCode = typeCode;
this.targetPath = targetPath;
}
public String getSourcePath() {
return sourcePath;
}
public void setSourcePath(String sourcePath) {
this.sourcePath = sourcePath;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public String getTypeCode() {
return typeCode;
}
public void setTypeCode(String typeCode) {
this.typeCode = typeCode;
}
public String getTargetPath() {
return targetPath;
}
public void setTargetPath(String targetPath) {
this.targetPath = targetPath;
}
@Override
public String toString() {
return "Book [sourcePath=" + sourcePath + ", name=" + name + ", fileName=" + fileName + ", typeCode=" + typeCode + ", targetPath=" + targetPath + "]";
}
}
只不过最终这个项目的方案,我自己否掉了,主要原因如下
1.命中率不高,原本图书中有259本,网站大约有三十本左右是无法查询到的。
2.图书分类并不能十分符合原本意愿,可能是网站比较大,并不是专门为计算机图书定制的,对于部分图书会存在分类不准确的情况。
反思:通过这个项目,发现自己对于项目的估计太过乐观,也反映了,在少数情况下可能会比较正常,但是数据上去之后,很容易就会出现意外,以及自己对项目的把控能力不足的问题。
图书已经手动分类到百度云上:
链接:https://pan.baidu.com/s/1TRXSt_e7o-mUUL_HVgI-sw 密码:uu2q
对图书有兴趣的可以自行下载,对于项目感兴趣的小伙伴可以提出您的建议,那我将不胜感激