Java爬虫学习
一. 学习历程
HTML语言
- HTML是一种超文本语言(HyperText Markup Language),是一种标记语言,而非编程语言,HTML编写的文件在浏览器渲染后就成为了我们所看到的网页界面(在网页界面点击F12即可显示该网页的HTML格式)
- HTML主要包括
<code class="prettyprint" >和
两部分,head部分主要包括标题、脚本、样式等信息,body部分包括网页的主体信息 - 除
<code class="prettyprint" >和
标签外,还有其他的一些标签,如标题为
,段落为
,换行为
,这些标签都可以在
或
下使用
java方法
-
java为了使程序员写代码更加方便,定义了一个java标准类库,里面有各种类,以及各种方法,都是平时写代码时容易用到的,需要使用时直接通过类名和方法名直接调用,有些类在使用时需要import声明
-
方法的命名,我们在需要使用一些java标准类库中没有的方法时,需要自己创建一个类,在创建方法时需要命名方法名,第一个单词应以小写字母作为开头,后面的单词则用大写字母开头写,不使用连接符,标准的方法名有助于理解记忆方法的用途
-
方法的写法,编写方法时的格式如下,注意最后返回值的类型应该和头部声明的类型相同,没有返回值时头部应为void
修饰符 返回值类型 方法名(参数类型 参数名){ ... 方法体 ... return 返回值; }
正则表达式
-
正则表达式是一种用来匹配的表达式,比如,在某个网页的搜索框中输入指定格式的表达式,网页就会标记出该格式的字符
-
举个例子
^\d+(\.\d+)?
^ 定义了以什么开始,即标志着正则表达式的开始,\d表示匹配一个随机的0~9数字,\d+表示一个或多个数字,.表示小数点,则.\d+就表示小数,()?表示可有可无,这些合在一起就表示一个整数或小数 -
·pattern 对象是一个正则表达式的编译表示。Pattern 类没有公共构造方法。要创建一个 Pattern 对象,你必须首先调用其公共静态编译方法,它返回一个 Pattern 对象。该方法接受一个正则表达式作为它的第一个参数。在我理解它就是定义了一会要匹配的格式
·matcher对象可以对输入的表达式进行解释,同时根据表达式进行匹配
Jsoup和爬虫
- 在进行爬虫前需要新建maven项目以及在pom中导入依赖,但依赖具体是干什么的我也不是很清楚,就不多说了
- Jsoup可以用来连接某网站获取html文档,
Document document = Jsoup.connect("https://www.xbiquge.so/book/10415/").get();
此行代码可以通过Jsoup连接到小说网站获得其html文档 -
css选择器,可以帮你选择指定网页html文档中的指定标签内容, 如下第一行代码可以选择到dl下的dd标签的所有内容,第二行可以选择到a标签具有herf属性的标签
Elements menu = document.body().select"dl dd"; Elements as = menu.select("a[herf]");
二. 问题存疑
- 爬取出的小说只有文本,换行符空格那些完全没有,导致爬出来后时一团,很难受,始终做不到可以把换行符一起爬出来,也有想过用css选择器选择
标签,然后爬出来,但是不知道怎么把换行符和文本一起爬出来 - 还有就是目录问题,目录我就是把每节的标题爬下来了,然后做了超链接,让他链接到各自的网页上,但是,它依旧很乱,不晓得怎么把它搞得整齐,好看一点(我是把爬出来的小说保存成md形式了)
三.代码
import org.jsoup.nodes.Element;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
import java.io.*;
import java.util.Scanner;
public class Main {
public static void main(String[] args) throws IOException {
/*
* 声明一些常量、变量
*/
String menuUrl = "https://www.aixiaxsw.com/111/111972/";//默认目录页
final String fileAddr = "./";
Scanner scanner = new Scanner(System.in);
System.out.println("输入1则根据下次输入的目录URL爬取(URL模板示例:https://www.aixiaxsw.com/111/111972/),输入2则爬取示例小说《超能星武》");
if(scanner.nextInt()==1) {
menuUrl = scanner.next();
if(menuUrl.startsWith("www.aixiaxsw.com"))
menuUrl = "https://" + menuUrl;
if(!menuUrl.endsWith("/"))
menuUrl = menuUrl + "/";
if(!menuUrl.startsWith("http://www.aixiaxsw.com")){
if(!menuUrl.startsWith("https://www.aixiaxsw.com")){
System.out.println("请输入爱下书小说网小说目录的URL\n请稍后重新输入");
System.exit(0);
}
}
}
/*
* 访问目录页,获取小说名、章节名、章节链接
*/
Document document = null;//新建一个文档
try {
document = Jsoup.connect(menuUrl).get();
} catch (IOException ewww) {
ewww.printStackTrace();
}
String title = document.body().selectFirst("h1").text();
String author = document.body().selectFirst("p").text();
System.out.println("开始爬取:"+title);
Elements menu = document.body().select("dl dd");//选择父元素为dl的所有dd标签
Elements as = menu.select("a[href]");
/*
* 新建文件、文件流
*/
System.out.println("小说将保存在:"+fileAddr + title+".md 中");
File file = new File(fileAddr + title+".md");
OutputStream fileOut = null;
try {
fileOut = new FileOutputStream(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
// 在向文件中输出每一章节前,先输出小说名
fileOut.write(("#"+title+"\n"+"*"+author+"*"+"\n\n"+"##目录##"+"\n\n").getBytes());
/*保存目录到文件中
*
*/
System.out.println("正在爬取小说目录...");
int count1 = 1;
for(Element a : as){
if(count1<=9){
count1++;
continue;
}
String chapterName = a.text();
String subLink = a.attr("href");
fileOut.write(("["+chapterName + "](https://www.aixiaxsw.com/"+subLink+")" + " ").getBytes());
}
fileOut.write(("\n\n##正文##").getBytes());
/*
* 保存每个章节的正文到文件中
*/
int count = 1;
//循环操作每个章节
for (Element a : as){
if(count<=9){
count++;
continue;
} //跳过最新章节
String subLink = a.attr("href"); //章节链接
String chapterName = a.text(); //章节名称
System.out.println("当前爬取章节:"+chapterName);
Document chapter = null;
try {
chapter = Jsoup.connect("https://www.aixiaxsw.com/"+subLink).timeout(10000).get();
} catch (IOException ewww) {
ewww.printStackTrace();
}
Element chapterContent = chapter.selectFirst("#content");
fileOut.write(("\n\n###" + chapterName + "###\n\n " + chapterContent.text()).getBytes());
}
System.out.println("小说爬取完成");
fileOut.close();
}
}