htmlunit设置支持js和 ajax

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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平均响应时间。这个时间用来设置 htmlunit设置支持js和
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 是一个比较好的模拟浏览器的框架,但是在爬虫方面算不上一个比较好的

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


以上是关于htmlunit设置支持js和 ajax的主要内容,如果未能解决你的问题,请参考以下文章

HtmlUnit爬取Ajax动态生成的页面内容

如何用JAVA爬取AJAX加载后的页面

如何使用HtmlUnit显示所有AJAX请求

用htmlunit怎么去获取一个有JS加载的网页信息

htmlunit 和 document.addEventListener

Java使用HtmlUnit抓取js渲染页面