維護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。