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


    欢迎转载但请标明出处: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进行用户的usernamepassword以及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();
                }
            });
            //对登录button绑定单击响应事件
            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();
                    }
                    //假设server响应成功
                    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()
        {
            //获取输入信息。并保存为做记住password来铺垫
            StudentNumber =studentNumber.getText().toString();
            PassWord =passWord.getText().toString();
            IdCode = idCode.getText().toString();
            //这里写入StudentNumber和PassWord是为了做记住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);
                        //这里我们不仅须要保证server正常响应,并且还要知道当我们登陆失败时是什么原因导致的
                        if(!result.contains("错误提示")&&httpResponse.getStatusLine().getStatusCode() == 200)
                        {
                            startActivity(new Intent(MainActivity.this, Score_find.class));
                        }
                        else
                        {
                            if(result.contains("password不匹配"))
                            {
    
                                handler.post(new Runnable() {
                                    @Override
                                    public void run() {
    
                                        Toast.makeText(MainActivity.this, "password不匹配或username错误!!!请又一次输入", 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+"	"+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+"	"+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(" ").append(element4.text()).append(" "); } 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(" "); } 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

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



  • 相关阅读:
    ResGen.exe 生成resources文件方法 [转]
    C#【Winform】带参启动外部EXE
    SBO的5个开发原则机遇只给有准备的人[转]
    在SQL中插入临时表时使用自动增长的数据字段
    c# 强制退出
    C#实现SQL全库检索数据比较使用DataReader与DataAdapter+Datatable效率,差距惊人!
    推荐一个C#代码混淆器 .NET Reactor
    面向对象软件设计——设计模式学习
    AbstarctFactory模式——设计模式学习
    插入排序算法(直接,折半,希尔)
  • 原文地址:https://www.cnblogs.com/yangykaifa/p/7243386.html
Copyright © 2020-2023  润新知