Android http实战模拟登录 okhttp/retrofit/jsoup/验证码获取

短命女 2021-10-01 09:46 418阅读 0赞

定义retrofit的接口

  1. public interface ApiService {
  2. @GET("{part}/")
  3. Observable<NewsGson> getNewsData(@Path("part") String part, @Query("key") String key, @Query("num") String num, @Query("page") int page);
  4. @FormUrlEncoded
  5. @POST("reader/redr_verify.php")
  6. Call<String> getMyBookData(@Header("Cookie") String cookie,@FieldMap Map<String,String> params);
  7. @FormUrlEncoded
  8. @POST("Default.aspx")
  9. Call<String> allSeatSearch(@FieldMap Map<String,String> params);
  10. @GET("FunctionPages/Statistical/LibraryUsedStat.aspx")
  11. Call<String> getPhoto();
  12. @GET("reader/book_lst.php")
  13. Call<String> getMyBookDataDetail(@Header("Cookie") String cookie);
  14. @GET("reader/captcha.php")
  15. Call<String> getCookieData();
  16. }

1.实现模拟登录图书馆,查看《我的借阅》
首先发现登录界面需要验证码,所以第一步获取验证码图片,拿到COOKIE保存起来。代码如下。

  1. public void requestTestOkhttp(){
  2. OkHttpClient okHttpClient=new OkHttpClient();
  3. Request request=new Request.Builder().get()
  4. .url("http://202.194.40.71:8080/reader/captcha.php")
  5. .build();
  6. okHttpClient.newCall(request).enqueue(new okhttp3.Callback() {
  7. @Override
  8. public void onFailure(okhttp3.Call call, IOException e) {
  9. e.printStackTrace();
  10. }
  11. @Override
  12. public void onResponse(okhttp3.Call call, okhttp3.Response response) throws IOException {
  13. Message message=handler.obtainMessage();
  14. if(response.isSuccessful()){
  15. message.what=1;
  16. message.obj=response.body().bytes();
  17. handler.sendMessage(message);
  18. String s=response.headers().get("Set-Cookie").toString();
  19. String[] cookieArray=s.split(";");
  20. Log.d("SearchMyBook",cookieArray[0]);
  21. editor=pref.edit();
  22. editor.putString("cookie",cookieArray[0]);//PHPSESSID=xxxxxxx;
  23. editor.apply();
  24. }else{
  25. Log.d("SearchMyBook","response is not successful");
  26. }
  27. }
  28. });
  29. }

因为okhttp的onresponse发生在子线程,无法进行UI操作,所以此处通过Handler进行图片的加载。通过response.body().bytes()转换成字节流传送,通过字节数组btye[]保存,通过BitmapFactory.decodeByteArray(result,0,result.length)将字节数组转换成bitmap图片,实现验证码获取下载。
(此处用retrofit转字节数组不成功,暂时搁置挖个坑以后过来填)

  1. private Handler handler=new Handler(){
  2. @Override
  3. public void handleMessage(Message msg) {
  4. super.handleMessage(msg);
  5. switch (msg.what){
  6. case 1:
  7. byte[] result=(byte[])msg.obj;
  8. Bitmap bitmap=BitmapFactory.decodeByteArray(result,0,result.length);
  9. img.setImageBitmap(bitmap);
  10. break;
  11. }
  12. }
  13. };

第二步携带COOKIE进行POST请求登录,此处通过RETROFIT完成。
通过Map携带参数。

  1. public void requestMyBook(Map params){
  2. Retrofit retrofit=new Retrofit.Builder()
  3. .baseUrl("http://202.194.40.71:8080/")
  4. .addConverterFactory(ScalarsConverterFactory.create())
  5. .build();
  6. ApiService service=retrofit.create(ApiService.class);
  7. Call<String> call=service.getMyBookData(pref.getString("cookie",""),params);
  8. call.enqueue(new Callback<String>() {
  9. @Override
  10. public void onResponse(Call<String> call, Response<String> response) {
  11. //tv_mybook_search.setText(response.body().toString());
  12. requestMyBookDetail();
  13. }
  14. @Override
  15. public void onFailure(Call<String> call, Throwable t) {
  16. Toast.makeText(SearchMyBook.this,"请求失败",Toast.LENGTH_SHORT).show();
  17. }
  18. });
  19. }

第三步,登录后进行get请求获取具体的个人借阅页面,根据自己的需要新建实体类,此处我只需要借书名称,借出时间和应还时间。然后根据获得的H5代码通过JSOUP进行解析。添加对应的数据。

  1. public void requestMyBookDetail(){
  2. Retrofit retrofit=new Retrofit.Builder()
  3. .baseUrl("http://202.194.40.71:8080/")
  4. .addConverterFactory(ScalarsConverterFactory.create())
  5. .build();
  6. ApiService service=retrofit.create(ApiService.class);
  7. Call<String> call=service.getMyBookDataDetail(pref.getString("cookie",""));
  8. call.enqueue(new Callback<String>() {
  9. @Override
  10. public void onResponse(Call<String> call, Response<String> response) {
  11. if(response.isSuccessful()) {
  12. StringBuilder sb=new StringBuilder();
  13. Document doc= Jsoup.parse(response.body().toString());
  14. // Elements content=doc.getElementsByAttributeValue("class","blue");
  15. // for(Element link :content)
  16. // {
  17. // sb.append(link.getElementsByTag("a").text().toString()+"\r\n");
  18. //
  19. // }
  20. //whitetext标签查询
  21. // Elements content=doc.getElementsByAttributeValue("class","whitetext");
  22. // for(Element link :content)
  23. // {
  24. // sb.append(link.getElementsByAttributeValue("width","35%").text().toString());
  25. // sb.append(link.getElementsByAttributeValue("width","13%").text().toString());
  26. // }
  27. // tv_mybook_search.setText(sb.toString());
  28. Element table=doc.getElementsByTag("table").get(0);
  29. Element tbody=table.getElementsByTag("tbody").get(0);
  30. Elements trs=tbody.getElementsByTag("tr");
  31. for(int i=1;i<trs.size();i++){
  32. Element e=trs.get(i);
  33. Elements tds=e.getElementsByTag("td");
  34. String title=tds.get(1).text();
  35. String borrow_time="借书时间"+tds.get(2).text();
  36. String return_time="应还时间"+tds.get(3).text();
  37. Book book=new Book(title,borrow_time,return_time);
  38. bookList.add(book);
  39. Log.d("SearchMyBook","记录---"+title+borrow_time+return_time);
  40. }
  41. adapter.notifyDataSetChanged();
  42. Log.d("SearchMyBook",sb.toString());
  43. }else {
  44. Log.d("SearchMyBook","查询详细信息失败");
  45. }
  46. }
  47. @Override
  48. public void onFailure(Call<String> call, Throwable t) {
  49. Toast.makeText(SearchMyBook.this,"请求失败",Toast.LENGTH_SHORT).show();
  50. }
  51. });
  52. }

第四步在BUTTON点击事件中进行请求,输入参数

  1. btn1.setOnClickListener(new View.OnClickListener() {
  2. @Override
  3. public void onClick(View v) {
  4. Map<String,String> params=new HashMap<>();
  5. params.put("number","******");
  6. params.put("passwd","******");
  7. params.put("captcha", editText.getText().toString());
  8. params.put("select","cert_no");
  9. params.put("returnUrl","");
  10. requestMyBook(params);
  11. Log.d("SearchMyBook",params.toString());
  12. }
  13. });

这样一个模拟登录请求就完成了。下面介绍今天做的另一部分,它让我浪费了很久的时间,感觉自己是真的蠢!!!!!!!
2.这一部分做的是座位的查询,主要卡在了post登录和图片的获取上。
我开始直接用post但是无法登录,后来发现先post一次获得返回的cookie,然后带着cookie才可以登录!(又栽在了cookie上),然后一层一层地访问,直到访问到最后一层发现图片格式很奇怪,百度发现是AJAX生成的,然后我就苦恼了,以为无法通过jsoup获取,因为发现在网页里无法通过输入链接打开,但是最后最后在ANDroid端竟然下载成功了,当我发现打印的Headers信息里,content-type变成了jpg,心情难以抑制的激动啊。。还好舍友提了一次,我抱着不太可能心态尝试了一下竟然成功了!此处先记一下,还是不太理解为什么在Android端可以访问,如果是因为cookie缘故pc上不是自动保存cookie了吗。。回头再去咨询一下大神。。
不管怎么说总算下载成功了,没白花费这么久,开心又希望下次能更快一点。。代码部分还是太冗余,明天尝试进行一下优化封装!!fight!

发表评论

表情:
评论列表 (有 0 条评论,418人围观)

还没有评论,来说两句吧...

相关阅读

    相关 登录验证

    验证码的作用是区分人与机器,防止机器刷数据; 验证码的验证分了两步,一步是请求获取验证码,一步是前台传的验证码与后台的验证码进行对比判断后进行后续操作; 在MyEclips