爬蟲學習日記(八)

KIM曉峰發表於2019-01-18

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

相關文章