百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT知识 > 正文

httpclient+jsoup实现小说线上采集阅读

liuian 2025-02-16 21:56 36 浏览

前言

  用过老版本UC看小说的同学都知道,当年版权问题比较松懈,我们可以再UC搜索不同来源的小说,并且阅读,那么它是怎么做的呢?下面让我们自己实现一个小说线上采集阅读。(说明:仅用于技术学习、研究)

  看小说时,最烦的就是有各种广告,这些广告有些是站长放上去的盈利手段,有些是被人恶意注入。在我的上一篇博客中实现了小说采集并保存到本地TXT文件 HttpClients+Jsoup抓取笔趣阁小说,并保存到本地TXT文件,这样我们就可以导入手机用手机阅读软件看小说;那么我们这里实现一个可以在线看小说。

话不多说先看效果

  首页:

  页面很纯净,目前有三种来源

  搜索结果页:

  三个不同的来源,分页用的是layui的laypage,逻辑分页。(笔趣阁的搜索结果界面没有书本的图片)

  翻页效果:

  纵横网连简介等都帮我们分词,搞得数据量太大,速度太慢:books.size() < 888

  书本详情页:

  小说阅读页:


  上、下一章:

代码与分析

  项目是springboot项目,原理非常简单,就是用httpclient构造一个请求头去请求对应的来源链接,用jsoup去解析响应回来的response,

  通过jsoup的选择器去找到我们想要的数据,存入实体,放到ModelAndView里面,前端页面用thymeleaf去取值、遍历数据。

  但是有一些书是要会员才能看,这种情况下我们需要做模拟登陆才能继续采集,这里只是一个简单的采集,就不做模拟登陆了。

  采集过程中碰到的问题:

  1、起点中文网采集书本集合时,想要的数据不在页面源码里面

  起点中文网很机智,他在html代码了没有直接展示page分页信息的链接

  可以看到,httpClient请求回来的response里分页信息标签里面是空的,但用浏览器去请求里面有信息


  这是因为httpClient去模拟我们的浏览器访问某个链接,直接响应回这个链接对应的内容,并不会去帮我们触发其他的ajax,而浏览器回去解析响应回来的html,当碰到img、script、link等标签它会帮我们去ajax请求对应的资源。
  由此推测,page相关的信息,起点中文网是在js代码里面去获取并追加,最后通过network找到它的一些蛛丝马迹

既然他没有写在html里,那我们就自己去创建连接,可以看到html上有当前页跟最大页数

完美

  2、笔趣阁查看书本详情,图片防盗链

  笔趣阁有一个图片防盗,我们在自己的html引入图片路径时,但当我们把链接用浏览器访问时是可以的



  

  对比一下两边的请求头

  首先我们要知道什么事图片防盗链,猛戳这里 -->:图片防盗链原理及应对方法 ;我们直接用大佬的反防盗链方法,并且针对我们的项目改造一下:

    /**
     * 反防盗链
     */
    function showImg(parentObj, url) {
        //来一个随机数
        var frameid = 'frameimg' + Math.random();
        //放在(父页面)window里面   iframe的script标签里面绑定了window.onload,作用:设置iframe的高度、宽度 


book_details






    
    BOOK DETAILS
    
    
    
    


书名:

作者:

简介:

最新章节:

更新时间:

大小:

状态:

类型:

来源:


  book_read






    
    BOOK READ
    


  补充

  2019-07-17补充:我们之前三个来源网站的baseUrl都是用http,但网站后面都升级成了https,例如笔趣阁:


  导致抓取数据时报错






    
    BOOK LIST
    
    
    
    


来源

  解决办法:参考https://blog.csdn.net/xiaoxian8023/article/details/49865335,绕过证书验证

  在BookUtil.java中新增方法

    /**
     * 绕过SSL验证
     */
    private static SSLContext createIgnoreVerifySSL() throws NoSuchAlgorithmException, KeyManagementException {
        SSLContext sc = SSLContext.getInstance("SSLv3");

        // 实现一个X509TrustManager接口,用于绕过验证,不用修改里面的方法
        X509TrustManager trustManager = new X509TrustManager() {
            @Override
            public void checkClientTrusted(
                    java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
                    String paramString) throws CertificateException {
            }

            @Override
            public void checkServerTrusted(
                    java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
                    String paramString) throws CertificateException {
            }

            @Override
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };

        sc.init(null, new TrustManager[]{trustManager}, null);
        return sc;
    }

  然后在gather方法中改成这样获取httpClient

    /**
     * 采集当前url完整response实体.toString()
     *
     * @param url url
     * @return response实体.toString()
     */
    public static String gather(String url, String refererUrl) {
        String result = null;
        try {
            //采用绕过验证的方式处理https请求
            SSLContext sslcontext = createIgnoreVerifySSL();

            // 设置协议http和https对应的处理socket链接工厂的对象
            Registry socketFactoryRegistry = RegistryBuilder.create()
                    .register("http", PlainConnectionSocketFactory.INSTANCE)
                    .register("https", new SSLConnectionSocketFactory(sslcontext))
                    .build();
            PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
            HttpClients.custom().setConnectionManager(connManager);

            //创建自定义的httpclient对象
            CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(connManager).build();


            //创建httpclient对象 (这里设置成全局变量,相对于同一个请求session、cookie会跟着携带过去)
//            CloseableHttpClient httpClient = HttpClients.createDefault();

            //创建get方式请求对象
            HttpGet httpGet = new HttpGet(url);
            httpGet.addHeader("Content-type", "application/json");
            //包装一下
            httpGet.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36");
            httpGet.addHeader("Referer", refererUrl);
            httpGet.addHeader("Connection", "keep-alive");

            //通过请求对象获取响应对象
            CloseableHttpResponse response = httpClient.execute(httpGet);
            //获取结果实体
            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                result = EntityUtils.toString(response.getEntity(), "GBK");
            }

            //释放链接
            response.close();
        }
        //这里还可以捕获超时异常,重新连接抓取
        catch (Exception e) {
            result = null;
            System.err.println("采集操作出错");
            e.printStackTrace();
        }
        return result;
    }

  这样就可以正常抓取了

  我们之前获取项目路径用的是

var ctx = /*[[@{/}]]*/'';

  突然发现不行了,跳转的路径直接是/开头,现在改成这样获取

    //项目路径
    var ctx = [[${#request.getContextPath()}]];

  2019-08-01补充:大家如果看到有这个报错,连接被重置,不要慌张,有可能是网站换域名了比如现在我们程序请求的是http://www.biquge.com.tw,但这个网址已经不能访问了,笔趣阁已经改成https://www.biqudu.net/,我们改一下代码就可以解决问题,要注意检查各个源路径是否能正常访问,同时对方也可能改页面格式,导致我们之前的规则无法匹配获取数据,这种情况只能重新编写爬取规则了


  2019-08-02补充:发现了个bug,我们的BookUtil.insertParams方法原理是替换#字符串

    /**
     * 自动注入参数
     * 例如:
     *
     * @param src    http://search.zongheng.com/s?keyword=#1&pageNo=#2&sort=
     * @param params "斗破苍穹","1"
     * @return http://search.zongheng.com/s?keyword=斗破苍穹&pageNo=1&sort=
     */
    public static String insertParams(String src, String... params) {
        int i = 1;
        for (String param : params) {
            src = src.replaceAll("#" + i, param);
            i++;
        }
        return src;
    }

  但是我们在搜索的时候,调用参数自动注入,形参src的值是来自静态属性Map,初始化的时候有两个#字符串,在进行第一次搜索之后,#字符串被替换了,后面再进行搜索注入参数已经没有#字符串了,因此后面的搜索结果都是第一次的结果...


  解决:获取来源时不是用=赋值,而是复制一份,三个方法都要改

  修改前:

        //获取来源详情
        Map src = source.get(sourceKey);

  修改后:

        //获取来源详情,复制一份
        Map src = new HashMap<>();
        src.putAll(source.get(sourceKey));

  多端开发

  公司最近打算做手机端,学习了DCloud公司的uni-app,开发工具是HBuilderX,并用我们的小说爬虫学习、练手,做了个H5手机端的页面

  DCloud公司官网:https://www.dcloud.io/

  uni-app官网:https://uniapp.dcloud.io/

  uni-app 是一个使用 Vue.js 开发所有前端应用的框架,开发者编写一套代码,可编译到iOS、Android、H5、以及各种小程序等多个平台。

  效果图:

  代码开源

  代码已经开源、托管到我的GitHub、码云:

  GitHub:https://github.com/huanzi-qch/spider

  码云:https://gitee.com/huanzi-qch/spider


版权声明

作者:huanzi-qch

出处:
https://www.cnblogs.com/huanzi-qch

若标题中有“转载”字样,则本文版权归原作者所有。若无转载字样,本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利.

相关推荐

电脑主机开机没反应(电脑主机开机没反应电源灯亮)

操作方法01第一种情况是电脑完全没有反应,那么就可能是电源没有连接上,检查插线板和机箱插头,重新插好就好了。?02还有是电脑机箱已经开启,但是显示屏还是黑的,那么这种情况就有可能是显示屏的电源没有连接...

cad激活码2010(cad激活码和序列号)

1.首先激活码出现问题,需要进行激活确认。首先需要的中进入电脑C盘。2.可以先点击组织设置隐藏文件夹显示。3.勾选显示隐藏文件夹。4.找到C:\ProgramData文件夹,打开找到CAD文件夹。5....

联想windows7笔记本怎么连接网络

检查笔记本的无线网卡驱动1.右键我的电脑,点击“属性”,选择左侧“设备管理器”2.点击“网络适配器”,如果方框内没有驱动,请下载驱动精灵万能网卡版安装网卡驱动 二、若发现驱动前面是感叹号的&...

iphone自动关机设置方法(iphone如何设自动关机)
  • iphone自动关机设置方法(iphone如何设自动关机)
  • iphone自动关机设置方法(iphone如何设自动关机)
  • iphone自动关机设置方法(iphone如何设自动关机)
  • iphone自动关机设置方法(iphone如何设自动关机)
淘宝电脑版网页入口(淘宝网电脑版网页官方)

网站地址:https://www.taobao.com/网站链接:进入网站服务器IP:116.253.191.241网站描述:淘宝网首页,淘宝网-亚洲最大、最安全的网上交易平台,提供各类服饰、美容...

大学生用哪个牌子的笔记本电脑好

荣耀MagicBook14英寸轻薄窄边框笔记本电脑(AMD锐龙58G512GFHDIPS正版Office)冰河银这款的性价比较高。也可以根据自己的预算选同系列其他型号。...

苹果怎么查询手机激活时间(苹果手机如何查询手机激活时间)
  • 苹果怎么查询手机激活时间(苹果手机如何查询手机激活时间)
  • 苹果怎么查询手机激活时间(苹果手机如何查询手机激活时间)
  • 苹果怎么查询手机激活时间(苹果手机如何查询手机激活时间)
  • 苹果怎么查询手机激活时间(苹果手机如何查询手机激活时间)
免费手机模拟器(免费手机模拟器下载)

目前能成功在电脑上模拟苹果系统的iOS模拟器,对比市面上常见的安卓模拟器少太多了,主要原因还是iOS系统比较封闭,难于开发。虽然前面说开发很困难,但是国内还是有一些厉害的IT小组成功推出了iOS模拟器...

免费主题商店app下载(免费主题商店app下载苹果)
  • 免费主题商店app下载(免费主题商店app下载苹果)
  • 免费主题商店app下载(免费主题商店app下载苹果)
  • 免费主题商店app下载(免费主题商店app下载苹果)
  • 免费主题商店app下载(免费主题商店app下载苹果)
新手怎么制作word表格(工作表格制作)

步骤如下:1、本次演示使用的软件为word文字处理软件,软件版本为Microsoftoffice家庭和学生版2016。2、首先打开Excel电子表格,根据问题描述,我们在word中插入两页表格。3、...

电脑开机启动进不了系统怎么办
电脑开机启动进不了系统怎么办

一、修复错误如果频繁无法正常进入系统,则开机后马上按F8,看能否进入安全模式或最后一次配置正确模式,如能则进入后会自动修复注册表,并回忆前几次出现不正常现象时进行了什么操作,并根据怀疑是某个应用软件导致问题产生,将其卸载,然后正常退出,...

2026-01-02 13:05 liuian

win11任务栏隐藏不了(win11任务栏怎么隐藏)

方法/步骤:  1、打开电脑桌面,双击我的计算机。  2、打开控制面板。  3、点击类别切换到大图标或小图标。  4、找到通知区域图标打开。  5、选择显示图标或隐藏图标也可以仅显示通知,选好以后点击...

win10怎么打开系统更新(怎么开启windows10更新)
  • win10怎么打开系统更新(怎么开启windows10更新)
  • win10怎么打开系统更新(怎么开启windows10更新)
  • win10怎么打开系统更新(怎么开启windows10更新)
  • win10怎么打开系统更新(怎么开启windows10更新)
笔记本注册表编辑器怎么打开

你好,要打开注册表编辑器,可以按照以下步骤进行操作:1.打开“运行”对话框。可以通过按下Win+R键组合,或者在开始菜单中搜索“运行”来打开。2.在“运行”对话框中,输入“regedit”并点...

怎样查询ip地址(怎么顺着ip地址找人)

答:查看ip地址的步骤如下,1.通过网页进行查询:可以通过第三方平台进行查询。2.通过电脑内部的网络连接进行查询:首先我们点击桌面右下角的开始,在开始的选项栏当中找到运行,点击运行,然后再用新的对...