浏览器向服务器请求网页的过程:
1.浏览器发送请求
2.服务器发回响应
请求头和响应头包含了请求和响应信息,可以用谷歌浏览器在开发者工具中查看。响应代码ResponseCode反映了请求的执行情况
- ResponseCode为302:需要重定向
- ResponseCode为200:请求成功
1.用HttpUrlConnection或HtppsUrlConnection建立连接、进行通信。如果请求返回的ResponseCode为302,需要获取响应头中的重定向地址,带上服务器在响应头中设置的Cookie重新访问重定向地址,直到ResponseCode为200正常为止。
2.ResponseCode为200后,可以通过UrlConnection的getInputStream()方法获得输入流,从而获取html源码。
3.ResponseCode为200只表示请求成功,却不一定表示能获得真正的html网页。有些服务器发送的是带有js代码的html,用js代码再设置cookie,并且再次跳转(jump(),window.location="?")。这些js代码不一定是明文的,可能是用eval加密的。在这种情况下,我们可以解密这些js代码,分析它的行为(设置了哪些cookie,又跳转到何处)。然后在程序中模拟这些行为,从而获得真正的html源码。一般来说,一个普通站点的js加密方法和行为是固定的,分析几次后可以知道如何获取关键数据。
以下是代码。
- getRealHtml()获得真正的html源码,对于直接发送真实数据的站点来说,不需要这一步。
- 使用HttpsUrlConnection还是HttpURLConnection取决于访问的url地址使用Https协议还是Http协议
- 调用URLConnection的getResponseCode()或getInputStream()方法后,服务器已经返回响应,本次连接结束
- URLConnection一定要设置不立即重定向。因为需要在设置cookie后再重定向
import javax.net.ssl.HttpsURLConnection;
import java.io.*;
import java.net.*;
import java.text.SimpleDateFormat;
import java.util.Date;
public class HtmlCatcher {
//带cookie访问url地址,获取ResponseCode不为302后(即重定向后)的html源码
//对于初始cookie为空的访问,传入参数cookie为"",字符串空
public String getHTmlText(String url,String cookie){
BufferedReader in = null;
String result = "";
try{
HttpsURLConnection conn=getConnection(url);//获取一个UrlConnection
int code=0;
conn.setRequestProperty("Cookie", cookie);//设置请求头的cookie
while ((code=conn.getResponseCode())==302){
String redirect=conn.getHeaderField("Location");//获取重定向地址
String[] str=conn.getHeaderField("Set-Cookie").split(";");//获取响应头设置的cookie
for(int i=0;i<str.length-1;i++){
if(!cookie.contains(str[i]))
cookie+=str[i]+"; ";
}
conn=getConnection(redirect);
conn.setRequestProperty("Cookie", cookie);//带上cookie,返回while时访问重定向地址
}
//获取html源码
in = new BufferedReader(new InputStreamReader(conn.getInputStream(),"UTF-8"));
String line=null;
while((line = in.readLine())!=null){
result +="\n"+line;
}
}catch(Exception e){
//异常情况
e.printStackTrace();
if(e instanceof UnknownHostException){
//网络断开,5分钟后重试
Date date=new Date();
SimpleDateFormat sf=new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");
System.out.println(sf.format(date)+" 网络断开。将在5分钟后重试");
try {
Thread.sleep(300000);