软件园学生在线

  • {{ item.name }}
  • 2023试用期

登录与注册

【后端二】沈怀瑾

  • 沈 怀瑾
  • 2022-10-23
  • 0

基于Jsoup的网文爬虫

一、正则表达式

用处:检验字符串是否满足一定的规则(用来查找特定内容),并用来核验数据结构的合法性。

字符类(只匹配一个字符)

[abc] 只能是abc
[^abc] 除abc以外的其他字符
[a-zA-Z] a到z,A到Z
[a-d[m-p]] a到z或m到p
[a-z&&[ ^bc]] a到z和非bc的交集

预定义字符(只匹配一个字符)

. 任何字符
\d 一个数字:[0-9]
\D 非数字:[ ^0-9]
\s 一个空白字符[\t\n\x0B\f\r]
\S 非空白字符
\w [a-zA-Z_0-9]英文、数字、下划线
\W [ ^\w]

数量用词

X? X,一次或零次
**X*** X,零次或多次
X+ X,一次或多次
X{n} X,正好n次
X{n,} X,至少n次
X{n,m} X,至少n次且不超过m次

例子:

//判断网址输入是否合法
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入要爬取的小说网址");
        String URL = sc.next();
        if(URL.matches("[h-t]{5}://w{3}.aixiaxsw.\\w*")){
            System.out.println("1");
        }else{
            System.out.println("0");
        }

二、try,catch and throw

  • try:定义一个代码块,以便在执行时进行错误调试。当发生错误时,拋出一个相应的异常对象。之后程序会跳过 try 语句块中剩余的语句,转到 catch 语句块后面的第一条语句开始执行。
  • catch:当try中发生错误时,依据所拋出异常对象的类型进行捕获,并执行catch中的代码。如果 try 语句块中没有异常发生,那么 try 正常结束,后面的 catch 语句被跳过,程序将从 catch 语句块后的第一条语句开始执行。
  • finally:在try…catch后执行代码,无论结果。

例子:

try {
            document = Jsoup.connect(menuUrl).get();
        } catch (IllegalArgumentException e) {                         //判断输入内容是否为网址
            e.printStackTrace();
            System.out.println("输入类型非法,请输入网址");
            System.exit(0);
        } catch (UnknownHostException e){                              //判断网络状况
            e.printStackTrace();
            System.out.println("网络状况不佳,请检查您的网络连接");
            System.exit(0);

注:try后面可以加多个catch,匹配多种错误类型。

  • throws:当一个方法产生一个它不处理的异常时,那么就需要在该方法的头部声明这个异常,以便将该异常传递到方法的外部进行处理。使用 throws 声明的方法表示此方法不处理异常。public static void main(String[] args) throws IOException {(来自zxgg原码)

  • throw:throw 语句用来直接拋出一个异常,后接一个可拋出的异常类对象。

throws和throw不是很明白,只是会用一点点 什么复制粘贴大师

Java中的部分异常类型

  • 算数异常:ArithmeticException
  • 空指针异常:NullPointerException
  • 类型强制转换异常:ClassCastException
  • 文件未找到异常:FileNotFoundException
  • 数组下标越界异常;ArrayIndexOutOfBoundsException

依靠异常类型的不同,可以实现对爬取小说中用户网络质量的判断(UnknownHostException)、网址不合法(IllegalArgumentException)等的判断。(代码见上)

三、Jsoup.connect的部分知识

Jsoup含义:Jsoup是一款Java的HTML解析器,主要用来对HTML解析。

org.jsoup.Jsoup把输入的HTML转换成一个org.jsoup.nodes.Document对象,然后从Document对象中取出想要的元素。然后利用Jsoup.connect方法可以返回一个org.jsoup.Connection对象,在该对象中就可以使用get和post来执行请求了。

四、简单CSS选择器

选择器 例子 描述
.class(类选择器) .intro 选取所有 class="intro" 的元素
#(id 选择器) #firstname 选取 id="firstname" 的那个元素
*(通用选择器) * 选取所有元素
element(元素选择器) p 选取所有 \

元素

element,element,..(分组选择器) div,p 选取所有 \

元素和所有 \

元素

元素选择器和分组选择器都只需要打标签名,分组选择器可以节省代码。

五、产品介绍

该产品实现了爬取爱小说网站上所有小说的功能。在运行时输入2将爬取示例小说《天灾之龙》,输入1则需要用户输入爱小说网站上的任意一本小说,而后进行爬取。
该爬虫程序在爬取小说目录时可自动为目录添加超链接,以实现了在.md格式下小说标题、目录、正文的合理排版。
实现了对用户输入网址不正确、输入内容非网址以及网络质量不佳三种情况的处理,并能有对用户的明显提示信息。
附代码:

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.jsoup.select.Selector;

import java.io.*;
import java.net.UnknownHostException;
import java.util.Scanner;

/*作者
* 沈怀瑾
 */

public class spider {
    public static void main(String[] args) throws IOException {

        String menuUrl = "https://www.aixiaxsw.com/105/105503/";
        String menuUrl2 = "https://www.aixiaxsw.com";
        final String fileAddr = "./";
        Scanner sc = new Scanner(System.in);
        System.out.println("输入1则根据下次输入的目录爬取,输入2则爬取示例小说《天灾之龙》");
        if(sc.nextInt()==1){
            menuUrl = sc.next();
        }

        //访问目录,获取小说名、作者名、章节名、章节链接
        Document document =null;
        try {
            document = Jsoup.connect(menuUrl).get();
        } catch (IllegalArgumentException e) {                         //判断输入内容是否为网址
            e.printStackTrace();
            System.out.println("输入类型非法,请输入网址");
            System.exit(0);
        } catch (UnknownHostException e){                              //判断网络状况
            e.printStackTrace();
            System.out.println("网络状况不佳,请检查您的网络连接");
            System.exit(0);
        }
        String title = null;
        String author = null;
        try{
            title = document.body().selectFirst("h1").text();
            author = document.body().selectFirst("p").text();
            System.out.println("开始爬取:"+title);
        }catch(Exception e){
            System.out.println("网址错误,请输入正确的网址!!");
            System.exit(0);                                      //判断网址是否正确
        }
        Elements menu = document.body().select("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\n").getBytes());
        fileOut.write(("##### "+author+"\n\n").getBytes());

        //循环每个章节

        //写入目录
        int count1 = 1;
        for (Element a : as ){
            if(count1<=9){
                count1++;
                continue;
            }
            String chapterName = a.text();
            String subLink = a.attr("href");
            fileOut.write(( "#### "+"["+chapterName+"]"+"("+menuUrl2+subLink+")"+"\n").getBytes());
        }

        //写入文章内容
        int count2 = 1;
        for (Element a : as ){
            if(count2<=9){
                count2++;
                continue;
            }
            String subLink = a.attr("href");
            String chapterName = a.text();
            System.out.println("当前爬取章节:"+chapterName);
            Document chapter = null;
            try {
                chapter = Jsoup.connect(menuUrl2+subLink).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();
    }
}
沈 怀瑾
沈 怀瑾
© 2025 软件园学生在线
Theme by Wing