htmlunit设置支持js和 ajax

免责声明:不要拿爬虫在法律边缘试探

简单的说,就是进行如下设置:

webclient.getOptions().setUseInsecureSSL(true);
// 禁用css ,一般来说 css没啥用
webclient.getOptions().setCssEnabled(false);
webclient.getOptions().setThrowExceptionOnFailingStatusCode(false);
// 设置支持 js
webclient.getOptions().setJavaScriptEnabled(true);
// 不抛出异常
webclient.getOptions().setThrowExceptionOnScriptError(false);
webclient.getOptions().setDoNotTrackEnabled(true);
// 最好设置一下超时
webclient.getOptions().setTimeout(5*1000);
// 支持ajax
webclient.setAjaxController(new NicelyResynchronizingAjaxController());

如果简单的看,这样也就解决了,但是我们试着回想一下,当我们自己打开网页的时候是不是都得等半天(有一段时间,肯定不是半天),于是问题来了,如果我们直接写代码

HtmlPage page = webclient.getPage(url);

可以确定,如果是比较小的js操作,在你余下操作完成之前,js可能能够执行完成,如果是那种比较繁琐的js操作或者是ajax还需要去请求其他服务器的操作,多半在于你余下操作(例如解析html等)之前,js是无法执行完的,那么我们得到的就是不完成的网页。所以设置一个超时时间是很有必要的,也就是这样:

HtmlPage page = webclient.getPage(url);
// TODO: 2019/1/4 10秒钟是为了让js能够充分执行(特别是ajax)
webclient.waitForBackgroundJavaScript(10*1000);
webclient.setJavaScriptTimeout(5*1000);

将上诉代码放到项目中进行测试,我们可以发现可以得到结果了(这里只能说得到了结果,谁也不清楚正确的网页到底爬下来是怎么样的,这是为做一个通用的爬虫准备的,没人能够预测这些不同网站的网页里面的Js究竟会执行多久)。

于是,又出现了几个问题:
1、如何确定某类网站的js平均响应时间,一般来说,同种类型的网站(由于跟响应需求有关,有些网站没必要性能很好这个可以理解)可以算个js平均响应时间。这个时间用来设置 w e b c l i e n t . w a i t F o r B a c k g r o u n d J a v a S c r i p t webclient.waitForBackgroundJavaScript webclient.waitForBackgroundJavaScript
2、是否可以优化js 执行时间
3、如果每个页面都等待那么长时间(而且这种等待是必然每个页面都会等待),那么如果量比较大,比如爬取一千个不同的网站,该如何优化,使得整体的性能不至于非常差。

留坑:
1、第一个问题的本质是我该如何进行测试
2、第二个问题个人觉得应该从 htmlunit 选择浏览器,设置 js 引擎和 ajax 支持出发去优化
3、到第三个问题,是在前两个问题已经确定的情况下进行优化的,需要对遍历算法和线程池进行优化

第一个问题,我的解决办法是 写一个动态的方法来记录页面的加载时间,主要在数据库中存储这几个字段

字段名 字段含义 字段类型
url 网页地址 string
size 当前检查的网页大小 double
waittime 等待js的执行时间 double
netaffect 上一次结果是否受网络影响 int
maxsize 记录中页面最大是多大 double

作为维护的中间变量,然后每一次通过一定的算法自动调节等待的时间,也就是说,对于每一个页面动态的根据相关算法调整等待js的执行时间。代码例子如下:

@Override
    public HtmlPage executeReq(double handletime) {
        int time = 1;
        ArrayList<String> cache = redisDao.getMultiValue(url);
        double lastpagesize = 0.0*-1;
        double lasthandletime = 1000;
        double maxsize = 0.0*-1;
        int affect = -1;
        if (cache != null){
            lastpagesize = Double.parseDouble(cache.get(0));
            lasthandletime = Double.parseDouble(cache.get(1));
            maxsize = Double.parseDouble(cache.get(2));
            affect = Integer.parseInt(cache.get(3));
        }
        if (affect == 1){
            handletime = handletime/2.0;
        }
        while (time <= 5) {
            try {
                HtmlPage page = webclient.getPage(url);
                // TODO: 2019/1/4 线程休息五秒钟是为了让js能够充分执行(特别是ajax)
                webclient.waitForBackgroundJavaScript((long) (handletime*1000));
                webclient.setJavaScriptTimeout(5*1000);
                // TODO: 2019/1/7 判断当前page大小与上一次page大小的关系,如果小于之前page的一半就重新尝试,并且保留最大的那一次
                double pagesize = page.asXml().length();
                if ((lastpagesize - 2*pagesize) <  -1*0.0001){
                    endpage = pagesize>endsize?page:endpage;
                    endsize = Math.max(pagesize, endsize);
                    jiangeshijian = pagesize>endsize?handletime:jiangeshijian;
                    if (time < 5){
                        handletime = handletime + 1.0;
                        continue;
                    }
                }else {
                    endpage = page;
                    endsize = pagesize;
                    jiangeshijian = handletime;
                }
                ArrayList<String> value = new ArrayList<String>();
                String toredissize = "";
                toredissize = toredissize + endsize;
                String toredistime = "";
                toredistime = toredistime + jiangeshijian;
                value.add(toredissize);
                value.add(toredistime);
                if (maxsize < endsize){
                    value.add(toredissize);
                }else {
                    String toredismaxsize = "" + maxsize;
                    value.add(toredismaxsize);
                    if (jiangeshijian > lasthandletime){
                        value.add("1");
                    }else {
                        value.add("0");
                    }
                }
                redisDao.setMultiValue(url,value);
                return endpage;
            } catch (IOException e) {
                e.printStackTrace();
            }
            time++;
        }
        return null;
    }

这里我将维护的信息放到redis里面的

关于第二个问题,我在咨询了技术大佬之后,他建议我用一个真正的爬虫来做,htmlunit 是一个比较好的模拟浏览器的框架,但是在爬虫方面算不上一个比较好的

关于第三个问题,尚没有解决

你可能感兴趣的:(java,利用搜索引擎进行资源收集)