`
NetBus
  • 浏览: 145082 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

HttpClient对URL编码的处理方式解惑!

阅读更多

HttpClient是Apache基金下jakarta commons项目中的一个小项目,该项目封装了对远程地址下载的一些功能,最新版本为3.0。该项目地址:http://jakarta.apache.org/commons/httpclient

最近在编写Spider的时候就用到了HttpClient。在使用过程中发现一个有趣现象:有些URL的编码方式是utf-8,有些URL的编码方式是gbk。他总能够正确识别,但是有些他又不能识别(抓取回来后是乱码)。调用的是:httpMethod.getResponseBodyAsString();  方法。

在进行进一步分析时,发现他对在http头信息中有charset描述的就正确正常识别。如:

  1. HTTP/1.1 200 OK   
  2. Connection: close   
  3. Content-Type: text/html; charset=utf-8  
  4. Set-Cookie: _session_id=066875c3c0530c06c0204b96db403560; domain=iteye.com; path=/   
  5. Vary: Accept-Encoding   
  6. Cache-Control: no-cache   
  7. Content-Encoding: gzip   
  8. Content-Length: 8512  
  9. Date: Fri, 16 Mar 2007 09:02:52 GMT   
  10. Server: lighttpd/1.4.13  

 而没有charset描述信息时,就会是乱码。再查看相关文档时,可以指定URL的编码方式。如:HttpClientParams.setContentCharset("gbk");,指定了编码后,就能够正确识别对应编码的URL了。问题出现了,因URL编码不一样,Spider不可能把URL的编码方式写死。并且只有在抓取回来后才知道编码是否正确。于是再仔细研究一下httpclient的源代码,发现他使用编码的顺序是:http头信息的charset,如果头信息中没有charset,则查找HttpClientParams的contentCharset,如果没有指定编码,则是ISO-8859-1。

  1. /**  
  2.    * Returns the character set from the Content-Type header.  
  3.    *   
  4.    * @param contentheader The content header.  
  5.    * @return String The character set.  
  6.    */  
  7.   protected String getContentCharSet(Header contentheader) {   
  8.       LOG.trace("enter getContentCharSet( Header contentheader )");   
  9.       String charset = null;   
  10.       if (contentheader != null) {   
  11.           HeaderElement values[] = contentheader.getElements();   
  12.           // I expect only one header element to be there   
  13.           // No more. no less   
  14.           if (values.length == 1) {   
  15.               NameValuePair param = values[0].getParameterByName("charset");   
  16.               if (param != null) {   
  17.                   // If I get anything "funny"    
  18.                   // UnsupportedEncondingException will result   
  19.                   charset = param.getValue();   
  20.               }   
  21.           }   
  22.       }   
  23.       if (charset == null) {   
  24.           charset = getParams().getContentCharset();   
  25.           if (LOG.isDebugEnabled()) {   
  26.               LOG.debug("Default charset used: " + charset);   
  27.           }   
  28.       }   
  29.       return charset;   
  30.   }   
  31.   
  32.   
  33.   /**    
  34.   * Returns the default charset to be used for writing content body,     
  35.   * when no charset explicitly specified.    
  36.   * @return The charset    
  37.   */     
  38.  public String getContentCharset() {      
  39.      String charset = (String) getParameter(HTTP_CONTENT_CHARSET);      
  40.      if (charset == null) {      
  41.          LOG.warn("Default content charset not configured, using ISO-8859-1");      
  42.          charset = "ISO-8859-1";      
  43.      }      
  44.      return charset;      
  45.  }     

这个该死的iso-8859-1害了多少人啊(Tomcat对提交的数据处理默认也是iso-8859-1)!!

经过仔细思考后,决定httpclient再封装一次,思路如下:

  1. 先不设定HttpClientParams的charset;
  2. executemethod后,再检查http头信息中的charset是否存在; 
  3. 如果charset存在,返回httpMethod.getResponseBodyAsString();  ;
  4. 如果charset不存在,则先调用httpMethod.getResponseBodyAsString();得到html后,再分析html head的meta的charset <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">;
  5. 从meta中分析出charset后,设置到HttpClientParams的contentCharset;
  6. 再调用httpMethod.getResponseBodyAsString(),并返回该值。

经过以上思路处理后,发现抓回来的URL再也没有乱码了。爽!

以上步骤中,就是第四步稍微麻烦一些,不过,也可以利用第三方的html paser工具来分析meta的charset!

如果没有特别注明,本Blog文章岂为原创。

转贴请注明出处:    http://netbus.iteye.com

分享到:
评论
8 楼 NetBus 2011-08-03  
Invalid uri 'xxx': escaped absolute path not valid

好像uri不支持acsii以外的字符。

这种事情可以学学讯雷的处理办法
1、uri中的路径名字符(非“/”部分,“?”前)默认通过gbk编码。urlencoder类中的方法。
2、服务端返回404,则表示gbk失败,可以尝试utf-8。
3、utf-8再失败,可以偿试%uxxxx的处理办法。

实在不行的话,先GET / ,通过head或者html meta里面取出charset的值,encoding的时候就使用该值。
7 楼 wubaodong 2011-08-03  
maxima 写道
最近也在使用httpclient,遇到问题就是url带中文时httpclient无法识别url,请教lz怎么解决

比如url="http://www.blcu.edu.cn/financial/musicclub/02-sunyanzi/CD3/05%20-%20星期一天气晴我离开你.mp3"
调用: GetMethod getMethod = new GetMethod(url);
报url异常:java.lang.IllegalArgumentException: Invalid uri 'http://www.blcu.edu.cn/financial/musicclub/02-sunyanzi/CD3/05%20-%20星期一天气晴我离开你.mp3': escaped absolute path not valid

at org.apache.commons.httpclient.HttpMethodBase.<init>(HttpMethodBase.java:219)
at org.apache.commons.httpclient.methods.GetMethod.<init>(GetMethod.java:88)


以下为个人理解。目前的规范中,URL是不支持中文的,或者说只支持英文。中文信息加入URL中必须进行转换,具体转换成哪种编码形式跟URL对应的WEB服务器的设置有关。我们平时看到的很多浏览器貌似支持中文,就是地址栏中显示中文,那只是一个假象,只是浏览器本身在这块功能上的一个封装,就是说你写的含中文的URL中它发送请求时会自动进行转码操作,显示的时候又会进行相反的操作让你看到中文。所以我的看法就是,没有办法统一解决URL中含中文的问题,除非你访问的时一个固定的WEB服务,就是中文处理方式确定。
6 楼 maxima 2007-08-17  
最近也在使用httpclient,遇到问题就是url带中文时httpclient无法识别url,请教lz怎么解决

比如url="http://www.blcu.edu.cn/financial/musicclub/02-sunyanzi/CD3/05%20-%20星期一天气晴我离开你.mp3"
调用: GetMethod getMethod = new GetMethod(url);
报url异常:java.lang.IllegalArgumentException: Invalid uri 'http://www.blcu.edu.cn/financial/musicclub/02-sunyanzi/CD3/05%20-%20星期一天气晴我离开你.mp3': escaped absolute path not valid

at org.apache.commons.httpclient.HttpMethodBase.<init>(HttpMethodBase.java:219)
at org.apache.commons.httpclient.methods.GetMethod.<init>(GetMethod.java:88)
5 楼 NetBus 2007-03-20  
楼上的,你说得也有道理,你这种搞法属于内容分析后的结果。
适合0.1%的情况,不过,写程序也需要你这种精神。尽可能的捕捉到所有的可能,并且做好相应的处理程序。
4 楼 caocao 2007-03-19  
NetBus 写道
你这种搞法太费时了,byte to String和分词是一个非常慢的过程。

对于中文来说,服务器文件编码无非就是utf-8或者gbk(gb18030),如果header中没有charset信息,那么meta中肯定是有的。如果meta中都没有charset信息,那说明这个网页可能是小学生弄出来。

退一万步讲如果从meta中取不出来的话,那就只有硬编码采用gbk了,毕竟采用gbk编码的网站要多一些!


我建议的方式是对上述的补充,就是对付小学生搞的网页,既然99.9%都两者必有其一,剩下0.1%用我这个算法也不算慢哦。
我这个算法是基于内容含义来判断编码,理论上准确率相当高,假设不看charset,就算写网页的人把charset写错了也可以准确解码。
3 楼 presses 2007-03-17  
我的步聚:
1:httpMethod.getResponseBody 返回byte[]
2:用new String(byte[],"iso-8859-1")转为String.因为meta里的字符为英文,所以无论html为什么编码,只要里面的meta里有编码信息都能正确显视。(经过几十万个网页的测试,header里有编码信息的网页不足20%,meta里有编码信息的网页超过99.8%)
3:用正则表达式查找meta里的编码是什么。
4:再用new String(byte[],"编码")。

经过几十万个网页的测试,这个方法几乎没什么问题,性能也还可以。
但话说回来,我觉得httpclient比java.net.URL好用的地方是他可以方便地维护http中的session(cookies).如果只是写一般的spider,还不如直接用URL来得直接。
2 楼 NetBus 2007-03-17  
你这种搞法太费时了,byte to String和分词是一个非常慢的过程。

对于中文来说,服务器文件编码无非就是utf-8或者gbk(gb18030),如果header中没有charset信息,那么meta中肯定是有的。如果meta中都没有charset信息,那说明这个网页可能是小学生弄出来。

退一万步讲如果从meta中取不出来的话,那就只有硬编码采用gbk了,毕竟采用gbk编码的网站要多一些!
1 楼 caocao 2007-03-16  
有些网页里面连meta charset也没有的时候咋办呀
建议直接拿返回的Stream开刀,拿到byte[],可以用utf-8尝试解码、分词得到所有汉字词语总数,再用gbk解码,分词也得到一个总数,绝大多数情况下两个统计总数相差悬殊,选大的那个就是了,试试看 ;)
另,这个分词算法可以相当简单,正向最大匹配即可。

相关推荐

    httpclient方式调用url

    本篇文章将深入探讨如何使用HttpClient方式调用URL,以及相关的知识点。 首先,HttpClient允许我们构建复杂的HTTP请求,包括GET、POST以及其他HTTP方法。使用HttpClient调用URL的基本步骤包括创建HttpClient实例、...

    java使用HttpClient通过url下载文件到本地

    在这个特定的场景中,我们利用HttpClient来从指定的URL下载文件到本地。以下是对这个主题的详细阐述: 1. **HttpClient介绍**: HttpClient是一个Java库,支持HTTP/1.1协议以及部分HTTP/2特性。它提供了一组高级...

    基于httpClient的文件编码导入系统

    在IT行业中,基于httpClient的文件编码导入系统是一个常见的应用场景,主要涉及到网络通信和数据处理两个核心领域。HttpClient是Apache开源组织提供的一款强大的HTTP客户端库,它允许开发者在Java环境中发送HTTP请求...

    httpClient和URLConnection的区别

    在Android应用开发中,进行网络通信是常见的任务,其中两种主要的请求方式是使用`HttpURLConnection`和`HttpClient`。虽然两者都能实现HTTP通信,但它们在功能、使用方式和性能上存在一些区别。 首先,Apache ...

    每个web开发者都应该知道的url编码知识

    5. **使用第三方库**:Apache Commons HttpClient等库提供了更高级的URL处理功能,但在使用时也要注意它们可能存在的局限性。 #### 在Web应用程序的每个层次处理URL编码问题 1. **创建URL时始终编码URL**:无论是...

    Android使用HttpClient和HttpsUrlConnection两种方式访问https网站

    本文将详细介绍如何使用`HttpClient`和`HttpsURLConnection`两种方式来访问HTTPS网站,包括验证证书和不验证证书的实现方法。 ### 1. Android中的HttpClient `HttpClient`是Apache提供的一种HTTP客户端库,它支持...

    Java HttpClient 全部的jar包

    在HttpClient中,这个库用于处理URL编码和解码,以及在HTTP请求头或参数中可能涉及到的其他编码问题。 3. `commons-collections-3.2.jar`: Apache Commons Collections提供了对Java集合框架的扩展和增强,包括集合...

    HTTPCLIENT

    在这个主题中,我们将深入探讨HTTPCLIENT、日志(LOGGING)以及编码解码(CODEC)相关的知识点。 首先,我们来关注HTTPCLIENT。Apache HttpClient是Apache软件基金会的一个项目,它提供了一组API,用于实现客户端的...

    httpclient-4.5所需jar包

    7. **commons-codec-x.x.jar**:提供了常见的编码和解码算法,如Base64、URL编码等,HTTPClient在处理编码问题时会用到。 8. **其他可能的依赖库**:根据实际需求,可能还需要包括其他Apache Commons库(如...

    httpclient4.3工具类

    9. **异常处理**:`httpclientUtils`可能会包含对HttpClient抛出的各种异常的处理逻辑,如`IOException`、`HttpException`等,以提供更友好的错误信息和处理方案。 10. **线程安全**:为了适应多线程环境,`...

    httpclient所需lib

    2. **commons-codec-1.6.jar**:这是一个编码解码库,HttpClient依赖它来处理URL编码、Base64编码等,它是进行网络通信时数据编码的关键库。 3. **httpcore-4.2.1.jar**:这是HTTP Core库,提供了HTTP协议的基础...

    org.apache.commons.httpclient相关资源包

    在HttpClient中,这个库用于处理URL编码、MD5哈希等任务,是网络通信中数据转换的重要组成部分。 2. **commons-httpclient-3.0.jar**:这就是Apache HttpClient的核心库,提供了HTTP客户端接口和实现。这个版本(3.0...

    httpclient4.3 封装工具类

    这些方法会处理URL编码、参数拼接、Header设置等细节,让开发者可以专注于业务逻辑,而不用关心底层HTTP交互的复杂性。 5. **响应处理**:HttpClient 4.3封装工具类还可能包括对HTTP响应的处理,如获取响应状态码、...

    httpClient

    httpClient的get请求方式2 * @return * @throws Exception */ public static String doGet(String url, String charset) throws Exception { /* * 使用 GetMethod 来访问一个 URL 对应的网页,实现步骤: 1:...

    httpclient jar

    2. `commons-codec-1.3.jar`: 这个库提供了各种编码解码工具,如Base64编码、URL编码等,HttpClient依赖它来处理一些数据编码问题。 3. `commons-logging-1.1.1.jar`: Apache Commons Logging是一个轻量级的日志...

    彻底解决httpClient乱码问题

    1. **字符编码设置**:HttpClient默认可能不会自动处理服务器返回的字符集,因此需要明确指定编码。在发送请求时,可以使用`EntityUtils.toString(entity, "UTF-8")`来指定解码的字符集,确保与服务器响应的字符集...

    HttpClient3.1.jar

    HttpClient3.1依赖于这个库来处理HTTP请求中的编码问题,例如在URL参数或表单数据中进行编码。 4. **commons-logging-1.0.4.jar**:Apache Commons Logging是一个轻量级的日志记录抽象层,允许开发者选择底层的日志...

    httpclient

    5. **请求与响应处理**:HttpClient允许自定义请求头,处理响应头,以及对请求和响应实体内容的编码和解码。 **三、使用HttpClient的步骤** 1. **创建HttpClient实例**:根据项目需求配置连接管理器、重试策略等。...

    HttpClient 调用WebService示例

    HttpClient可以处理这两种类型的Web服务。在本示例中,我们假设你正在使用SOAP,因为通常需要发送XML格式的数据到WebService。 1. **导入必要的库**: 包含在压缩包中的jar文件可能是HttpClient库和其他依赖,如`...

Global site tag (gtag.js) - Google Analytics