维护WHLCCrawler:
这个爬虫之前跑不通的原因:
1.之前的作者写的工具类,里面的重定向出现了问题,没有重定向成功。
解决方案:
我重新声明一个httpclient,不过用的还是defaultHttpclient的方式,这个方式早已经过时了,但是我需要他前面操作然后获取他的cookie,用最新的方式的话,全部都要大改,所以我就跟着他先用着过时的方法,把之前进行操作的cookie放进去。放进去以后,手动完成重定向,他返回302状态后,在返回的response中取出header,在header中取出location,把location当做新的url了,用之前的parma再重新访问一遍,如果返回的是301则重复上诉操作。
HttpResponse res = client.execute(post);
int status = res.getStatusLine().getStatusCode();
if(res.getStatusLine().getStatusCode() == HttpStatus.SC_MOVED_TEMPORARILY){
Header[] header ;
header = res.getHeaders("Location");
String location = header[0].getValue();
HttpPost post2 = new HttpPost(location);
post2.setEntity(entity);
DefaultHttpClient client2 = httpClientProxy.generateClient();
client2.setCookieStore(httpClientProxy.getCookieStore());
HttpResponse res2 = client2.execute(post2);
int status2 = res2.getStatusLine().getStatusCode();
if(res2.getStatusLine().getStatusCode() == HttpStatus.SC_MOVED_PERMANENTLY){
Header[] header2 ;
header2 = res2.getHeaders("Location");
String location2 = header2[0].getValue();
HttpPost post3 = new HttpPost(location2);
post3.setEntity(entity);
DefaultHttpClient client3 = httpClientProxy.generateClient();
client3.setCookieStore(httpClientProxy.getCookieStore());
HttpResponse res3 = client3.execute(post3);
int status3 = res3.getStatusLine().getStatusCode();
routeScheduleResponse = EntityUtils.toString(res3.getEntity());
System.out.print(routeScheduleResponse);
}
}
复制代码
2.返回的response是乱码
解决方案:观察response header里面,他的contenttype是gzip,就说明了网站把数据进行了压缩,我们获取到是压缩过得数据,想要获得正确的数据,就必须解码,解码成utf-8。因为原作者是直接返回的String,所以我在他原工具类里面,添加了一个判断,判断header里面的contenttype是否为gzip,是的话,就进行转码,不是的话,也不影响之前的功能。
转码实现方式:因为返回来的是String,先用inputStream输入流来接收他,再传进去gzip输入流。
InputStream in = response.getEntity().getContent();
GZIPInputStream gzin = new GZIPInputStream(in);
InputStreamReader isr = new InputStreamReader(gzin,"utf-8");
StringBuilder buffer = new StringBuilder();
BufferedReader reader = null;
reader = new BufferedReader(isr);
String line = null;
while ((line = reader.readLine()) != null) {
buffer.append(line + "\n");
}
reader.close();
body = buffer.toString();
复制代码
3.特定的por和特定的fnd不能返回正确的结果 解决方案:因为这个爬虫之前的逻辑是,模拟输入出发国家,模拟输入出发城市,再模拟目的国家,然后把进行完这些操作的cookie传给要进行submit操作的client就能返回正确的结果。而当进行模拟输出出发国家时,他会返回默认的出发国家,如果我们刚好给的数据就是这个默认的国家的话,就不用进行模拟出发城市的操作,而我之前是进行的,可能这个cookie就是错的,他往下面执行,就不能获取正确的结果。
所以我在进行模拟输入出发城市的时候,会获取默认城市,跟我要搜索的城市进行比较。
private boolean checkFromCity(String response,String fromCity) {
// TODO Auto-generated method stub
Parser parser;
try {
parser = Parser.createParser(new String(response.getBytes(), encode_UTF8), encode_UTF8);
parser.setEncoding(parser.getEncoding());
String defaultOption = parserOptionNode(parser, CSS_OPTION_SELECTED, ATTRIBUTE_VALUE);
if(defaultOption.equals(fromCity)){
return true;
}else{
return false;
}
} catch (UnsupportedEncodingException e) {
throw new UnRetriableException(RoboticsException.TYPE_UNKNOWN, "parser defaultOption from search index page meet encoding error!", e);
} catch (ParserException e) {
throw new UnRetriableException(RoboticsException.TYPE_UNKNOWN, "parser defaultOption from search index page meet parser error!", e);
}
}
private String parserOptionNode(Parser parser, String css, String attribute) throws ParserException {
// TODO Auto-generated method stub
NodeList searchResultNodes = extractNodesByCss(parser, css);
if (null == searchResultNodes || searchResultNodes.size() < 1) {
throw new RetriableException(RoboticsException.TYPE_UNEXPECTED_RESPONSE, "Can not get " + css + " element from route search page!", null);
}
OptionTag inputTag = (OptionTag) searchResultNodes.elementAt(1);
String value = inputTag.getAttribute(attribute);
return value;
}
private NodeList extractNodesByCss(Parser parser, String css) throws ParserException {
parser.reset();
CssSelectorNodeFilter searchResultFilter = new CssSelectorNodeFilter(css);
NodeList searchResultNodes = parser.extractAllNodesThatMatch(searchResultFilter);
return searchResultNodes;
}
复制代码
这里学到一个很重要的东西,怎么把页面转成可解析的html然后根据css的值来取value。
首先把response转成parse,parse是一个HTML解析器。CssSelectorNodeFilter searchResultFilter = new CssSelectorNodeFilter(css);這一句相当于设置一个过滤,NodeList searchResultNodes = parser.extractAllNodesThatMatch(searchResultFilter);然后装载,把符合条件的的节点放在NodeList中。然后我要的节点在索引1的位置,取出索引1的的值,我取得节点标签是option,就用optionTag来接收,然后用.getAttribute(attribute);来获取这个节点里面的值,我要获取的是他的value,所以atribute的值是value。