Java实现从正方教务系统抓取数据(一)--模拟登录

前言:今天1024程序员节,便想抽出时间把前段时间做的小东西写成一个系列记录下来,以后有时间会迭代更新。这里分两部分,一:Java Web后台接口开发,主要分模拟登录,破解正方教务网登录验证码,抓取教务网数据,最后将这些封装成json API 接口给Android客户端调用。二:Android客户端调用接口,主要是写前端工作,也是最终呈现给用户的。
声明:转载请注明出处。

开发环境 :

  • Myeclipse10+apache-tomcat-6.0.44
  • 抓包工具fiddler 4(其实Firefox抓取也足够用,只是对中文会乱码)
  • 开发中用到的包(源代码后面会给出),其中jsoup-1.8.3.jar在后面对抓取到的html数据进行解析会用到。
  • 这是工程目录
    这里写图片描述

这里写图片描述

HttpClient的工具类

//单例模式得到HttpClient的对象,会自动帮我们管理cookie。
public class JwUtils {
    private static CloseableHttpClient httpClient = null;
    public final static String BASE_URL = "http://jw1.hustwenhua.net/";

    public static CloseableHttpClient getHttpClient() {
        if (httpClient == null){
            httpClient = HttpClients.createDefault();
            return httpClient;
        }
        return httpClient;
    }
}

首先我们分析会发现在浏览器输入教务网址:http://jw1.hustwenhua.net,它会变成http://jw1.hustwenhua.net/(oem5ln55gp0jac2njop2tmzo)/default2.aspx。中间会多出“(oem5ln55gp0jac2njop2tmzo)”这么一段字符串,这一段字符串很重要,以后每次访问都要带上它。而且等你下次打开浏览器在访问教务网这段字符串又不一样。这段字符串可以理解为一次有效的访问时期。

用fidder4抓取得到登录需要传递的参数如下:
POST请求,请求网址为:“http://jw1.hustwenhua.net/(oem5ln55gp0jac2njop2tmzo)/default2.aspx
这里写图片描述
这里就就解释下两个,_VIEWSTATE是以后每次抓取像教务网发起请求都要传递的一段字符串,它隐藏在每一个页面的一个表单里,所以我们首先可以通过Get请求先得到这段字符串。txtSecretCode是要传递的验证码。不多说直接贴代码。

public class JwLogin {
    /**
     * 通过Post请求得到Location中的头部请求的实际网址信息,解析出中间那段上面说的很重要的字符串,作用是标志这是一次有效访问。
     * 在通过Get请求解析出隐藏在当前页面的__VIEWSTATE的值
     * @return
     */
    public static Map<String, String> getBaseValue() {
        Map<String, String> map = new HashMap<String, String>();
        CloseableHttpClient hc = JwUtils.getHttpClient();
        HttpGet hg = null;
        HttpPost hp = new HttpPost(JwUtils.BASE_URL);
        HttpResponse responseGet = null;
        HttpResponse responsePost = null;
        try {
            responsePost = hc.execute(hp);
            if("HTTP/1.1 302 Found".equals(responsePost.getStatusLine().toString())){
                Header lheader = responsePost.getFirstHeader("Location");
                String urlcode = lheader.getValue();
                urlcode = urlcode.substring(urlcode.indexOf("("), (urlcode.indexOf(")")+1));
                map.put("urlcode", urlcode);
                hg = new HttpGet(JwUtils.BASE_URL+urlcode+"/default2.aspx");
                responseGet = hc.execute(hg);
                if ("HTTP/1.1 200 OK".equals(responseGet.getStatusLine().toString())) {
                    HttpEntity entity = responseGet.getEntity();
                    if (entity != null) {
                        String result = EntityUtils.toString(entity, "utf-8");
                        org.jsoup.nodes.Document doc = Jsoup.parse(result);
                        map.put("viewstate", doc.select("input[name=__VIEWSTATE]").val());
                    }
                }
            }
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            if(hg != null){
                hg.abort();
            }
            if(hp != null){
                hp.abort();
            }
        }
        return map;
    }

    /**
     * 
     * @param hm 用户名
     * @param pwd 密码
     * @param role 用户类型
     * @param secretcode 验证码
     * @param viewstate 页面隐藏的__VIEWSTATE的值
     * @param urlcode 网址中那段标志是此次有效请求的值
     * @return  返回登录用户的用户名,在后面的抓取别的数据有用
     */
    public static String isLogin(String hm, String pwd, String role, String secretcode, String viewstate, String urlcode) {
        CloseableHttpClient hc = JwUtils.getHttpClient();

        HttpPost hp = new HttpPost(JwUtils.BASE_URL+urlcode+"/default2.aspx");
        HttpResponse responsePost = null;
        List<NameValuePair> params = new ArrayList<NameValuePair>();
        params.add(new BasicNameValuePair("__VIEWSTATE", viewstate));
        params.add(new BasicNameValuePair("txtUserName", hm));
        params.add(new BasicNameValuePair("TextBox2", pwd));
        params.add(new BasicNameValuePair("txtSecretCode", secretcode));
        params.add(new BasicNameValuePair("RadioButtonList1", role));
        params.add(new BasicNameValuePair("Button1", ""));
//      params.add(new BasicNameValuePair("lbLanguage", ""));
//      params.add(new BasicNameValuePair("hidPdrs", ""));
//      params.add(new BasicNameValuePair("hidsc", ""));
        try {
            hp.setEntity(new UrlEncodedFormEntity(params));
            responsePost = hc.execute(hp);
            // 获得跳转的网址
            Header locationHeader = responsePost.getFirstHeader("Location");
            if (locationHeader != null && "HTTP/1.1 302 Found".equals(responsePost.getStatusLine().toString())) {
                String login_success = locationHeader.getValue();// 获取登陆成功之后跳转链接
                HttpGet httpget = new HttpGet(JwUtils.BASE_URL+login_success);
                HttpResponse re2 = hc.execute(httpget);
                Document doc = Jsoup.parse(EntityUtils.toString(re2.getEntity(), "utf-8"));
                Element e = doc.getElementById("xhxm");
                if(e==null){
                    return null;
                }else{
                    System.out.println("登陆成功");
                    return e.text();
                }
            } else{
                System.out.println("登陆不成功,请稍后再试!");
                return null;
            }
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            if(hp != null){
                hp.abort();
            }
        }
        return null;
    }
}

项目源码:
CSDN: http://download.csdn.net/detail/sinat_18127633/9210327
GitHub: https://github.com/zhugusheng/whjw

展开阅读全文

没有更多推荐了,返回首页