热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

校园助手APP--爬取教务处网页,并解析出数据

在使用服务器前,我是直接爬取网页数据的,包括做到最后也还是采用直接爬教务处网页获得通知内容的。这种方式在有些时候也是会用得上的,在此介绍一下publicclassInternetHelper{p

在使用服务器前,我是直接爬取网页数据的,包括做到最后也还是采用直接爬教务处网页获得通知内容的。这种方式在有些时候也是会用得上的,在此介绍一下


public class InternetHelper {

private static final String TAG = "InternetHelper";


public static final String URL_BASE = "http://61.183.207.40/zjdxgc/(kgd5dczwtsnv50yznsqeuh55)/";
public static final String USER_AGENT = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)";
public static final String HOST = "http://61.183.207.40";

private static COOKIEStore COOKIE = null;

/**
* 单例模式,生成HttpClient对象,并进行请求参数封装
* @return HttpClient对象
*/
public static DefaultHttpClient getClient(){
DefaultHttpClient client = null;
if (null == client) {
HttpParams httpParams = new BasicHttpParams();
httpParams.setParameter("http.protocol.allow-circular-redirects", Boolean.valueOf(true));
httpParams.setParameter(ClientPNames.COOKIE_POLICY, COOKIEPolicy.BEST_MATCH);
HttpClientParams.setRedirecting(httpParams, true);

//设置编码
HttpProtocolParams.setContentCharset(httpParams, HTTP.UTF_8);
HttpProtocolParams.setUseExpectContinue(httpParams, true);
HttpProtocolParams.setUserAgent(httpParams, USER_AGENT);

HttpConnectionParams.setTcpNoDelay(httpParams, true);
//关闭旧连接检查,提升速度
HttpConnectionParams.setStaleCheckingEnabled(httpParams, false);
////从连接池中取连接的超时时间
//ConnManagerParams.setTimeout(httpParams, 1000);
////连接超时
//HttpConnectionParams.setConnectionTimeout(httpParams, 2000);
////请求超时
//HttpConnectionParams.setSoTimeout(httpParams, 4000);

//设置httpClient支持HTTP和HTTPS两种模式
SchemeRegistry schReg = new SchemeRegistry();
schReg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
schReg.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));

//使用线程安全的连接管理
ClientConnectionManager cOnMgr= new ThreadSafeClientConnManager(httpParams, schReg);

client = new DefaultHttpClient(conMgr, httpParams);
}

if (null != COOKIE) {
client.setCOOKIEStore(COOKIE);
Log.i(TAG, COOKIE.toString());
}

return client;
}


/**
* 通过URL获取含有新闻的网页源码
* @param url_news
* @return
* @throws Exception
*/
public static String getNewsHtmlByURL(String url_news) throws Exception {

DefaultHttpClient client = InternetHelper.getClient();

HttpGet localHttpGet = new HttpGet(url_news);
String referer = url_news;

localHttpGet.setHeader("Referer", referer);
localHttpGet.setHeader("User-Agent", USER_AGENT);

HttpResponse httpRespOnse= client.execute(localHttpGet);
int statusCode = httpResponse.getStatusLine().getStatusCode();
System.out.println("statusCode————————————————>" + statusCode);

String html = null;

if (statusCode == 400) {
HttpEntity localHttpEntity = httpResponse.getEntity();
System.out.println("出错了,400,下面是得到的html代码:"+ EntityUtils.toString(localHttpEntity, "gb2312"));
return null;
}else if (statusCode == 302) {//网页跳转

//从头信息中获取跳转地址
Header[] arrayOfHeader = httpResponse.getHeaders("Location");
String location = HOST + arrayOfHeader[0].getValue();

HttpGet httpGet = new HttpGet(location);
httpGet.setHeader("Referer", location);
html = EntityUtils.toString(client.execute(httpGet).getEntity(), "gb2312");
httpGet.abort();
} else if (statusCode == 200){
html = EntityUtils.toString(httpResponse.getEntity(),"gb2312");
}
return html;
}

}

直接访问网页需要添加一些头信息,具体需要哪些头信息就需要通过抓包来得到,换了几次电脑,忘了当时是用的chrome的什么插件

这样获取得到的是整个网页的源码,需要解析源码获得需要的信息,首先是教务处通知的列表信息,包含通知的标题以及相应的链接

/**
* 通过获取的含有新闻标题的网页源码获取新闻列表
* @param html
* @return
*/
private static List getNewsByHtml(String html) {

List newsList = new ArrayList();
String reg = "(]*&todo=show\" target=\"_blank\">).*?()";

Pattern pattern = Pattern.compile(reg);
Matcher matcher = pattern.matcher(html);

while (matcher.find()) {
String titleStr = matcher.group(0);
String title = titleStr.substring(titleStr.indexOf('】')+1, titleStr.indexOf("String source = titleStr.substring(titleStr.indexOf('【')+1, titleStr.indexOf('】'));
String url = "http://jwc.wit.edu.cn/" + titleStr.substring(titleStr.indexOf("href=\"")+"href=\"".length(), titleStr.indexOf("todo=show")+"todo=show".length());

News news = new News();//封装为news对象
news.setTitle(title);
news.setSource(source);
news.setUrl(url);

newsList.add(news);
}
return newsList;
}

不断的分析源码,通过正则表达式获得标题及链接,封装为一个列表显示出来,点击列表中的某一条标题,就跳到该通知的详细内容页面。

通过链接可以获取到详细通知的网页源码,由于源码中包含太多的标签信息,为方便找到正文开始的地方,就通过通知的标题来定位:

/**
* 通过点击的新闻标题得到News实体
* @param title
* @return
* @throws Exception
*/
public News getNewsByTitle(String title) throws Exception {

SQLiteDatabase database = dbHelper.getWritableDatabase();
Cursor cursor = database.query(News.TABLE_NAME, new String[]{News.ID,News.URL,News.SOURCE,News.TIME,News.CONTENT}, News.TITLE+"=?", new String[]{title}, null, null, null);

News news = new News();
if(cursor.moveToFirst()){
news.setId(cursor.getLong(cursor.getColumnIndex(News.ID)));
news.setTime(cursor.getString(cursor.getColumnIndex(News.TIME)));
news.setSource(cursor.getString(cursor.getColumnIndex(News.SOURCE)));
news.setContent(cursor.getString(cursor.getColumnIndex(News.CONTENT)));
news.setUrl(cursor.getString(cursor.getColumnIndex(News.URL)));
news.setTitle(title);
}

//如果数据库中的news数据没有新闻主体部分则联网获取
if (null == news.getContent()) {
String url = news.getUrl();

String html = InternetHelper.getNewsHtmlByURL(url);

html = html.substring(html.indexOf(title)+title.length());//去头
String regexstr = "<(?!p|/p).*?>";
html = html.replaceAll(regexstr, "");//去HTML标签
html = html.replace(" ", " ");//去空格

//获取新闻内容
String cOntent= html.substring(html.indexOf("教务处")+3, html.lastIndexOf("机构设置")).trim();//去尾
//获取发布时间
String time = html.substring(html.indexOf("发布时间:")+5, html.indexOf("点击次数"));

news.setTime(time);
news.setContent(content);

//更新数据库中的数据,主要是加入content和time
updateNews(news);
}
database.close();
return news;
}

去掉网页源码的头尾后,就能够清晰地看到内容部分及一些网页标签,再次通过正则表达式解析出正文内容。

因为获取到通知信息后,我是存到数据库的,所以初始化时会先从数据库获取信息,只是还没来得及做列表刷新大笑


这里特别提出一个地方

String regexstr = "<(?!p|/p).*?>";
html = html.replaceAll(regexstr, "");//去HTML标签
html = html.replace(" ", " ");//去空格

真是好用!

很好地把正文内容分里出来了



推荐阅读
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • Whatsthedifferencebetweento_aandto_ary?to_a和to_ary有什么区别? ... [详细]
  • 欢乐的票圈重构之旅——RecyclerView的头尾布局增加
    项目重构的Git地址:https:github.comrazerdpFriendCircletreemain-dev项目同步更新的文集:http:www.jianshu.comno ... [详细]
  • SpringBoot uri统一权限管理的实现方法及步骤详解
    本文详细介绍了SpringBoot中实现uri统一权限管理的方法,包括表结构定义、自动统计URI并自动删除脏数据、程序启动加载等步骤。通过该方法可以提高系统的安全性,实现对系统任意接口的权限拦截验证。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
  • 本文介绍了游标的使用方法,并以一个水果供应商数据库为例进行了说明。首先创建了一个名为fruits的表,包含了水果的id、供应商id、名称和价格等字段。然后使用游标查询了水果的名称和价格,并将结果输出。最后对游标进行了关闭操作。通过本文可以了解到游标在数据库操作中的应用。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • ALTERTABLE通过更改、添加、除去列和约束,或者通过启用或禁用约束和触发器来更改表的定义。语法ALTERTABLEtable{[ALTERCOLUMNcolu ... [详细]
  • 本文介绍了iOS数据库Sqlite的SQL语句分类和常见约束关键字。SQL语句分为DDL、DML和DQL三种类型,其中DDL语句用于定义、删除和修改数据表,关键字包括create、drop和alter。常见约束关键字包括if not exists、if exists、primary key、autoincrement、not null和default。此外,还介绍了常见的数据库数据类型,包括integer、text和real。 ... [详细]
  • 开发笔记:实验7的文件读写操作
    本文介绍了使用C++的ofstream和ifstream类进行文件读写操作的方法,包括创建文件、写入文件和读取文件的过程。同时还介绍了如何判断文件是否成功打开和关闭文件的方法。通过本文的学习,读者可以了解如何在C++中进行文件读写操作。 ... [详细]
  • 基于Socket的多个客户端之间的聊天功能实现方法
    本文介绍了基于Socket的多个客户端之间实现聊天功能的方法,包括服务器端的实现和客户端的实现。服务器端通过每个用户的输出流向特定用户发送消息,而客户端通过输入流接收消息。同时,还介绍了相关的实体类和Socket的基本概念。 ... [详细]
  • 本文介绍了Oracle存储过程的基本语法和写法示例,同时还介绍了已命名的系统异常的产生原因。 ... [详细]
author-avatar
shahua1111
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有