赞
踩
免责声明:不要拿爬虫在法律边缘试探
简单的说,就是进行如下设置:
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 是一个比较好的模拟浏览器的框架,但是在爬虫方面算不上一个比较好的
关于第三个问题,尚没有解决
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。