Java--使用net包获取网页源代码
读取过程分析本文只是简单的读取网页源代码,用到的Java类很有限。本文针对的目标网页都是一些简单的网页,这些网页不能加密,不能压缩(将网页代码去除空格、换行等,压缩成一行),不存在需要经过一次或n次跳转才能到达。PS:至少目前90%以上的网站都是这种简单的网站。首先介绍一下HTTP请求头包含的内容:Accept:客户端希望接收的MIME数据类型,所有的数据类型可以参考http://tool.osc
读取过程分析
本文只是简单的读取网页源代码,用到的Java类很有限。
本文针对的目标网页都是一些简单的网页,这些网页不能加密,不能压缩(将网页代码去除空格、换行等,压缩成一行),不存在需要经过一次或n次跳转才能到达。PS:至少目前90%以上的网站都是这种简单的网站。
首先介绍一下HTTP请求头包含的内容:
- Accept:客户端希望接收的MIME数据类型,所有的数据类型可以参考http://tool.oschina.net/commons/。
- Accept-Encoding:浏览器支持的编码类型,包括gzip,defult,compress,identity。
- Accept-Language:浏览器支持的语言类型。zh-CN代表汉语,en代表英文。
- User-Agent:浏览器的标识,方便服务器识别。
Java代码
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.zip.GZIPInputStream;
import org.htmlparser.Node;
import org.htmlparser.Parser;
import org.htmlparser.filters.TagNameFilter;
import org.htmlparser.nodes.TagNode;
import org.htmlparser.util.ParserException;
import org.htmlparser.util.SimpleNodeIterator;
public class WebPageSourceCode {
private String pageEnCode;
public static void main(String[] args) {
String path = "http://www.hao123.com/";
String encode = "UTF-8";
WebPageSourceCode wb = new WebPageSourceCode();
String sourceCode = wb.getPageSourceCode(path, encode);
//http返回的头信息中没有包含网页的编码格式
if(wb.getPageEnCode() == null){
encode = getEncodeFromMeta(sourceCode);
sourceCode = wb.getPageSourceCode(path, encode);
}
System.out.println(sourceCode);
}
/**
*这里涉及到一些htmlparser包的一些知识,以后再说。
*下面使用UTF-8格式解析网页源码,可能存在中文乱码,但是我们要得到meta标签的内容
*而meta标签的内容是英文,所以中文乱码无所谓
*/
private static String getEncodeFromMeta(String sourceCode) {
Parser p = Parser.createParser(sourceCode, "UTF-8");
String encode = "";
try {
SimpleNodeIterator sni = p.extractAllNodesThatMatch(new TagNameFilter("meta")).elements();
while(sni.hasMoreNodes()){
Node node = sni.nextNode();
TagNode tag = new TagNode();
tag.setText(node.toHtml());
String temp = null;
if((temp = tag.getAttribute("content")) != null &&
temp.contains("text/html") && temp.contains("charset")){
encode = temp.substring(temp.indexOf("=")+1);
}
}
} catch (ParserException e) {
System.out.println("HtmlParser库无法使用!");
e.printStackTrace();
}
return encode.trim();
}
public String getPageSourceCode(String path,String encode){
StringBuffer sb = new StringBuffer();
try {
//1.构建URL对象
URL url = new URL(path);
//2.打开URL链接
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//3.设置请求头属性
conn.setConnectTimeout(5000);//设置响应时间为5s
conn.setReadTimeout(3000);
conn.setRequestMethod("GET");
conn.setRequestProperty("Accept", "*/*");
conn.setRequestProperty("Accept-Encoding", "gzip,default");
conn.setRequestProperty("User-Agent",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) "
+ "Chrome/23.0.1271.64 Safari/537.11");
//4.得到响应码
int responseCode = conn.getResponseCode();
Map<String, List<String>> responseHead = null;
if(responseCode == HttpURLConnection.HTTP_OK){
responseHead = conn.getHeaderFields();
//printHead(responseHead);
//5.得到网页内容的编码格式,防止中文乱码
String pageEncode = getEncode(responseHead);
if(pageEncode != null
&& pageEncode.trim().length() > 0){
this.setPageEncode(pageEncode);
encode = pageEncode;
}
//6.读取网页源代码
BufferedReader in = new BufferedReader(
new InputStreamReader(
new GZIPInputStream(conn.getInputStream()),
encode));
String line = "";
while((line = in.readLine()) != null){
sb.append(line);
sb.append(System.getProperty("line.separator"));
}
in.close();
}else{
System.out.println("服务器响应失败,响应码:"+responseCode);
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return sb.toString();
}
private String getEncode(Map<String, List<String>> map) {
String encode = "";
Set<Map.Entry<String, List<String>>> entry = map.entrySet();
for(Map.Entry<String, List<String>> temp: entry){
if(temp.getKey() !=null&&
temp.getKey().equals("Content-Type")){
String value = temp.getValue().toString()
.replace("[", "").replace("]", "");
int start = value.indexOf("=");
if(start != -1){
encode = value.substring(start+1);
}
}
}
return encode;
}
private void printHead(Map<String, List<String>> map) {
Set<Map.Entry<String, List<String>>> entry = map.entrySet();
for(Map.Entry<String, List<String>> temp: entry){
System.out.println(temp.getKey()+":"+temp.getValue());
}
}
public String getPageEnCode() {
return pageEnCode;
}
public void setPageEncode(String pageEnCode) {
this.pageEnCode = pageEnCode;
}
}
实验说明
设置请求头的时候,最好设置Accept-Encoding属性,如果不设置这个属性,一般网站不会发送压缩数据,但是也有一部分网站会发送压缩数据,这大概是网站服务器的默认属性,如果有一部分是压缩有一部分不压缩,就很难处理流了,所以我设置了这个属性,网站的服务器就会发送压缩数据,这样处理流数据的方式就统一了。PS:浏览器请求头设置Accept-Encoding属性也只是建议性的!!!
处理网页数据流时,一般用UTF-8解码就可以了,但是不能排除有一部分网站是以GBK或gb2312格式编码正文内容的。不以正确的格式读取流数据,就会得到乱码。获取网页正文编码方式的途径有两种:1.返回的请求头中Content-Type属性的值中可能包含编码方式(Content-Type:[text/html;charset=UTF-8])2.如果1中没有写编码格式,就只能从meta标签中读取了。
建议先用第一种方法获取编码格式。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)