Java获取网页编码

简介:

    使用爬虫从网上抓取到一个网页内容,要想能正确显示,必须要获取网页的原始编码,否则会出现乱码。首先需要获取网页内容,最简单的办法就是通过JDK自带的HttpURLConnection类,要实现更复杂的抓取操作,请使用开源的爬虫框架,如Crawler4j,Web-Harvest,JSpider,WebMagic,Heritrix,Nutch等,我并不是来说爬虫相关技术的,只是网页内容的获取需要使用到爬虫技术,所以顺带提提有关爬虫的框架,具体你们自己去研究。这里为了简便起见,我就以JDK自带的HttpURLConnection类来抓取网页内容,抓取示例代码如下:

 

Java代码   收藏代码
  1. package com.yida.test;  
  2.   
  3. import java.io.BufferedReader;  
  4. import java.io.IOException;  
  5. import java.io.InputStreamReader;  
  6. import java.net.HttpURLConnection;  
  7. import java.net.URL;  
  8. /** 
  9.  * 提取网页内容 
  10.  * @author Lanxiaowei 
  11.  * 
  12.  */  
  13. public class FetchWebPageTest {  
  14.     public static void main(String[] args) throws IOException {  
  15.         String charset = "UTF-8";  
  16.         String line = "";  
  17.         StringBuffer buffer = new StringBuffer();  
  18.         URL url = new URL("http://www.baidu.com");  
  19.         //开始访问该URL  
  20.         HttpURLConnection urlConnection = (HttpURLConnection)url.openConnection();  
  21.         //获取服务器响应代码  
  22.         int responsecode = urlConnection.getResponseCode();  
  23.         String contentType = urlConnection.getContentType();  
  24.         //打印出content-type值,然后就可以从content-type中提取出网页编码  
  25.         System.out.println("content-type:" + contentType);  
  26.         if(responsecode == 200){  
  27.             //获取网页输入流  
  28.             BufferedReader reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(),charset));  
  29.             while((line = reader.readLine()) != null){  
  30.                 buffer.append(line).append("\n");  
  31.             }  
  32.             System.out.println(buffer.toString());  
  33.         }  
  34.         else{  
  35.             System.out.println("获取不到网页的源码,服务器响应代码为:"+responsecode);  
  36.         }  
  37.         urlConnection.disconnect();  
  38.     }  
  39. }  

     关键点在这一句代码:

 

 

Java代码   收藏代码
  1. BufferedReader reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(),charset));  

   这里的charset表示网页内容的字符集编码,上面的示例代码中charset是直接定义为UTF-8,实际我们期望是能自动判断,因为并不是所有网页内容的字符集编码都为UTF-8,这也是我们今天这篇文章的主题:如何获取网页内容的原始字符集编码。

 

    首先,我们可以通过URLConnection类的getContentType()方法的返回值中获取,比如:

 

Java代码   收藏代码
  1. String contentType = urlConnection.getContentType();  

     返回值类似这样:

 

 

Java代码   收藏代码
  1. content-type:text/html; charset=utf-8  

     然后我们从字符串中提取出字符集编码,剩下这就是字符串处理了,没什么难度,你们都懂的!

 

    当然,URLConnection类的getContentType()方法的返回值并不能保证一定会包含字符集编码,这时我们就需要另辟蹊径,我们都知道一般HTML页面源代码中都会包含<meta标签,如:

 

Html代码   收藏代码
  1. <%@ page language="java" contentType="text/html; charset=UTF-8"  
  2.     pageEncoding="UTF-8"%>  
  3. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">  
  4. <html>  
  5. <head>  
  6. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  
  7. <title>欢迎页面</title>  
  8. </head>  
  9. <body>  
  10. 欢迎页面  
  11. </body>  
  12. </html>    

     关键点在这里:

Html代码   收藏代码
  1. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  

     我们可以通过正则表达式从中提取出编码,示例代码如下:

Java代码   收藏代码
  1. package com.yida.test;  
  2.   
  3. import java.util.regex.Matcher;  
  4. import java.util.regex.Pattern;  
  5. /** 
  6.  * 从HTML网页的meta元素中提取页面编码 
  7.  * 这里采用的是正则表达式方式提取,你也可以采用XML解析的方式来提取[HTML其实就是XML] 
  8.  * @author Lanxiaowei 
  9.  * 
  10.  */  
  11. public class CharsetExtractTest {  
  12.     public static void main(String[] args) {  
  13.         //test1();  
  14.         test2();  
  15.     }  
  16.       
  17.     /** 
  18.      * 常规情况 
  19.      */  
  20.     public static void test1() {  
  21.         String content="<html xmlns=\"http://www.w3.org/1999/xhtml\">\n" +  
  22.                 "<head>\n" +  
  23.                 "<meta http-equiv = \"Content-Type\" content = \"text/html; charset=utf-8\" />\n" +  
  24.                 "<meta content=\"java获取 html网页编码\" name=\"Keywords\"/>...\n";  
  25.         Pattern pattern = Pattern.compile("<meta\\s+http-equiv\\s*=\\s*\"Content-Type\"\\s+content\\s*=\\s*\"[\\s\\S]*?charset=(\\S+?)\"\\s*/>");  
  26.         Matcher matcher=pattern.matcher(content);  
  27.         if(matcher.find()){  
  28.             System.out.println(matcher.group(1));  
  29.         }  
  30.     }  
  31.       
  32.     /** 
  33.      * 非常规情况,比如http-equiv和content属性颠倒了 
  34.      */  
  35.     public static void test2() {  
  36.         String content="<html xmlns=\"http://www.w3.org/1999/xhtml\">\n" +  
  37.                 "<head>\n" +  
  38.                 "<meta content = \"text/html; charset=utf-8\" http-equiv = \"Content-Type\" />\n" +  
  39.                 "<meta content=\"java获取 html网页编码\" name=\"Keywords\"/>...\n";  
  40.         String regex = "(<meta\\s+http-equiv\\s*=\\s*\"Content-Type\"\\s+content\\s*=\\s*\"[\\s\\S]*?charset=(\\S+?)\"\\s*/>)|" +   
  41.                 "(<meta\\s+content\\s*=\\s*\"[\\s\\S]*?charset=(\\S+?)\"\\s+http-equiv\\s*=\\s*\"Content-Type\"\\s*/>)";  
  42.         Pattern pattern = Pattern.compile(regex);  
  43.         Matcher matcher=pattern.matcher(content);  
  44.         if(matcher.find()){  
  45.             System.out.println(matcher.group(4));  
  46.         }  
  47.     }  
  48. }  

     但遗憾的是,并不是每个网页内容都包含meta标签,因为总有些人不遵守HTML规范,这是我们该怎么办?还好我们还有一招可以来应对这种情形,那就是IBM的icu4j类库,icu4j可以从指定的字节数据从自动推断出其采用的字符集编码,具体示例代码如下:

    

Java代码   收藏代码
  1. package com.yida.test;  
  2.   
  3. import java.io.IOException;  
  4. import java.io.InputStream;  
  5.   
  6. import com.ibm.icu.text.CharsetDetector;  
  7. import com.ibm.icu.text.CharsetMatch;  
  8.   
  9. /** 
  10.  * 使用icu4j探测内容编码,这里的内容可以来自于字符串,字节数组,输入流等等 
  11.  *  
  12.  * @author Lanxiaowei 
  13.  *  
  14.  */  
  15. public class Icu4jTest {  
  16.     public static void main(String[] args) {  
  17.         String data = "ICU4J 是IBM的国际化开发组件ICU的Java语言实现版本。";  
  18.         String encode = getEncode(data);  
  19.         System.out.println("encode:" + encode);  
  20.     }  
  21.       
  22.     public static String getEncode(String data) {  
  23.         return getEncode(data.getBytes());  
  24.     }  
  25.     public static String getEncode(byte[] data) {  
  26.         CharsetDetector detector = new CharsetDetector();  
  27.         detector.setText(data);  
  28.         CharsetMatch match = detector.detect();  
  29.         //取Confidence值最大的  
  30.         String encoding = match.getName();  
  31.         System.out.println("The Content in " + match.getName());  
  32.         CharsetMatch[] matches = detector.detectAll();  
  33.         System.out.println("All possibilities");  
  34.         for (CharsetMatch m : matches) {  
  35.             System.out.println("CharsetName:" + m.getName() + " Confidence:"  
  36.                     + m.getConfidence());  
  37.         }  
  38.         return encoding;  
  39.     }  
  40.   
  41.     public static String getEncode(InputStream data)  
  42.             throws IOException {  
  43.         CharsetDetector detector = new CharsetDetector();  
  44.         detector.setText(data);  
  45.         CharsetMatch match = detector.detect();  
  46.         String encoding = match.getName();  
  47.         System.out.println("The Content in " + match.getName());  
  48.         CharsetMatch[] matches = detector.detectAll();  
  49.         System.out.println("All possibilities");  
  50.         for (CharsetMatch m : matches) {  
  51.             System.out.println("CharsetName:" + m.getName() + " Confidence:"  
  52.                     + m.getConfidence());  
  53.         }  
  54.         return encoding;  
  55.     }  
  56. }  

     还有一点需要注意的就是,如果抓取到的网页内容输入流不管是使用GBK还是UTF-8,都全是乱码,那很有可能是该网页所在服务器对其采用GZip压缩,所以在获取到网页输入流时首先需要对其进行GZip解压缩,那如何确定对方服务器是否有对网页进行GZip压缩呢,一般可以通过响应头信息中获取到,如果响应头里包含了如下信息:

Plaintext代码   收藏代码
  1. Accept-Encoding: gzip,deflate    

     则表明该网页被GZip压缩过,在获取网页内容之前,需要一个GZip解压缩过程,特此提醒!GZip解压缩示例代码如下:

Java代码   收藏代码
  1. InputStream is = urlConnection.getInputStream();  
  2. //用GZIPInputStream 对原始的输入流包装一下  
  3. GZIPInputStream gis = new GZIPInputStream(he.getContent());  
  4. BufferedReader reader = new BufferedReader(new InputStreamReader(gis,charset));  

   上述所有示例代码打包上传到我的百度网盘,代码下载地址如下:

    http://pan.baidu.com/s/1kTgQi0Z

 

    如果你还有什么问题请加我Q-Q:7-3-6-0-3-1-3-0-5,

或者加裙
一起交流学习!

转载:http://iamyida.iteye.com/blog/2206228

目录
相关文章
|
3月前
|
Java
Java开发实现图片URL地址检验,如何编码?
【10月更文挑战第14天】Java开发实现图片URL地址检验,如何编码?
100 4
|
3月前
|
Java
Java实现随机生成某个省某个市的身份证号?如何编码?
【10月更文挑战第18天】Java实现随机生成某个省某个市的身份证号?如何编码?
188 5
|
3月前
|
Java
Java开发实现图片地址检验,如果无法找到资源则使用默认图片,如何编码?
【10月更文挑战第14天】Java开发实现图片地址检验,如果无法找到资源则使用默认图片,如何编码?
72 2
|
1天前
|
自然语言处理 Java
Java中的字符集编码入门-增补字符(转载)
本文探讨Java对Unicode的支持及其发展历程。文章详细解析了Unicode字符集的结构,包括基本多语言面(BMP)和增补字符的表示方法,以及UTF-16编码中surrogate pair的使用。同时介绍了代码点和代码单元的概念,并解释了UTF-8的编码规则及其兼容性。
72 60
|
5月前
|
安全 Java API
告别繁琐编码,拥抱Java 8新特性:Stream API与Optional类助你高效编程,成就卓越开发者!
【8月更文挑战第29天】Java 8为开发者引入了多项新特性,其中Stream API和Optional类尤其值得关注。Stream API对集合操作进行了高级抽象,支持声明式的数据处理,避免了显式循环代码的编写;而Optional类则作为非空值的容器,有效减少了空指针异常的风险。通过几个实战示例,我们展示了如何利用Stream API进行过滤与转换操作,以及如何借助Optional类安全地处理可能为null的数据,从而使代码更加简洁和健壮。
138 0
|
7月前
|
XML Java 数据格式
必知的技术知识:java基础73dom4j修改xml里面的内容(网页知识)
必知的技术知识:java基础73dom4j修改xml里面的内容(网页知识)
44 1
|
3月前
|
存储 缓存 Java
java基础:IO流 理论与代码示例(详解、idea设置统一utf-8编码问题)
这篇文章详细介绍了Java中的IO流,包括字符与字节的概念、编码格式、File类的使用、IO流的分类和原理,以及通过代码示例展示了各种流的应用,如节点流、处理流、缓存流、转换流、对象流和随机访问文件流。同时,还探讨了IDEA中设置项目编码格式的方法,以及如何处理序列化和反序列化问题。
95 1
java基础:IO流 理论与代码示例(详解、idea设置统一utf-8编码问题)
|
4月前
|
存储 移动开发 Java
java核心之字符串与编码
java核心之字符串与编码
28 2
|
5月前
|
Java
Java系列之:字符串UTF-8 编码格式转换位 UTF-32 【生僻字截取问题】
这篇文章讨论了在Java中处理包含生僻字的字符串时可能遇到的问题,并提供了一种解决方法:将字符串的编码格式从UTF-8转换为UTF-32,以确保每个字符都占用固定的字节数,从而避免在截取操作中破坏字符,示例代码展示了如何进行编码转换和字符串截取。
|
5月前
|
存储 安全 Java
"Java编码魔法:揭秘图片与文件的Base64神秘转换术,让数据在指尖跳跃!"
【8月更文挑战第16天】Base64编码在Java开发中常用于将二进制数据如图片转换为ASCII字符串以便传输。编码使用64个字符及等号填充,每3字节数据编码为4个字符。Java利用`java.util.Base64`类实现此功能:读取图片或文件为字节数组后进行编码。解码时将Base64字符串还原为字节数组并写入文件。需注意编码效率降低、不提供安全性及特殊字符兼容性等问题。掌握这些技巧有助于解决Web开发中的数据传输需求。
125 4