Android实现模拟登陆教务系统并解析网页数据

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 版权声明:本文为博主原创文章,转载请注明出处http://blog.csdn.net/u013132758。 https://blog.csdn.net/u013132758/article/details/73203820 前言     时光飞逝,日月如梭,转眼间四年的大学生活已经结束啦!开始了程序员的加班生活。
版权声明:本文为博主原创文章,转载请注明出处http://blog.csdn.net/u013132758。 https://blog.csdn.net/u013132758/article/details/73203820

前言

     时光飞逝,日月如梭,转眼间四年的大学生活已经结束啦!开始了程序员的加班生活。我的第二学位的毕业设计是实现一个学习小助手。这其中最重要的环节就是模拟登录学校的教务系统,获取到教务系统的数据并解析,用自己的数据库存储,展示在自己设计的界面上。例如课程表我是仿照超级课程表的界面来设计的。废话不多说下面先看看效果。

   

        

抓取教务系统登录时需要传递的参数

     模拟登录之前我们首先需要抓取我们登录时所需要传递的数据,可能有人会想用专业的抓包工具来抓包,其实不用那么复杂,用火狐浏览器或者Chrom浏览器的开发者模式就可以了。博主用的是火狐浏览器抓包,传的一些参数也是按照火狐浏览器来的。

首先,我们来看一下模拟器登录时需要传递的参数及HTTP请求头,我们可以看到请求是post请求,请求头字段基本差不多

传递的参数有这么些



其中这些参数中lt这个是搞的我最头疼的。本以为lt是一个固定值,但是模拟登录的时候发现不对,每次抓包lt是不一样的。最后,只能通过学习JS代码,研究这个lt的取值,最后发现lt及其他参数都隐藏在返回的HTML页面的代码中:(如下图)


搞清楚需要传什么参数和请求的HTTP头了,我们就可以模拟登录教务系统了。

自定义HTTPClient实现模拟登录

实现模拟登录首先要自定义HTTPClient,来模拟浏览器发送HTTP请求。自定义HTTP如下代码:

/**
 * Http请求工具类
 * @author leiqi
 * @date 2017-3-4
 */
public class HttpUtil {
	private static AsyncHttpClient client = new AsyncHttpClient(); // 实例话对象
	// Host地址
	public static final String HOST = "cas.hdu.edu.cn";
	// 基础地址
	public static final String URL_BASE = "http://i.hdu.edu.cn/dcp/xphone/";
	// 验证码地址
	public static final String URL_CODE = "http://cas.hdu.edu.cn/cas/Captcha.jpg";
	// 登陆地址
	public static final String URL_LOGIN = "http://cas.hdu.edu.cn/cas/login?service=http%3a%2f%2fi.hdu.edu.cn%2fdcp%2fxphone%2fm.jsp";
	// 登录成功的首页
	public static String URL_MAIN = "http://i.hdu.edu.cn/dcp/xphone/m.jsp";
	//当前学期课表
	public static String URL_Course= "http://i.hdu.edu.cn/dcp/xphone/kbcx0.jsp";
	//考试安排url
	public static String URl_KSAP = "http://i.hdu.edu.cn/dcp/xphone/ksap.jsp";
	//校园新闻
	public static String Url_XYXW = "http://m.hdu.edu.cn/";
	//上课时间
	public static String Url_Time = URL_BASE+"TimeTable.jsp";
	//我的学费
	public static String Url_WDXF = "http://yxt.hdu.edu.cn/EducationManager/xphone/m.jsp";

	/**
	 * 请求参数
	 */
	public static String captcha = "";//验证码
	public static String encodedService = "http%3a%2f%2fi.hdu.edu.cn%2fdcp%2fxphone%2fm.jsp";
	public static String loginErrCnt = "0";
	public static String lt = "LT-1552500-7P9jMewfE3wH2dWObBuJ";
	public static String password = "19191cf09b99b03ab0df1db04c3840ed";
	public static String username = null;
	public static String service = "http://i.hdu.edu.cn/dcp/xphone/m.jsp";
	public static String serviceName = null;
	public static String ticket = null;
	public static String Cookie = "key_dcp_cas=HHxRYyDMhr0GmDfQ6vgPxXQT8yCsvPSCg0MWBnnnWMGv4dQngpLS!748587538; route=4376efc7edf61c9fe699e82a2fb7a34f" ;
	// 静态初始化
	static {
		client.setTimeout(10000); // 设置链接超时,如果不设置,默认为10s
		// 设置请求头
		client.addHeader("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
		client.addHeader("Accept-Encoding","gzip, deflate");
		client.addHeader("Accept-Language","zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3");
		client.addHeader("Connection","keep-alive");
		client.addHeader("Cookie", Cookie);
		client.addHeader("Host", HOST);
		client.addHeader("Referer", URL_LOGIN);
		client.addHeader("User-Agent",
				"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:52.0) Gecko/20100101 Firefox/52.0");
		client.addHeader("Upgrade-Insecure-Requests","1");

	}



	/**
	 * get,用一个完整url获取一个string对象
	 * 
	 * @param urlString
	 * @param res
	 */
	public static void get(String urlString, AsyncHttpResponseHandler res) {
		client.get(urlString, res);
	}

	/**
	 * get,url里面带参数
	 *  @param urlString
	 * @param params
	 * @param res
	 */
	public static void get(String urlString, RequestParams params,
						   AsyncHttpResponseHandler res) {
		client.get(urlString, params, res);
	}

	/**
	 * get,不带参数,获取json对象或者数组
	 * 
	 * @param urlString
	 * @param res
	 */
	public static void get(String urlString, JsonHttpResponseHandler res) {
		client.get(urlString, res);
	}

	/**
	 * get,带参数,获取json对象或者数组
	 * 
	 * @param urlString
	 * @param params
	 * @param res
	 */
	public static void get(String urlString, RequestParams params,
                           JsonHttpResponseHandler res) {
		client.get(urlString, params, res);
	}

	/**
	 * get,下载数据使用,会返回byte数据
	 * 
	 * @param uString
	 * @param bHandler
	 */
	public static void get(String uString, BinaryHttpResponseHandler bHandler) {
		client.get(uString, bHandler);
	}

	/**
	 * post,不带参数
	 * 
	 * @param urlString
	 * @param res
	 */
	public static void post(String urlString, AsyncHttpResponseHandler res) {
		client.post(urlString, res);
	}

	/**
	 * post,带参数
	 * 
	 * @param urlString
	 * @param params
	 * @param res
	 */
	public static void post(String urlString, RequestParams params,
                            AsyncHttpResponseHandler res) {
		client.post(urlString, params, res);
	}

	/**
	 * post,不带参数,获取json对象或者数组
	 * 
	 * @param urlString
	 * @param res
	 */
	public static void post(String urlString, JsonHttpResponseHandler res) {
		client.post(urlString, res);
	}

	/**
	 * post,带参数,获取json对象或者数组
	 * 
	 * @param urlString
	 * @param params
	 * @param res
	 */
	public static void post(String urlString, RequestParams params,
                            JsonHttpResponseHandler res) {
		client.post(urlString, params, res);
	}

	/**
	 * post,返回二进制数据时使用,会返回byte数据
	 * 
	 * @param uString
	 * @param bHandler
	 */
	public static void post(String uString, BinaryHttpResponseHandler bHandler) {
		client.post(uString, bHandler);
	}

	/**
	 * 返回请求客户端
	 * 
	 * @return
	 */
	public static AsyncHttpClient getClient() {
		return client;
	}

	/**
	 * 获得登录时所需的请求参数
	 * 
	 * @return
	 */
	public static RequestParams getLoginRequestParams() {
		// 设置请求参数
		RequestParams params = new RequestParams();
		params.add("captcha", captcha);
		params.add("encodedService", encodedService);
		params.add("loginErrCnt", loginErrCnt);
		params.add("lt", lt);
		params.add("password", password);
		params.add("username", username);
		params.add("service", service);
		params.add("serviceName", serviceName);
		return params;
	}

	/**
	 * 获取请求首页参数
	 * @return
	 */
	public static RequestParams gethomeRequestParams(){
		RequestParams params = new RequestParams();
		params.add("ticket",ticket);
		return params;
	}


}
定义完HTTP客户端,我们就需要去模拟登录,当然模拟登录必须要设置CookieStore如下所示:

   /**
     * 初始化Cookie
     */
    private void initCookie(Context context) {
        //必须在请求前初始化
        cookie = new PersistentCookieStore(context);
        HttpUtil.getClient().setCookieStore(cookie);
        httpClient.setCookieStore(cookie);
    }
然后在请求登录页面时候就可以将返回的cookie设置给HTTPClient了。

难到这样就可以了?那那个lt值怎么获取传递过去昵?先贴一段获取lt的代码后面做解释:

/**
     * 获取lt
     */
    private void getlt(){
        Document doc = null;
            doc = Jsoup.parse(GetShouye());
            if (doc != null)
        if (doc != null) {
            Elements login = doc.body().getElementsByClass("login_form");
            Document containerDoc = Jsoup.parse(login.toString());
            Elements ddd = containerDoc.getElementsByTag("input");
            for (Element aaa : ddd) {
                if (aaa.toString().contains("lt")) {
                    String l = aaa.toString();
                    String lt = l.substring(38, l.length() - 4);
                    HttpUtil.lt = lt;
                }
            }
        }
    }

 /**
     * 请求首页
     * @return
     */
    public String GetShouye()
    {
        String result= "";

//    	创建HttpGet或HttpPost对象,将要请求的URL通过构造方法传入HttpGet或HttpPost对象。
        if (urlll == null){
            urlll = HttpUtil.URL_MAIN;
        }
        HttpGet httpRequst = new HttpGet(urlll);

//    	new DefaultHttpClient().execute(HttpUriRequst requst);
        try {
            //使用DefaultHttpClient类的execute方法发送HTTP GET请求,并返回HttpResponse对象。
            HttpResponse httpResponse = httpClient.execute(httpRequst);//其中HttpGet是HttpUriRequst的子类
            if (httpResponse.getStatusLine().getStatusCode() == 200) {
                HttpEntity httpEntity = httpResponse.getEntity();
                result = EntityUtils.toString(httpEntity);//取出应答字符串
                // 一般来说都要删除多余的字符
                result.replaceAll("\r", "");//去掉返回结果中的"\r"字符,否则会在结果字符串后面显示一个小方格
            } else{
                httpRequst.abort();
            }
        }catch (ClientProtocolException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            result = e.getMessage().toString();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            result = e.getMessage().toString();
        }
        return result;
    }
所有准备工作做好我们就可以发送登录请求了

 /**
     * 登录
     */
    private void login() {
        HttpUtil.username = username.getText().toString().trim();
        String md5 = "@";
        try {
            md5= MD5Until.GetMD5Code(password.getText().toString().trim());
        } catch (Exception e) {
            e.printStackTrace();
        }
        Log.d("md5  ",md5);
        HttpUtil.password = md5;
        //需要时打开验证码注释
        HttpUtil.captcha = secrectCode.getText().toString().trim();
        Log.d("cookie",HttpUtil.Cookie);
        if (TextUtils.isEmpty(HttpUtil.username)
                || TextUtils.isEmpty(HttpUtil.password)) {
            Toast.makeText(getApplicationContext(), "账号或者密码不能为空!",
                    Toast.LENGTH_SHORT).show();
            return;
        }
        final ProgressDialog dialog =CommonUtil.getProcessDialog(BindActivity.this,"正在登录中!!!");
        dialog.show();
        RequestParams params = HttpUtil.getLoginRequestParams();// 获得请求参数
        Log.d("http",params.toString());
        HttpUtil.getClient().setURLEncodingEnabled(true);
        HttpUtil.post(HttpUtil.URL_LOGIN, params,
                new AsyncHttpResponseHandler() {

                    @Override
                    public void onSuccess(int arg0, Header[] arg1, byte[] arg2) {
                        try {
                            String resultContent = new String(arg2, "gb2312");
                            Log.d("Header",arg1.toString());
                            Log.d("resunt",resultContent);
//							List<String> list = Getlt.match(resultContent,"input","name=\"lt\" ");
//							Log.d("list",list.toString());
                            if(linkService.isLogin(resultContent)!=null){
                                String ret = linkService.parseMenu(resultContent);
                                Log.d("cas", "login success:"+ret);
                                GetHerfUrl(resultContent);
                                Toast.makeText(getApplicationContext(),
                                        "登录成功!!!", Toast.LENGTH_SHORT).show();
                                new Thread(new Runnable() {
                                    @Override
                                    public void run() {
                                        String s = GetShouye();
                                        Log.d("sdfsdaf",s);
                                        String ss = Getksap();
                                        Log.d("qqqqqq",ss);
                                        jump2Main();
                                    }
                                }).start();

                            }else{
                                getCode();
                                Toast.makeText(getApplicationContext(),"账号或者密码错误!!!", Toast.LENGTH_SHORT).show();
                            }

                        } catch (UnsupportedEncodingException e) {
                            e.printStackTrace();
                        } finally {
                            dialog.dismiss();
                        }

                    }
                    @Override
                    public void onFailure(int arg0, Header[] arg1, byte[] arg2,
                                          Throwable arg3) {
                        Toast.makeText(getApplicationContext(), "登录失败!!!!",
                                Toast.LENGTH_SHORT).show();
                        dialog.dismiss();
                    }
                });
    }
登录成功后会返回一个链接,并不是登录后的教务首页,我们还需要解析提取链接并用GET请求去请求,即可!下面我们就来说一下关于HTML网页数据的解析。

JSOUP对HTML网页数据的解析

       JSOUP是一个非常好用的,用JAVA来抓取网页数据的开源框架。使用起来也非常简单,就是根据HTML内容,先获取BODY====》》》提取字段对应的class====》》》对应的标签ID。我们还是以lt为例来看:

    /**
     * 获取lt
     */
    private void getlt(){
        Document doc = null;
            doc = Jsoup.parse(GetShouye());
            if (doc != null)
        if (doc != null) {
            //获取解析后的body及对应的class——login_form
            Elements login = doc.body().getElementsByClass("login_form");
            Document containerDoc = Jsoup.parse(login.toString());
            //获取到标签id对应的数据
            Elements ddd = containerDoc.getElementsByTag("input");
            for (Element aaa : ddd) {
                //从这些数据中提取出lt
                if (aaa.toString().contains("lt")) {
                    String l = aaa.toString();
                    String lt = l.substring(38, l.length() - 4);
                    HttpUtil.lt = lt;
                }
            }
        }
    }
后面所有的数据获取都是这样,不过后面都是解析table而已。下面觉得重点应该说一下对课程信息的存储。

课程表信息的存储与读取

      课程表信息的存储也是非常麻烦的一件事,当时没想明白,存储完之后发现读到的数据全乱了。

{\"Course_address\":\"第12教研楼405\",\"Course_name\":\"网站规划与设计\",
        \"Course_teacher\":\"李君君\",\"Course_type\":\"必修\",\"Course_week\":\"周一第3,4节{第1-16周}\"},
上面是用JSON数组来存储每节课信息的存储结构,绘制课程表时,根据课表中的字段。如下所示:

public class CourseActivity extends Activity {
    private ArrayList<CourseBean> mCourse;
    private SharedPreferences mShaerPreferences;
    // 每天有多少节课
    private int mMaxCouese;
    // 一共有多少周
    private int mMaxWeek;
    // 现在是第几周
    private int mNowWeek;
    // 左边一节课的高度
    private float mLeftHeight;
    // 左边一节课的宽度
    private float mLeftWidth;

    private TextView mChangeWeek;
    private LinearLayout mLeftNo;
    private LinearLayout mMonday;
    private LinearLayout mTuesday;
    private LinearLayout mWednesday;
    private LinearLayout mThursday;
    private LinearLayout mFirday;
    private LinearLayout mSaturday;
    private LinearLayout mWeekend;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_course);
        // 实例化所有对象
        initCtrl();
        // 初始化数据
        initData();

        // 绘制左边的课程节数
        drawLeftNo();
        // 绘制当前周
        drawNowWeek();
        // 绘制所有课程 其实可以使用redrawAll替代三步
        drawAllCourse();
    }

    /**
     * 实例化所有对象
     */
    private void initCtrl() {
        mChangeWeek = (TextView) findViewById(R.id.changeWeek);
        mLeftNo = (LinearLayout) findViewById(R.id.leftNo);
        mMonday = (LinearLayout) findViewById(R.id.monday);
        mTuesday = (LinearLayout) findViewById(R.id.tuesday);
        mWednesday = (LinearLayout) findViewById(R.id.wednesday);
        mThursday = (LinearLayout) findViewById(R.id.thursday);
        mFirday = (LinearLayout) findViewById(R.id.firday);
        mSaturday = (LinearLayout) findViewById(R.id.saturday);
        mWeekend = (LinearLayout) findViewById(R.id.weekend);
    }

    /**
     * 初始化所有数据
     */
    private void initData() {
        // 初始化课表
        praseJson();
        // 读取配置信息
        readIniFile();

        // 点击选择切换周
        mChangeWeek.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                showChangeWeekDlg(v);
            }
        });
    }

    /**
     * 绘制左边的课程节数
     */
    private void drawLeftNo() {
        mLeftHeight = getResources().getDimension(R.dimen.left_height);
        mLeftWidth = getResources().getDimension(R.dimen.left_width);
        LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
                (int) mLeftWidth, (int) mLeftHeight);
        for (int i = 1; i <= mMaxCouese; i++) {
            TextView tv = new TextView(this);
            tv.setText(i + "");
            tv.setGravity(Gravity.CENTER);
            tv.setTextColor(getResources().getColor(R.color.font));
            tv.setBackgroundResource(R.drawable.boder);
            mLeftNo.addView(tv, lp);
        }
    }

    /**
     * 绘制课表
     *
     * @param ll
     *            绘制课表到哪一个LinearLayout上
     * @param dayOfWeek
     *            绘制的数据来自周几 一二三四五六七
     */
    private void drawCourse(LinearLayout ll, char dayOfWeek) {
        // 删除所有子View
        ll.removeAllViews();
        // 上一节课结束是第几节
        int perCourse = -1;
        for (CourseBean course : mCourse) {
            // 判断是否显示这节课
            // 是不是同一天 是不是这一周
            if (course.getDayOfWeek() != dayOfWeek
                    || !course.inThisWeek(mNowWeek))
                continue;

            // 设置TextView的属性样式
            TextView tv = new TextView(this);
            tv.setText(course.getCourse_name() + "\n@"
                    + course.getCourse_address());
            tv.setBackgroundResource(R.drawable.course);
            tv.setTextColor(getResources().getColor(R.color.course_font_color));
            tv.setTextSize(12);
            // 将数据绑定到TextView上
            tv.setTag(course);
            tv.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    CourseBean tag = (CourseBean) v.getTag();
                    showCouseDetails(tag);
                }
            });

            // 设置TextView的位置
            LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
                    LayoutParams.MATCH_PARENT,
                    (int) (course.getStep() * mLeftHeight));
            // 说明这节课为第一节课
            if (perCourse == -1) {
                lp.setMargins(1,
                        (int) ((course.getMinCourse() - 1) * mLeftHeight), 1, 0);
                // useHeight = (int) ((course.getMaxCourse()-1) * mLeftHeight);
            } else {
                lp.setMargins(1, (course.getMinCourse() - perCourse - 1)
                        * (int) mLeftHeight, 1, 0);
                // useHeight = useHeight + (course.getMaxCourse() - perCourse -
                // 1)* (int) mLeftHeight;
            }
            perCourse = course.getMaxCourse();
            ll.addView(tv, lp);
        }
    }

    /**
     * 绘制当前周
     */
    private void drawNowWeek() {
        mChangeWeek.setText("第" + mNowWeek + "周");
    }

    /**
     * 重新绘制所有,不包括标题栏和星期几 在修改每天的节数后调用
     */
	/*private void redrawAll() {
		drawLeftNo();
		drawNowWeek();
		drawAllCourse();
	}*/

    /**
     * 绘制课程,用于周数切换以后
     */
    private void drawAllCourse() {
        drawCourse(mMonday, '一');
        drawCourse(mTuesday, '二');
        drawCourse(mWednesday, '三');
        drawCourse(mThursday, '四');
        drawCourse(mFirday, '五');
        drawCourse(mSaturday, '六');
        drawCourse(mWeekend, '日');
    }

    /**
     * 读取配置信息
     */
    private void readIniFile() {
        mShaerPreferences = getSharedPreferences("iniFile",
                Context.MODE_PRIVATE);
        mMaxCouese = mShaerPreferences.getInt("mMaxCouese", -1);
        mMaxWeek = mShaerPreferences.getInt("mMaxWeek", -1);
        mNowWeek = mShaerPreferences.getInt("mNowWeek", -1);

        Editor edit = mShaerPreferences.edit();
        // 默认12节课
        if (mMaxCouese == -1) {
            edit.putInt("mMaxCouese", 12);
        }

        // 默认20周
        if (mMaxWeek == -1) {
            edit.putInt("mMaxWeek", 17);
        }

        // 默认第一周
        if (mNowWeek == -1) {
            edit.putInt("mNowWeek", 15);
        }
        edit.commit();
    }

    /**
     * 解析来自strings.xml里面的Json课表数据
     */
    private void praseJson() {
        String json = getResources().getString(R.string.kb);
        Gson gson = new Gson();
        mCourse = gson.fromJson(json, new TypeToken<ArrayList<CourseBean>>() {
        }.getType());
    }

    /**
     * 弹出窗口,显示课程详细信息
     *
     */
    public void showCouseDetails(CourseBean bean) {
        AlertDialog.Builder builder = new Builder(this);
        AlertDialog dialog = builder.create();
        dialog.show();
        dialog.setContentView(R.layout.details_layout);
        TextView textView = (TextView) dialog.findViewById(R.id.name);
        textView.setText(bean.getCourse_name());
        textView = (TextView) dialog.findViewById(R.id.type);
        textView.setVisibility(View.GONE);
        textView.setText(bean.getCourse_type());
        textView = (TextView) dialog.findViewById(R.id.teacher);
        textView.setText(bean.getCourse_teacher());
        textView = (TextView) dialog.findViewById(R.id.address);
        textView.setText(bean.getCourse_address());
        textView = (TextView) dialog.findViewById(R.id.week);
        textView.setText(bean.getCourse_week());
    }

    /**
     * 显示切换当前周的窗口
     */
    public void showChangeWeekDlg(View v) {
        View view = View.inflate(this, R.layout.changweek_layout, null);
        ListView weekList = (ListView) view.findViewById(R.id.weekList);

        ArrayList<String> strList = new ArrayList<String>();
        for (int i = 1; i < mMaxWeek; i++) {
            strList.add("第" + i + "周");
        }

        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
                R.layout.item, strList);

        weekList.setAdapter(adapter);
        view.measure(0, 0);
        final PopupWindow pop = new PopupWindow(view, 300, 500, true);
        pop.setBackgroundDrawable(new ColorDrawable(0x00000000));
        int xOffSet = -(pop.getWidth() - v.getWidth()) / 2;
        pop.showAsDropDown(v, xOffSet, 0);

        weekList.setOnItemClickListener(new OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> adapter, View view,
                                    int positon, long id) {
                mNowWeek = positon + 1;
                pop.dismiss();
                drawNowWeek();
                drawAllCourse();
            }
        });
    }

}
项目地址:https://github.com/Terrybthvi/HduStudyHelper







相关文章
|
19天前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
99 2
|
23小时前
|
JavaScript API 开发工具
<大厂实战场景> ~ Flutter&鸿蒙next 解析后端返回的 HTML 数据详解
本文介绍了如何在 Flutter 中解析后端返回的 HTML 数据。首先解释了 HTML 解析的概念,然后详细介绍了使用 `http` 和 `html` 库的步骤,包括添加依赖、获取 HTML 数据、解析 HTML 内容和在 Flutter UI 中显示解析结果。通过具体的代码示例,展示了如何从 URL 获取 HTML 并提取特定信息,如链接列表。希望本文能帮助你在 Flutter 应用中更好地处理 HTML 数据。
70 1
|
5天前
|
自然语言处理 数据可视化 前端开发
从数据提取到管理:合合信息的智能文档处理全方位解析【合合信息智能文档处理百宝箱】
合合信息的智能文档处理“百宝箱”涵盖文档解析、向量化模型、测评工具等,解决了复杂文档解析、大模型问答幻觉、文档解析效果评估、知识库搭建、多语言文档翻译等问题。通过可视化解析工具 TextIn ParseX、向量化模型 acge-embedding 和文档解析测评工具 markdown_tester,百宝箱提升了文档处理的效率和精确度,适用于多种文档格式和语言环境,助力企业实现高效的信息管理和业务支持。
31 0
从数据提取到管理:合合信息的智能文档处理全方位解析【合合信息智能文档处理百宝箱】
|
17天前
|
消息中间件 中间件 数据库
NServiceBus:打造企业级服务总线的利器——深度解析这一面向消息中间件如何革新分布式应用开发与提升系统可靠性
【10月更文挑战第9天】NServiceBus 是一个面向消息的中间件,专为构建分布式应用程序设计,特别适用于企业级服务总线(ESB)。它通过消息队列实现服务间的解耦,提高系统的可扩展性和容错性。在 .NET 生态中,NServiceBus 提供了强大的功能,支持多种传输方式如 RabbitMQ 和 Azure Service Bus。通过异步消息传递模式,各组件可以独立运作,即使某部分出现故障也不会影响整体系统。 示例代码展示了如何使用 NServiceBus 发送和接收消息,简化了系统的设计和维护。
32 3
|
18天前
|
数据采集 XML 前端开发
Jsoup在Java中:解析京东网站数据
Jsoup在Java中:解析京东网站数据
|
1天前
|
JSON 前端开发 JavaScript
API接口商品详情接口数据解析
商品详情接口通常用于提供特定商品的详细信息,这些信息比商品列表接口中的信息更加详细和全面。以下是一个示例的JSON数据格式,用于表示一个商品详情API接口的响应。这个示例假定API返回一个包含商品详细信息的对象。
|
14天前
|
API
Vue3组件通信全解析:利用props、emit、provide/inject跨层级传递数据,expose与ref实现父子组件方法调用
Vue3组件通信全解析:利用props、emit、provide/inject跨层级传递数据,expose与ref实现父子组件方法调用
174 0
|
14天前
|
前端开发 算法 JavaScript
无界SaaS模式深度解析:算力算法、链接力、数据确权制度
私域电商的无界SaaS模式涉及后端开发、前端开发、数据库设计、API接口、区块链技术、支付和身份验证系统等多个技术领域。本文通过简化框架和示例代码,指导如何将核心功能转化为技术实现,涵盖用户管理、企业店铺管理、数据流量管理等关键环节。
|
14天前
|
域名解析 缓存 网络协议
Windows系统云服务器自定义域名解析导致网站无法访问怎么解决?
Windows系统云服务器自定义域名解析导致网站无法访问怎么解决?
|
24天前
|
安全 网络安全 Android开发
深度解析:利用Universal Links与Android App Links实现无缝网页至应用跳转的安全考量
【10月更文挑战第2天】在移动互联网时代,用户经常需要从网页无缝跳转到移动应用中。这种跳转不仅需要提供流畅的用户体验,还要确保安全性。本文将深入探讨如何利用Universal Links(仅限于iOS)和Android App Links技术实现这一目标,并分析其安全性。
136 0

推荐镜像

更多