软件园学生在线

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

登录与注册

【后端二】郭雨欣

  • 郭 雨欣
  • 2022-10-22
  • 1

第一次爬虫笔记

培训

学习到了简单爬虫程序:

线上的时候没有很多时间来细细读代码,一遍过去只能说是懵的.

但是多跟几遍录屏,搜索了很多资料和动手实践后对代码的理解越来越多.

学习过程

规范用户输入url

可能不小心没审到要换个网站的句子,我首先把学长的代码跟着录屏复制下来,

然后考虑用户输入的规范性.

考虑过自动补全或修正用户输入的url的想法,查了资料...没能实现

这个class在IDEA里并没有报错...但也运行不起来

public class  GetProtocol {
    private final  static String HTTP= "http://";
    private final  static  String HTTPS =  "https://";
    private String newurl;

    //判断协议 能连接上则协议正确
    public  String getProtocol(String url) {
        newurl = clearUrl(url);
        url = HTTP + newurl;
        if (exists(url)) {
            return url;
        } else {
            url = HTTPS + newurl;
            if (exists(url)) {
                return url;
            } else {
                return null;
            }
        }

    }
    //清除URL里多余的符号
    private  String clearUrl(String url) {
        if (url.contains(HTTP)) {
            url = url.substring(url.lastIndexOf(HTTP) + HTTP.length());
            for (int i = 0; i < url.length(); i++) {
                if (url.charAt(i) == '/' || url.charAt(i) == '.'
                        || url.charAt(i) == '\\') {
                } else {
                    url = url.substring(i);
                    return url;
                }
            }
        } else if (url.contains(HTTPS)) {
            url = url.substring(url.lastIndexOf(HTTPS) + HTTPS.length());
            for (int i = 0; i < url.length(); i++) {
                if (url.charAt(i) == '/' || url.charAt(i) == '.'
                        || url.charAt(i) == '\\') {
                } else {
                    url = url.substring(i);
                    return url;
                }
            }
        }else{
            for (int i = 0; i < url.length(); i++) {
                if (url.charAt(i) == '/' || url.charAt(i) == '.'
                        || url.charAt(i) == '\\') {
                } else {
                    url = url.substring(i);
                    return url;
                }
            }
        }
        return url;
    }
    //是否能连接上
   private  boolean exists(String url) {
        try {
            HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection();
            con.setConnectTimeout(3000);
            return (con.getResponseCode() == 200);
        } catch (Exception e) {
            return false;
        }
    }
}

emmmm所以最后采用文明用语.温馨提示

System.out.println("请输入https://www.xbiquge.so/(笔趣阁)中的小说目录网址");//此时还没换网站
System.out.println("否则无法运行:");//天真的我此时还不知道为什么不能运行(T^T)

接着加上作者名,目录名

作者名好办,直接模仿,刚好是第一个p标签

String author = document.body().selectFirst("p").text();

目录名就...//此处省略一千字痛苦过程

这里查阅资料了解了一些select的用法(中途还有一些find,但是我并没有用到)

  1. 标签名查找

    Elements as = menu.select("a[href]");//这里还带了属性
    
    Elements menu = document.body().select("dl dd")//可以用多个一起
  2. id名来查找

    Elements elements = document.select("#conten");
  3. class名查找

    Elements elements = document.select(".box_con");//尝试过,但是出现好多杂乱的信息,感觉不太美观  

​ 还有一些根据文本内容,和正则表达式一起运用等等.

最终采用了Elements elements = document.select("#list");

​ 然后琢磨怎么才能跳过最新章节...由于dt和dd在小说html里我看着不是父子元素,我也不清楚如何跳过去,删除,或设置内容查重来达到

除去最新章节的效果(这些相关资料都查了,但真的真的还是没找到解决办法,很无奈...)

查询过程中了解了索引index一些知识,问题是这本小说在96之后是正文章节,不一定其他的是...

开始对文本内容琢磨

首先把文本内容变成字符串待处理

Element chapterContent = chapter.selectFirst("#content");
String content = chapterContent.text();//尽管我不清楚会不会占太多空间

然后思考怎么分段落,这内容一出来就是一条线...(此处再次省略一千次的痛苦查询过程)

尽管我已经知道是因为\
与\r\n转换的问题

有一些解决方案比如:用模拟浏览器的方法抓取网页,先进行页面处理替换再替换回来,于是兴冲冲去搜索下一秒就哭了,能写简单爬虫也是因为有一个模板,而且我也不知道怎么先进行页面处理.

于是我只能考虑把"。"换成"。+\n"

一开始只找到了replaceAll方法,并没有意识到这个一定要用正则匹配(给我狠狠学)

开始大量试错,期间找到了中文标点符号对应(这里找到一个转码小软件)

  • 。:\u3002
  • ;:\uff1b
  • ,:\uff0c
  • ::\uff1a
  • “ ”:\u201c\u201d
  • ():\uff08\uff09
  • 、:\u3001
  • ?:\uff1f
  • 《》:\u300a\u300b

但是说实话,这里的"。"表达要用"\u3002",我还是更喜欢用replace直接换

String content1 = content.replaceAll("\u3002","\u3002\n\n");

    fileOut.write(("\n\n" + "## " + chapterName + "\n\n " + content1).getBytes());
}

顺便把目录也顺顺//尽管我后面觉得有了二级标题就不需要目录页了...

String cata1 = cata.replace("第","\n第");//原本打算用markdown表格的,但...一言难尽

加入一级和二级标题

String title1 = "# " + title + "    ";

String cata1 = cata.replace("第","\n第");

fileOut.write((title1+"\n\n" + author + "\n\n" + cata1 ).getBytes());
fileOut.write(("\n\n" + "## " + chapterName + "\n\n " + content1).getBytes());

终于发现要改网站了

刚开始我并没有意识到事情的严重性

单纯把url换了下

String menuUrl = "https://www.aixiaxsw.com/100/100677/";//默认目录页

开始不断运行,不断报错...//以后一定要重视报错里的提示,可以先变成中文看看大意

刚开始排查错误找的也只是menuurl

后面才看到是因为这个网站的menuurl+sublink合并起来重了...天呐

try {
                chapter = Jsoup.connect(menuUrl+subLink).timeout(10000).get();
            } catch (IOException ewww) {
                ewww.printStackTrace();
            }

然后很快就改好了

try {
                String url2 = "https://www.aixiaxsw.com/";
                chapter = Jsoup.connect(url2+subLink).timeout(10000).get();
            } catch (IOException ewww) {
                ewww.printStackTrace();
            }

虽然已经打了jar包了,但是不清楚代码是否要复制在这里...

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

import java.io.*;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

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

        String menuUrl = "https://www.aixiaxsw.com/100/100677/";//默认目录页
        final String fileAddr = "./";
        Scanner scanner = new Scanner(System.in);
        System.out.println("输入1则根据下次输入的目录爬取,输入2则爬取示例小说《我在冥界当萌新》");
        if(scanner.nextInt()==1) {
            System.out.println("请输入https://www.aixiaxsw.com/(爱下书小说网)中的小说目录网址");
            System.out.println("否则无法运行:");
            menuUrl = scanner.next();

        }

//这个部分是标题,作者,目录
        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();
        Elements catalogue = document.body().select("#list");
        String cata = catalogue.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();
        }

        String title1 = "# " + title + "    ";

        String cata1 = cata.replace("第","\n第");

        fileOut.write((title1+"\n\n" + author + "\n\n" + cata1 ).getBytes());

        int count = 1;
        //循环操作每个章节
        for (Element a : as){
            if(count<=12){
                count++;
                continue;
            }
            String subLink = a.attr("href");
            String chapterName = a.text();
            System.out.println("当前爬取章节:"+chapterName);
            Document chapter = null;

            try {
                String url2 = "https://www.aixiaxsw.com/";
                chapter = Jsoup.connect(url2+subLink).timeout(10000).get();
            } catch (IOException ewww) {
                ewww.printStackTrace();
            }

            Element chapterContent = chapter.selectFirst("#content");
            String content = chapterContent.text();
            String content1 = content.replaceAll("\u3002","\u3002\n\n");

            fileOut.write(("\n\n" + "## " + chapterName + "\n\n " + content1).getBytes());
        }

        System.out.println("小说爬取完成");
        fileOut.close();

    }
}

体会

​ 很巧,第一节IDEA实验课助教没来,我参加了这周四的java讲座(两大总监都在,可惜在108...(T^T))

听了好多学姐学长的经验分享,学习分享,会有一种很奇妙的感觉.很庆幸当初勇敢地去了学线的面试,然后收获了敲代码的快乐.

尽管我知道这代码迟早要敲,但是在IDEA实验课上看到大部分同学生疏的新建文件,犹豫着敲下main方法的时候,在听到学长强调一定要多敲代码的时候,会很感激培训时懵逼地敲下一串东西,慢慢有了更深的理解,在运行成功时的那种开心.

因为培训的内容和作业让我不得不去搜索知识,学习一些java知识.(作业让我又爱又恨就是了!!!)

在java课学习过程中,才发现那些知识让我能更容易去理解老师新课的内容,更快地接受

//就是一些听了讲座很奇妙的体会

郭 雨欣
郭 雨欣
© 2025 软件园学生在线
Theme by Wing