如何使用使用java抓取网页内容信息并制作一个排名系统

3068人阅读
& & & & 之前学了一些java web的编程,理解了web应用的原理后,就突然想到,可以用java模拟登录吉珠的教务系统,然后爬取里面的课表、成绩、个人信息等等数据,然后就可以写成一个简易的课表APP。
一、第三方工具
& & & & &这里我用到了httpClient这个第三方包,相信很多人都认识这个包,不认识的话可以自行百度一下,httpClient和传统的URLConnection相比,更加强大,更加灵活,更加易用,我用的是httpcomponents-client-4.5.2,下载地址:
二、思路描述
& & & & 这里就拿获取课表的例子说一下,首先,要登录教务系统,就要获取登录的验证码,然后输入学号密码和验证码后,向教务网发起登录请求,接着要做的就是维持登录状态,登录状态是靠cookie里的sessionID这个参数维持的,只需要保存cookie就行了,在后续的所有提交的请求里,只要都带着cookie一起提交,就能保持在登录状态,保证获取正确的页面,在登录成功后,就在响应页面里找到查询个人课表的链接,然后再提交查询课表的请求,得到的响应就是个人课表的页面,这时就直接抓取课表部分的内容就行了。至于怎么准确抓取相应的数据,当然是用正则表达式了,不懂正则表达式的自行百度。
三、页面分析
& & & & 按F12打开浏览器的开发者工具(我用的是火狐浏览器),然后访问学校的正方教务网,点击页面上的登录按钮后,开发者工具窗口中可以看到如下图片中的内容
& & & & 可以看到点击登录按钮后浏览器提交了一个post请求,请求/default2.aspx这个页面,然后表单数据里有若干个参数,包括学号、密码、验证码等,这里面还有一个__VIEWSTATE参数,查看页面源码得知这是一个表单隐藏域,这个参数的值要每次都在相应页面中通过正则匹配抽取出来。如果登录成功的话,会重定向到页面/xs_main.aspx?xh=***,这里的&***&就是对应的学生学号。
& & & &&接下来点击个人课表的链接,在开发者工具中可以看到请求课表页面的链接和对应参数,这些参数的值都可以在响应的HTML中匹配出来。
& & & & 最后,在个人课表的页面HTML中,我们能看到所有的课程信息,利用正则匹配我们就能把每个课程的名称、上课时间、上课教室、任课老师等信息抽取出来,并封装成一个java对象。
四、代码实现
& & & & 在这之前,我把一些固定的链接等字符串封装到一个常量类里,代码如下
* @author EsauLu
public class Constant {
* 验证码为空
public static final String CHECK_NULL_ERROR=&验证码不能为空,如看不清请刷新!!&;
* 验证码不正确
public static final String CHECK_ERROR=&验证码不正确!!&;
* 密码错误
public static final String PASSWD_ERROR=&密码错误!!&;
* 字符编码
public static final String ENCODING=&GB2312&;
* 用户类型
public static final String RADIO_BUTTON_LIST=&学生&;
* 教务网地址
public static final String BASE_URL=&http://jw.jluzh.com&;
* 验证码URL
public static final String CHECK_IMAGE_URL=BASE_URL+&/CheckCode.aspx&;
public static final String LOGIN_URL=BASE_URL+&/default2.aspx&;
* 登陆后主页面URL
public static final String STUDENT_URL=BASE_URL+&/xs_main.aspx?xh=&;
& & & & 首先,我定义了一个HttpInterface接口,定义了一些用于登录、获取验证码、获取课表等等的方法,详细请看代码
import org.apache.http.client.entity.UrlEncodedFormE
import com.jluzh.jw.bean.CourseT
import com.jluzh.jw.bean.PersonalI
import com.jluzh.jw.bean.U
* 获取数据的接口
* @author EsauLu
public interface HttpInterface {
* 初始化,主要用于收集cookie和viewState
public void init();
* 根据指定url发送给请求
* @param url 请求url
* @param ref 引用
* @return 响应页面的HTML文档
public StringBuffer sendGetRequest(String url,String ref);
* 根据指定url和参数值发送post请求
* @param url 请求url
* @param ref 引用
* @param entity 参数列表
* @return 响应页面的HTML文档
public StringBuffer sendPostRequest(String url,String ref, UrlEncodedFormEntity entity);
* 获取验证码
* @return 验证码图片
public byte[] getCheckImg();
* @param user 用户信息
* @return 返回登陆是否成功
public boolean login(User user);
* 根据学年度和学期获取课表
* @param xnd 学年度
* @param xqd 学期
* @return 课表
public CourseTable getCourseTable(String xnd,String xqd);
* 根据学年度和学期获取课表的Json串
* @param xnd 学年度
* @param xqd 学期
* @return 课表Json串
public String getCourseTableAsJson(String xnd,String xqd);
* 获取个人信息
* @param url 查询个人信息的url
* @return 个人信息
public PersonalInfo getPersonalInfo(String url);
* 获取错误信息
* @return 返回错误信息
public String getErrorMessege();
& & & & 然后下面就是接口的实现。需要说明一下的是,HttpService这个实现类做了维持登录的工作,就是把cookie保存起来。在初始化时,init()函数里首先访问一下教务网,然后记录cookie,cookie里有个参数ASP.NET_SessionId的参数,维持登录靠的就是这个参数。然后在获取验证码、登录、获取课表等的函数实现里,提交的请求都要设置cookie域,否则的话响应内容将是登录页面(这个知道web后端开发的都懂吧)。
import java.io.IOE
import java.io.InputS
import java.io.UnsupportedEncodingE
import java.util.ArrayL
import java.util.regex.M
import java.util.regex.P
import org.apache.http.client.ClientProtocolE
import org.apache.http.client.entity.UrlEncodedFormE
import org.apache.http.client.methods.CloseableHttpR
import org.apache.http.client.methods.HttpG
import org.apache.http.client.methods.HttpP
import org.apache.http.impl.client.CloseableHttpC
import org.apache.http.impl.client.HttpC
import org.apache.http.message.BasicNameValueP
import org.apache.http.util.EntityU
import com.jluzh.jw.bean.C
import com.jluzh.jw.bean.CourseT
import com.jluzh.jw.bean.PersonalI
import com.jluzh.jw.bean.StuSimpleI
import com.jluzh.jw.bean.U
import com.jluzh.jw.constant.C
import com.jluzh.jw.tool.HtmlT
public class HttpService implements HttpInterface {
* Http客户端
private CloseableHttpClient mHttpC
* 记录cookie
private String mC
* 记录正方教务系统页面表单的__VIEWSTATE的值
private String mViewS
* 已登陆用户的信息
private User mU
* 登陆错误信息
private String mErrorM
* 查询课程表信息的URL
private String mCourseURL;
* 查询个人信息的URL
private String mPersonalInfoURL;
* 查询成绩表的URL
private String mScorceURL;
* 构造函数
public HttpService() {
// TODO Auto-generated constructor stub
this.mErrorMessege=&no error&;
mHttpClient=HttpClients.createDefault();
public void init() {
// TODO Auto-generated method stub
String url=Constant.BASE_URL;
HttpGet httpGet=new HttpGet(url);
CloseableHttpResponse response=mHttpClient.execute(httpGet);//提交请求获得响应
mCookie=response.getFirstHeader(&Set-Cookie&).getValue(); //获取cookie
StringBuffer sb=sendGetRequest(url,null); //发送访问请求并获得响应页面
mViewState=HtmlTools.findViewState(sb.toString()); //提取页面表单中的__VIEWSTATE的值
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
public StringBuffer sendGetRequest(String url,String ref) {
// TODO Auto-generated method stub
StringBuffer sb=new StringBuffer();
InputStream in=
HttpGet httpGet=new HttpGet(url);
httpGet.setHeader(&Cookie&, mCookie);//设置cookie
if(ref!=null&&!ref.equals(&&)){
httpGet.setHeader(&Referer&,ref);//如果有地址引用则设置
CloseableHttpResponse response=mHttpClient.execute(httpGet);//提交请求获得响应
in=response.getEntity().getContent();
//获取响应内容
if(in!=null){
int len=-1;
byte[] data=new byte[1024];
while((len=in.read(data))!=-1){
String s=new String(data,0,len,Constant.ENCODING);
sb.append(s);
} catch (Exception e) {
// TODO: handle exception
if(in!=null){
in.close();
} catch (Exception e2) {
// TODO: handle exception
public StringBuffer sendPostRequest(String url, String ref, UrlEncodedFormEntity entity) {
// TODO Auto-generated method stub
StringBuffer sb=new StringBuffer();
HttpPost httpPost=new HttpPost(url);
InputStream in=
httpPost.setHeader(&Cookie&, mCookie); //设置cookie
if(ref!=null&&!ref.equals(&&)){
httpPost.setHeader(&Referer&,ref);//如果有地址引用则设置
httpPost.setEntity(entity);//设置请求参数
CloseableHttpResponse response=mHttpClient.execute(httpPost);//提交请求
in=response.getEntity().getContent();//获得响应流对象
//获取响应内容
int len=-1;
byte[] data=new byte[1024];
while((len=in.read(data))!=-1){
String s=new String(data,0,len,Constant.ENCODING);
sb.append(s);
} catch (Exception e) {
// TODO: handle exception
if(in!=null){
in.close();
} catch (Exception e2) {
// TODO: handle exception
public byte[] getCheckImg() {
// TODO Auto-generated method stub
String url=Constant.CHECK_IMAGE_URL;
HttpGet httpGet=new HttpGet(url);
byte[] imgByte=
CloseableHttpResponse response=mHttpClient.execute(httpGet);
imgByte=EntityUtils.toByteArray(response.getEntity());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return imgB
public boolean login(User user) {
// TODO Auto-generated method stub
//组织登陆请求参数
ArrayList&BasicNameValuePair& params=new ArrayList&BasicNameValuePair&();
params.add(new BasicNameValuePair(&__VIEWSTATE&, mViewState));//__VIEWSTATE,不可缺少这个参数
params.add(new BasicNameValuePair(&txtUserName&, user.getName()));//学号
params.add(new BasicNameValuePair(&TextBox2&, user.getPasswd()));//密码
params.add(new BasicNameValuePair(&txtSecretCode&,user.getCheck()));//验证码
params.add(new BasicNameValuePair(&RadioButtonList1&, Constant.RADIO_BUTTON_LIST));//登陆用户类型
params.add(new BasicNameValuePair(&Button1&, &&));
params.add(new BasicNameValuePair(&lbLanguage&, &&));
params.add(new BasicNameValuePair(&hidPdrs&, &&));
params.add(new BasicNameValuePair(&hidsc&, &&));
UrlEncodedFormEntity entity=new UrlEncodedFormEntity(params,Constant.ENCODING); //封装成参数对象
StringBuffer sb=sendPostRequest(Constant.LOGIN_URL,null, entity);//发送请求
mUser=//记录登陆的用户
String html=sb.toString();
//检测是否有登陆错误的信息,有则记录信息,否则登陆成功
if(html.contains(Constant.CHECK_ERROR)){
mErrorMessege=Constant.CHECK_ERROR;
}else if(html.contains(Constant.CHECK_NULL_ERROR)){
mErrorMessege=Constant.CHECK_NULL_ERROR;
}else if(html.contains(Constant.PASSWD_ERROR)){
mErrorMessege=Constant.PASSWD_ERROR;
//登陆成功,重定向获取主页面
StringBuffer userHtml=sendGetRequest(Constant.STUDENT_URL+user.getName(),null);
saveQueryURL(userHtml.toString()); //根据响应内容找到并保存查询各种信息的URL
//返回登陆成功
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
public CourseTable getCourseTable(String xnd,String xqd) {
// TODO Auto-generated method stub
String url=Constant.BASE_URL+mCourseURL;//查询课表的URL
String referer=Constant.STUDENT_URL+mUser.getName();//引用地址
StringBuffer courseHtml=
CourseTable couresTable=new CourseTable();
//没有学年度和学期的的信息,则发送get请求,否则发送post请求
if(xnd==null||xqd==null){
courseHtml=sendGetRequest(url, referer);
//记录post参数后发送请求
ArrayList&BasicNameValuePair& params=new ArrayList&BasicNameValuePair&();
params.add(new BasicNameValuePair(&__EVENTTARGET&, &xqd&));
params.add(new BasicNameValuePair(&__EVENTARGUMENT&, &&));
params.add(new BasicNameValuePair(&__VIEWSTATE&, mViewState));
params.add(new BasicNameValuePair(&xnd&, xnd));
params.add(new BasicNameValuePair(&xqd&, xqd));
UrlEncodedFormEntity entity=new UrlEncodedFormEntity(params,Constant.ENCODING);
courseHtml=sendPostRequest(url, referer, entity);
String html=courseHtml.toString(); //响应HTML文档
mViewState=HtmlTools.findViewState(html);//记录__VIEWSTATE
StuSimpleInfo stuInfo=HtmlTools.getStuInfo(html);
String[] xnds=HtmlTools.getXnd(html); //在响应内容中获取学年度选项列表
String[] xqds=HtmlTools.getXqd(html); //在响应内容中获取学期选项列表
ArrayList&Course& courses=HtmlTools.getCourseList(html); //在响应内容中获取课表
//如果传进来的学年度和学期参数为空,则使用默认选项
if(xnd==null&&xnds.length&0) xnd=xnds[0];
if(xqd==null&&xqds.length&0) xqd=xqds[0];
//保存获取到的所有信息
couresTable.setXnd(xnds);
couresTable.setXqd(xqds);
couresTable.setCurrXnd(xnd);
couresTable.setCurrXqd(xqd);
couresTable.setCourses(courses);
couresTable.setSimpleInfo(stuInfo);
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return couresT
public String getCourseTableAsJson(String xnd, String xqd) {
// TODO Auto-generated method stub
CourseTable courseTable=getCourseTable(xnd, xqd);
StringBuffer sb=new StringBuffer();
sb.append(&{&);
for(Course c:courseTable.getCourses()){
sb.append(&\n\t{&);
sb.append(&\n\t\t\&name\&:\&&+c.getName()+&\&&);
sb.append(&\n\t\t\&classRoom\&:\&&+c.getClassRoom()+&\&&);
sb.append(&\n\t\t\&teacher\&:\&&+c.getTeacher()+&\&&);
sb.append(&\n\t\t\&classTime\&:\&&+c.getClassTime()+&\&&);
sb.append(&\n\t\t\&weekNum\&:\&&+c.getWeekNum()+&\&&);
sb.append(&\n\t\t\&startWeek\&:\&&+c.getStartWeek()+&\&&);
sb.append(&\n\t\t\&endWeek\&:\&&+c.getEndWeek()+&\&&);
sb.append(&\n\t\t\&weekState\&:\&&+c.getWeekState()+&\&&);
sb.append(&\n\t\t\&number\&:\&&+c.getNumber()+&\&&);
sb.append(&\n\t\t\&day\&:\&&+c.getDay()+&\&&);
sb.append(&\n\t}\n&);
sb.append(&}&);
return sb.toString();
public PersonalInfo getPersonalInfo(String url) {
// TODO Auto-generated method stub
public String getErrorMessege() {
// TODO Auto-generated method stub
return mErrorM
* 查找并保存查询各种信息的URL
* @param html HTML文档
private void saveQueryURL(String html) {
// TODO Auto-generated method stub
String pattern=&&a href=\&(\\w+)\\.aspx\\?xh=(\\d+)&xm=(.+?)&gnmkdm=N(\\d+)\& target='zhuti' onclick=\&GetMc\\('(.+?)'\\);\&&(.+?)&/a&&;
Pattern p=Pattern.compile(pattern);
Matcher m=p.matcher(html);
while(m.find()){
String res=m.group();
String url=res.substring(res.indexOf(&href=\&&)+6);
url=url.substring(0,url.indexOf(&\&&));
if(res.contains(&学生个人课表&)){
mCourseURL=
if(res.contains(&成绩查询&)){
mScorceURL=
if(res.contains(&个人信息&)){
mPersonalInfoURL=
public User getmUser() {
& & & & 上面的HttpService里用到一个HtmlTools类,这个类里包含了一些了的静态方法,是专门用来解析响应页面的HTML里面的信息的,代码如下
import java.util.ArrayL
import java.util.regex.M
import java.util.regex.P
import com.jluzh.jw.bean.C
import com.jluzh.jw.bean.StuSimpleI
import com.jluzh.jw.factor.BeanF
* HTML工具类,主要用于提取HTML文档中的信息
* @author EsauLu
public class HtmlTools {
private static final int FIND_XND=1;//学年度
private static final int FIND_XQD=2;//学期
* 查找__VIEWSTATE参数的值
* @param html HTML文档
* @return 返回
public static String findViewState(String html) {
String res=&&;
String pattern=&&input type=\&hidden\& name=\&__VIEWSTATE\& value=\&(.*?)\& /&&;
Pattern p=Pattern.compile(pattern);
Matcher m=p.matcher(html);
if(m.find()){
res=m.group();
res=res.substring(res.indexOf(&value=\&&)+7,res.lastIndexOf(&\&&));
* 查找课表部分的HTML字符串
* @param html HTML文档
* @return 课表的HTML串
private static String findCourseTableHtml(String html){
String res=&&;
String tar=&&table id=\&Table1\& class=\&blacktab\& bordercolor=\&Black\& border=\&0\& width=\&100%\&&&;
String pattern=&&table id=\&Table1\& class=\&blacktab\& bordercolor=\&Black\& border=\&0\& width=\&100%\&&([\\S\\s]+?)&/table&&;
Pattern p=Pattern.compile(pattern);
Matcher m=p.matcher(html);
if(m.find()){
res=m.group(0);
res=res.substring(res.indexOf(tar)+tar.length(),res.lastIndexOf(&&/table&&)).trim();
System.out.println(html);
System.out.println(&什么都没有&);
* 在HTML中提取学年度或者学期的选项的HTML记录串
* @param html HTML文档
* @param x 代表学期或者学年度的参数
返回HTML表示的学年度或者学期选项
private static String findXndOrXqdHtml(String html,int x){
String res=&&;
String pattern=
switch(x){
case FIND_XND:
pattern=&&select name=\&xnd\& onchange=\&__doPostBack\\('xnd',''\\)\& language=\&javascript\& id=\&xnd\&&([\\s\\S]+?)&/select&&;
case FIND_XQD:
pattern=&&select name=\&xqd\& onchange=\&__doPostBack\\('xqd',''\\)\& language=\&javascript\& id=\&xqd\&&([\\s\\S]+?)&/select&&;
Pattern p=Pattern.compile(pattern);
Matcher m=p.matcher(html);
if(m.find()){
res=m.group(1);
return res.trim();
* 在HTML中提取学年度或者学期的选项列表
* @param html HTML文档
* @param x 代表学年度或者学期
* @return 返回学年度或者学期的选项数组
private static String[] getOptions(String html,int x){
String[] ops=
String res=&&;
String tar=findXndOrXqdHtml(html, x);
ArrayList&String& arr=new ArrayList&String&();
String pattern=&&option([\\s\\S]*?)&(.*?)&/option&&;
Pattern p=Pattern.compile(pattern);
Matcher m=p.matcher(tar);
while(m.find()){
res=m.group(2);
arr.add(res);
ops=new String[arr.size()];
for(int i=0;i&ops.i++){
ops[i]=arr.get(i);
* 获取学年度选项
* @param html HTML文档
* @return 返回学年度选项数组
public static String[] getXnd(String html){
return getOptions(html, FIND_XND);
* 获取学期选项数组
* @param html HTML文档
* @return 学期选项数组
public static String[] getXqd(String html){
return getOptions(html, FIND_XQD);
* 获取学生简要信息
* @param html HTML文档
* @return 返回学生简要信息数组
public static StuSimpleInfo getStuInfo(String html){
String[] info=
//(&span id=&([\\s\\S]+?)&&([\\s\\S]+?)&/span&\\|)?&span id=&(.+)&&(.+?)&/span&
String res=&&;
String pattern=&&TR class=\&trbg1\&&&
+ &([\\s\\S]*?)&TD&([\\s\\S]*?)&
+ &&span id=\&Labe(.+?)\&&([\\s\\S]+?)&/span&(\\|([\\s\\S]*?)&span id=\&Labe(.+?)\&&([\\s\\S]+?)&/span&)*&;
Pattern p=Pattern.compile(pattern);
Matcher m=p.matcher(html);
if(m.find()){
res=m.group(0);
info=res.split(&\\|&);
pattern=&&span id=\&Labe(.+?)\&&([\\s\\S]+?):([\\s\\S]+?)&/span&&;
p=Pattern.compile(pattern);
for(int i=0;i&info.i++){
m=p.matcher(info[i]);
if(m.find()){
info[i]=m.group(3);
info[i]=&&;
return BeanFactor.createStuSimpleInfo(info);
* 在HTML文档中提取课表
* @param html HTML文档
* @return 返回课表
public static ArrayList&Course& getCourseList(String html){
String courseTableHtml=findCourseTableHtml(html);//找到课表部分的HTML
ArrayList&Course& courses=new ArrayList&Course&();
String[] rows=courseTableHtml.split(&&/tr&&tr&&);//按上课时间分隔HTML
for(int i=2;i&rows.i+=2){
String r=rows[i];
String[] cols=r.split(&&/td&&td([\\S\\s]*?)&&);//按星期几分隔HTML
if(i==2||i==6||i==10){
for(;j&cols.x++,j++){
String c=cols[j];
String[] info=c.split(&&br&&);
if(info[0].contains(&&&))
String[] tem=new String[4];
for(int k=0;k&info.k++){
String item=info[k].trim();
if(item.equals(&&)){
//处理同一时间不同周数的课程
tem=new String[4];
Course course=BeanFactor.createCourse(tem, i-1, x);
courses.add(course);
& & & 然后还有一些封装类的代码就不贴上来了,后面有完整代码的链接
& & & & 上面的HttpService类已经为实现了访问教务网的所有操作,利用这个HttpService,我们就能得到课程表的信息,然后就可以写一个界面将这些课程信息展示出来,我自己写了一个简单的界面,并放到了GitHub上,有兴趣的读者可以去看一下,地址是。
& & & & 另外,我还依照这些思路写了一个安卓的课表APP,由于安卓的一些特性,写这个APP时并没有采用HttpClient这个包而是用了另一个包OkHttpClient,这个课表APP的源码地址:
访问:4860次
排名:千里之外
原创:10篇他的最新文章
他的热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)如何写一个java程序,获取usb设备使用信息,将名称,使用时间等等信息显示出来,如下是需要实现的截图。_百度知道
如何写一个java程序,获取usb设备使用信息,将名称,使用时间等等信息显示出来,如下是需要实现的截图。
我有更好的答案
关注一下。
可以看看libUsb这个库,然后通过jni调用
为您推荐:
其他类似问题
您可能关注的内容
java程序的相关知识
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。如何写一个用java程序抓取省地区和对应的编码_百度知道
如何写一个用java程序抓取省地区和对应的编码
我有更好的答案
mport java.util.
InetAddress ia = InetApublic class getMyIP{
public static void main(String[] args){
String IP =
String host = null.getHostName().getLocalHost();
host =//获取计算机名字
IP=/获取IP
catch(UnknownHostException e)
e.printStackTrace();
System.getHostAddress();&#47.println(host).*.import java.*
为您推荐:
其他类似问题
java程序的相关知识
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。}

我要回帖

更多关于 java实现爬虫抓取数据 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信