Android实现一键获取课程成绩dome

来源:互联网 发布:淘宝怎么看购买顺序 编辑:程序博客网 时间:2024/05/22 01:56

欢迎转载但请标明出处:http://blog.csdn.net/android_for_james/article/details/50984493

两周废寝忘食的创作终于成功了,现在拿出来分享一下。

先不说别的看一下程序运行效果图,我没怎么设计ui所以界面不是很好看但是能说明问题~~~



现在我们来看看实现这个功能需要些什么准备工作,我们需要网络信息抓取工具一般windows可以用httpwatch我是mac系统所以我详细介绍一下mac上面的工具


1.Charles

2.Google Chrome


接下来就可以进行网页信息抓包了,先看一下我们学校的教务网页



对浏览器抓包我使用的是Charles首先要配置成下图这个样子然后才可以抓包




首先对登录信息抓包时要找下面这张截图上的信息




然后对获取验证吗抓包




我们在response中可以看到返回信息。


然后我们需要下载一个解析HTML源码的架构包叫Jsoup放到libs目录下然后右键选择 

as library




这些就准备好了然后我们来看一小段HTML代码方便解析时候讲解


<br><table width="100%" class="datalist">    <tr>                        <th>                                    学年                    </th>                <th>                                    学期                    </th>                <th>                                    课程号                    </th>                <th>                                    课序号                    </th>                <th>                                    课程名                    </th>                <th>                                    选课属性                    </th>                <th>                                    课组                    </th>                <th>                                    学分                    </th>                <th>                                    平时                    </th>                <th>                                    期末                    </th>                <th>                                    总评                    </th>                <th>                                    是否缓考                    </th>                <th>                                    考试性质                    </th>                <th>                                    备注                    </th>                <th>                                    主讲教师                    </th>                <th>                                    课程类别                    </th>            </tr>
可以看到我们需要的信息都被一个一个的标签包裹着,Jsoup所做的就是将我们需要的信息从标签里剥离出来。

然后我们来看代码实现,我这里分了两个Activity来实现

1.MainActivity

public class MainActivity extends ActionBarActivity {    //使用SharedPreferences进行用户的用户名密码以及cookie的保存    SharedPreferences sharedPreferences;    SharedPreferences.Editor editor;    private EditText studentNumber;    private EditText passWord;    private EditText idCode;    private Bitmap bitmap;    private ImageView IdcodeImage;    //注意这里Handler使用的是import android.os.Handler;这个包    private Handler handler;    private Button logIn;    String StudentNumber;    String PassWord;    String IdCode;    String groupId="";    String login="登录";    //这条是解析出来进行获取验证码的图片的网址    String url2="http://jw.djtu.edu.cn/academic/getCaptcha.do";    //这条是解析出来进行提交登录信息的网址    String url3="http://jw.djtu.edu.cn/academic/j_acegi_security_check";    //这里使用HttpClient进行数据的获取和提交    HttpClient client;    @Override    protected void onCreate(final Bundle savedInstanceState)    {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        //初始化控件        initEvent();        //获取验证码        getIdCode();        //对我们的验证码绑定一个单击响应事件,这是为了去实现验证码看不清时再更新一张验证码而用        IdcodeImage.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                getIdCode();            }        });        //对登录按钮绑定单击响应事件        logIn.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                saveEvent();                loginEvent();            }        });    }    public void initEvent()    {        //实例化HttpClient对象        client=new DefaultHttpClient();        //sharedPreferences第一个参数是给你保存的信息起个名字,第二个参数设置为Context.MODE_PRIVATE属性,        // 这样会避免其他应用可以直接访问我们保存的信息        sharedPreferences=getSharedPreferences("params", Context.MODE_PRIVATE);        //实例化SharedPreferences.Editor对象        editor=sharedPreferences.edit();        studentNumber=(EditText)findViewById(R.id.studentNumber);        passWord=(EditText)findViewById(R.id.key);        IdcodeImage=(ImageView)findViewById(R.id.passImage);        idCode=(EditText)findViewById(R.id.identifyingCode);        logIn=(Button)findViewById(R.id.login);        //实例化Handler对象方便线程之间通信        handler =new Handler();    }    public void getIdCode()    {        new Thread() {            @Override            public void run() {                //我们需要同步Cookie信息所以从验证码开始就需要获取Cookie                List<Cookie> cookies1;                //HttpGet来发送获取验证码请求                HttpGet httpGet = new HttpGet(url2);                //声明一个HttpResponse                HttpResponse httpResponse = null;                try {                    //实例化HttpResponse                    httpResponse = client.execute(httpGet);                } catch (IOException e) {                    e.printStackTrace();                }                //如果服务器响应成功                if (httpResponse.getStatusLine().getStatusCode() == 200) {                    try {                        //使用输入流来接受数据                        InputStream in = httpResponse.getEntity().getContent();                        //bitmap来获取数据流中的图片信息                        bitmap = BitmapFactory.decodeStream(in);                        //关闭输入流                        in.close();                        String Cookies;                        //获取Cookie                        cookies1 = ((AbstractHttpClient) client).getCookieStore().getCookies();                        Cookies = "JSESSIONID="+cookies1.get(0).getValue().toString();                        //System.out.println(Cookies);                        //在SharedPreferences中保存cookie                        editor.putString("Cookies", Cookies);                        //提交保存数据                        editor.commit();                        //通过handler.post方法在线程中更新主线程中的验证码图片信息                        handler.post(new Runnable() {                            @Override                            public void run() {                                if (bitmap != null) {                                    IdcodeImage.setImageBitmap(bitmap);                                }                            }                        });                    } catch (IOException e) {                        e.printStackTrace();                    }                }            }        }.start();    }    public void saveEvent()    {        //获取输入信息,并保存为做记住密码来铺垫        StudentNumber =studentNumber.getText().toString();        PassWord =passWord.getText().toString();        IdCode = idCode.getText().toString();        //这里写入StudentNumber和PassWord是为了做记住密码登录        editor.putString("StudentNumber", StudentNumber);        editor.putString("PassWord", PassWord);        editor.putString("IdCode", IdCode);        editor.commit();    }    public void loginEvent()    {        new Thread() {            @Override            public void run() {                //提交数据用List<NameValuePair>的方式                List<NameValuePair> params = new ArrayList<NameValuePair>();                //这里的名称不要有多余的符号,因为提交数据时httppost方法会帮你维护数据                //这里表单的数据顺序要按照刚刚解析所显示的顺序排列                params.add(new BasicNameValuePair("groupId", groupId));                params.add(new BasicNameValuePair("j_username", StudentNumber));                params.add(new BasicNameValuePair("login",login));                params.add(new BasicNameValuePair("j_password", PassWord));                params.add(new BasicNameValuePair("j_captcha", IdCode));                System.out.println(params);                try {                    HttpPost httpPost = new HttpPost(url3);                    String Cookies;                    //获取到刚刚在获取验证码时得到的Cookie                    Cookies = sharedPreferences.getString("Cookies", null);                    //System.out.println(Cookies);                    //提交数据做准备                    httpPost.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));                    //同步cookie                    httpPost.setHeader("Cookie", Cookies);                    //获取返回的信息                    HttpResponse httpResponse = client.execute(httpPost);                    String result = EntityUtils.toString(httpResponse.getEntity());                    //System.out.println(result);                    //这里我们不仅需要保证服务器正常响应,而且还要知道当我们登陆失败时是什么原因导致的                    if(!result.contains("错误提示")&&httpResponse.getStatusLine().getStatusCode() == 200)                    {                        startActivity(new Intent(MainActivity.this, Score_find.class));                    }                    else                    {                        if(result.contains("密码不匹配"))                        {                            handler.post(new Runnable() {                                @Override                                public void run() {                                    Toast.makeText(MainActivity.this, "密码不匹配或用户名错误!!!请重新输入", Toast.LENGTH_LONG).show();                                    //当登陆失败时上一张验证码的图片已经失效因此需重新加载                                    getIdCode();                                }                            });                        }else if(result.contains("验证码错误")||result.contains("验证码不正确"))                        {                            handler.post(new Runnable() {                                @Override                                public void run() {                                    Toast.makeText(MainActivity.this, "验证码错误!!!请重新输入", Toast.LENGTH_LONG).show();                                    getIdCode();                                }                            });                        }                    }                } catch (UnsupportedEncodingException e) {                    e.printStackTrace();                } catch (ClientProtocolException e) {                    e.printStackTrace();                } catch (IOException e) {                    e.printStackTrace();                }            }        }.start();    }}

2.Score_find Activity

public class Score_find extends ActionBarActivity{    private String Cookies;    HttpClient client;    private String url="http://jw.djtu.edu.cn/academic/manager/score/studentOwnScore.do?groupId=&moduleId=2021";    private String year=null;    private String trem=null;    private String para="0";    private String sortColumn="";    private String Submit="查询";    private TextView showScore;    private EditText InputYear;    private EditText InputTrem;    SharedPreferences sharedPreferences;    StringBuffer sb=new StringBuffer();    private Handler handler=null;    private Button searchButton;    //这两个标记是用于判断用户输入的数据是否合法    private int mark1=0;    private int mark2=0;    @Override    protected void onCreate(final Bundle saveInstanceState)    {        super.onCreate(saveInstanceState);        setContentView(R.layout.score_find);        initEvent();        searchButton.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                String years=null,trems=null;                years=InputYear.getText().toString();                trems=InputTrem.getText().toString();                System.out.println(years+trems);                //输入信息的判断                if("春".equals(trems))                {                    trem="1";                    mark1=1;                    System.out.println(trems+"\t"+trem);                }else if("秋".equals(trems))                {                    trem="2";                    mark1=1;                }else                {                    mark1=0;                    Toast.makeText(Score_find.this,"输入学期有误请重新输入!",Toast.LENGTH_SHORT).show();                }                if("2014".equals(years))                {                    year="34";                    mark2=1;                    System.out.println(years+"\t"+year);                }else if("2015".equals(years))                {                    year="35";                    mark2=1;                }                else                {                    mark2=0;                    Toast.makeText(Score_find.this,"输入年份有误请重新输入!",Toast.LENGTH_SHORT).show();                }                //如果两个信息都输入合法则提交请求                if(mark1==1&&mark2==1) {                    //是耗时操作都要放到新线程里执行                    getScore();                }            }        });    }    public void initEvent()    {        InputTrem=(EditText)findViewById(R.id.InputTrem);        InputYear=(EditText)findViewById(R.id.InputYear);        searchButton=(Button)findViewById(R.id.searchButton);        showScore=(TextView)findViewById(R.id.show_score);        //设置showScore可以滚动        showScore.setMovementMethod(ScrollingMovementMethod.getInstance());        handler=new Handler()        {            @Override            public void handleMessage(Message message)            {                //加载信息                showScore.setText(sb.toString());            }        };        sharedPreferences = getSharedPreferences("params", Context.MODE_PRIVATE);        Cookies=sharedPreferences.getString("Cookies", null);        showScore=(TextView)findViewById(R.id.show_score);        client=new DefaultHttpClient();    }    public void analysisText(String results)    {        //这里使用jsoup开源的解析包进行html源码的解析        //获取要解析的网址或者文档或者网址        Document document = Jsoup.parse(results);        //经过分析成绩保存在datalist这个Class中因此要定位到这个类中        Elements elements = document.getElementsByClass("datalist");        //获取他的第一个元素集合        Element element = elements.get(0);        //再分析可以看到在tr标签下有成绩的详细信息        Elements elements1 = element.getElementsByTag("tr");        Element element2;        Elements elements3;        Element element3;        Element element4;        for (int i = 0; i < elements1.size(); i++) {            //剥离每一个标签            element2 = elements1.get(i);            //再重新定位td标签下的内容            elements3 = element2.getElementsByTag("td");            for (int j = 0; j < elements3.size(); j++) {                //这里为了获取td标签中的子元素要进行一个循环                if (j == 0) {                    //我发现我要的课程名和成绩分别在elements3集合中的第5个元素和第11个元素                    element3 = elements3.get(4);                    element4 = elements3.get(10);                    sb.append(element3.text()).append(":").append("\t\t").append(element4.text()).append("\n");                } else {                    break;                }            }        }        //数据获取完成通知组件重绘信息        handler.sendEmptyMessage(0);    }    public void getScore()    {        new Thread() {            @Override            public void run()            {                HttpResponse httpResponse;                HttpPost httpPost = new HttpPost(url);                List<NameValuePair> params = new ArrayList<NameValuePair>();                params.add(new BasicNameValuePair("year", year));                params.add(new BasicNameValuePair("term", trem));                params.add(new BasicNameValuePair("para", para));                params.add(new BasicNameValuePair("sortColumn", sortColumn));                params.add(new BasicNameValuePair("Submit", Submit));                System.out.println(params);                httpPost.setHeader("Cookie", Cookies);                try {                    httpPost.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));                    httpResponse = client.execute(httpPost);                    if (httpResponse.getStatusLine().getStatusCode() == 200) {                        StringBuffer stringBuffer = new StringBuffer();                        String result;                        InputStream inputStream = httpResponse.getEntity().getContent();                        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));                        String data = "";                        //读取得到的数据                        while ((data = bufferedReader.readLine()) != null) {                            stringBuffer.append(data);                            stringBuffer.append("\n");                        }                        result = stringBuffer.toString();                        //判断是否获取到数据                        if (result == null) {                            System.out.println("NULL!!!!");                        } else {                            analysisText(result);                        }                    }                } catch (UnsupportedEncodingException e) {                    e.printStackTrace();                } catch (ClientProtocolException e) {                    e.printStackTrace();                } catch (IOException e) {                    e.printStackTrace();                }            }        }.start();    }}

最后我用红字强调一下做这个demo我一开始失败了好多次的地方:

1.Cookie信息获取要在获取验证码时同时获取。

2.如果线程操作封装成类的话会造成SharedPreferences绑定content失败。

3.对HTML源码进行解析的时候我尝试将解析方法写成一个函数,但是会出现一些未捕获的错误而导致程序崩溃,因此我把解析步骤也放到了新线程中。

希望对大家有所帮助,欢迎转载但要标明出处,谢谢!

有什么不足的地方可以留言给我我会尽快回复并改正!

欢迎关注我的博客:http://blog.csdn.net/android_for_james

源码下载网址(点开后面链接后在文章末尾有点击下载按钮):点击打开链接



3 0