维护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。