2011-09-30 60 views
3

我想獲取網頁的內容作爲字符串,我發現這個問題尋址how to write a basic web crawler,它聲稱(似乎)處理編碼問題,但代碼提供那裏,這適用於美國/英國網站,無法正確處理其他語言。編碼問題抓取非英文網站

下面是一個完整的Java類,演示了什麼,我指的是:

import java.io.IOException; 
import java.io.InputStreamReader; 
import java.io.Reader; 
import java.io.UnsupportedEncodingException; 
import java.net.HttpURLConnection; 
import java.net.MalformedURLException; 
import java.net.URL; 
import java.util.regex.Matcher; 
import java.util.regex.Pattern; 


public class I18NScraper 
{ 
    static 
    { 
     System.setProperty("http.agent", ""); 
    } 

    public static final String IE8_USER_AGENT = "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; WOW64; Trident/4.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; InfoPath.2)"; 

    //https://stackoverflow.com/questions/1381617/simplest-way-to-correctly-load-html-from-web-page-into-a-string-in-java 
    private static final Pattern CHARSET_PATTERN = Pattern.compile("text/html;\\s+charset=([^\\s]+)\\s*"); 
    public static String getPageContentsFromURL(String page) throws UnsupportedEncodingException, MalformedURLException, IOException { 
     Reader r = null; 
     try { 
      URL url = new URL(page); 
      HttpURLConnection con = (HttpURLConnection)url.openConnection(); 
      con.setRequestProperty("User-Agent", IE8_USER_AGENT); 

      Matcher m = CHARSET_PATTERN.matcher(con.getContentType()); 
      /* If Content-Type doesn't match this pre-conception, choose default and 
      * hope for the best. */ 
      String charset = m.matches() ? m.group(1) : "ISO-8859-1"; 
      r = new InputStreamReader(con.getInputStream(),charset); 
      StringBuilder buf = new StringBuilder(); 
      while (true) { 
       int ch = r.read(); 
       if (ch < 0) 
       break; 
       buf.append((char) ch); 
      } 
      return buf.toString(); 
     } finally { 
      if(r != null){ 
       r.close(); 
      } 
     } 
    } 

    private static final Pattern TITLE_PATTERN = Pattern.compile("<title>([^<]*)</title>"); 
    public static String getDesc(String page){ 
     Matcher m = TITLE_PATTERN.matcher(page); 
     if(m.find()) 
      return m.group(1); 
     return page.contains("<title>")+""; 
    } 

    public static void main(String[] args) throws UnsupportedEncodingException, MalformedURLException, IOException{ 
     System.out.println(getDesc(getPageContentsFromURL("http://yandex.ru/yandsearch?text=%D0%A0%D0%B5%D0%B7%D1%83%D0%BB%D1%8C%D1%82%D0%B0%D1%82%D0%BE%D0%B2&lr=223"))); 
    } 
} 

,輸出:

???????????&nbsp;&mdash; ??????: ??????? 360&nbsp;???&nbsp;??????? 

雖然它應該是:

Результатов&nbsp;&mdash; Яндекс: Нашлось 360&nbsp;млн&nbsp;ответов 

燦你幫我明白我在做什麼錯了?嘗試諸如強制UTF-8之類的東西並不能提供幫助,儘管這是源和HTTP標頭中列出的字符集。

+0

您是否試過[Apache Http Client 4.x](http://hc.apache.org/httpcomponents-client-ga/)?我發現它更舒適,更穩定。儘管也應該關注大部分的編碼瘋狂 - 儘管如此,Joel提到的'Joel'元素的處理仍然取決於你,但[EntityUtils](http://hc.apache.org/httpcomponents- core-ga/httpcore/apidocs/org/apache/http/util/EntityUtils.html)有很長的路要走。 –

+0

事實上,你正在'?'而不是U + FFFD在這裏講述。也許對ISO-8859-1有一個隱含的解釋。標準庫的許多部分都默認使用這種編碼。 – wberry

+0

你怎麼知道解碼發生錯誤,而不是調試輸出的編碼?在返回字符串之前,您應該打印字符的數字值並查看它們是什麼作爲檢查。 – erickson

回答

1

您所看到的問題是,Mac上的編碼不支持西里爾文腳本。我不確定它是否在Oracle JVM上是正確的,但當Apple生產自己的JVM時,the default character encoding for Java was MacRoman.

當您啓動程序時,請指定file.encoding系統屬性以將字符編碼設置爲UTF-8(即默認情況下Mac OS X使用的是什麼)。請注意,您必須在啓動時設置它:java -Dfile.encoding=UTF-8 ...;如果以編程方式進行設置(調用System.setProperty()),則爲時已晚,並且該設置將被忽略。

每當Java需要的字符編碼成字節—例如,當它是將文本轉換爲字節寫入到標準輸出或錯誤流—它會使用默認的,除非你明確指定一個不同的。如果默認編碼不能對特定字符進行編碼,則替換適當的替換字符。

如果編碼可以處理使用的Unicode替換字符U + FFFD(&#xFFFD;)。否則,問號(?)是常用的替換字符。

+0

我用我的iMac進行了測試,在java版本「1.6.0_26」上,默認編碼仍然是「MacRoman」。即使我的'LANG'設置爲「en_US.UTF-8」,情況也是如此。 – erickson

+0

添加該系統屬性標誌輸出以下內容: - †-μ-Σ-ª-å-Ç-∞-Ç-æ-≦  —-Ø-Ω-Â-Å-Å:-ù -∞-ª-Å-å298  -º-Ω- -æ-Ç-≤-μ-Ç-æ-≤ – dimo414

+1

這裏我們開始吧!我找到了http://www.ibm.com/developerworks/opensource/library/os-eclipse-osxjava/,它描述瞭如何在eclipse中設置UTF-8。您提到的-D標誌在命令行上正常工作。謝謝你的幫助。 – dimo414

2

確定正確的字符集編碼可能會很棘手。

需要使用的

a)所述HTML META內容類型標籤的組合:

<META http-equiv="Content-Type" content="text/html; charset=EUC-JP"> 

b)該HTTP響應報頭:

Content-Type: text/html; charset=utf-8 

c)中試探法來從字節中檢測字符集(參見this question

使用all thr EE是:

  1. (a)和(b)中可能會丟失
  2. 的META內容類型可能是錯的(見this question

怎麼做,如果(一)和(b )都失蹤了?

在這種情況下,您需要使用一些啓發式來確定正確的編碼 - 請參閱this question

我發現這個序列是最可靠的用於魯棒地識別HTML頁面的字符集編碼:

  1. 使用HTTP響應報頭的Content-Type(如果存在)
  2. 使用的編碼檢測器上的響應內容的字節
  3. 使用HTML META Content-Type的

,但你可以選擇交換2和3

0

Apache Tika包含一個你想在這裏實現的實現。許多人爲此使用它。你也可以看看Apache Nutch。另一方面,那麼你根本就不必實現自己的抓取工具。