PS:恩,由于最近在学web和简单的http协议,所以心血来潮想用java写个爬虫来爬取学校官网(正方教务系统)个人主页的基础信息(课程信息、成绩……),其实在之前学过java基础教程的时候就可以写的,但后知后觉总是在当前阶段做之前阶段应该完成的任务!或许这就是菜鸟吧~~~。
写在前面:其实写java爬虫的话,一般使用三种方法:自带库类(urlconnection),外库(httpclient)和文档解析库(jsoup);其中jsoup这个第三方库重点用于对html文档的解析,在官方文档中除了Jsoup.connect()方法进行访问网页外并没有多余的方法,而且在访问网页是需要登录的网站爬虫中(get和post方法访问),大多使用前两种方法。又由于httpclient相对于自带库更加灵活高效,所以在该爬虫中使用httpclient访问+Jsoup解析文档结合操作。
注意:作为一个小白,在尝试每一个别人已经实现的而自己未曾实现的项目时,都会有或多或少的问题,而这个爬虫项目对于我来说也是如此,所以才会写下这篇博文作为填坑的记录,也方便别的刚入门的小白能够顺利完成。如果正在阅读的你也是一个刚入门的小白想用java写一个爬取学校官网的爬虫(大神勿喷请绕道~~~),那就很幸运了,只要你按照以下文章内容循序渐进,那一定会得到你想要的结果。(当然,在我接下来描述的项目中,是以正方教务系统来实现的,如果你的学校官网是其他的,其实掌握核心技术,也是大同小异)
注意:这几个jar包是必不可少的,可能会有人疑惑:不是只要httpclient包就好了嘛,怎么还要其他两个包。其实你只要知道这三个包的版本都是很老的,Apache已经不再维护更新,而且这三个包是相互依赖的,必不可缺。(由于我一开始下载的就是3.1版本,不想再改4.X的,因为里面的一些方法函数的使用是不一样的。下载的话我已经都分享到csdn中,可以进行下载:httpclient-jar包下载),导入eclipse中的话就不用细说了,结果如下图。
【注】爬虫是什么,就不需要赘述了,如果是通过url爬取没有权限的网页是很简单的,直接用Jsoup就可以完成。但是当我们在爬取一些需要登录的网站时,我们如果还是直接访问该url的话会重新返回到登录首页,所以我们就要进行模拟登录,至于什么是模拟登录,就是将账号密码验证码post给网站的服务器,通过记住其cookie来访问登录后的其他页面(其实这是先行知识,之所以要提一嘴,是因为我在开始的时候也是一头雾水状态)。
其中红框内就是请求数据界面的地址。
在用代码进行登录网站时,是需要将这些表单数据作为参数提交的,但是虽然有很多参数,但是真正需要的参数只需要其中标记的四个参数:
所以每一次提交信息的时候就需要get该网页获取验证码,因为对于验证码的自动识别比较麻烦,所以在这个项目中时将验证码获取下载到本地,再人工手动输入该验证码,进行登录。
【高能:关于验证码的自动识别,我在下一篇博文中会做出详细解释】
package com.yxs.Link;
import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.methods.*;
import org.apache.commons.httpclient.cookie.*;
import java.util.*;
import org.jsoup.*;
import org.jsoup.nodes.*;
import org.jsoup.select.*;
import java.io.*;
/**
*Tile:LoginTest.java
*
Description:获取cookie和验证码模拟登录教务系统
* @author YXS
* @data2018年6月3日
*/
public class LoginTMSystem {
public static String getHTML() {
String cookie1 = "";
String html = "null";
String txtSecretCode = "";
System.out.println("请输入学号:");
String txtUserName = new Scanner(System.in).next().trim();
System.out.println("请输入密码:");
String TextBox2 = new Scanner(System.in).next().trim();
String RadioButtonList1 = "";
String __VIEWSTATE = "";
//登录url
String loginURL = "http://jwxt.hfnu.edu.cn/(arezfqaeu12awkft0yuoe1qg)/default2.aspx";
//教务管理系统首页url
String indexURL = "http://jwxt.hfnu.edu.cn/(arezfqaeu12awkft0yuoe1qg)/xs_main.aspx";
//登录后访问的课程表url
String dataURL = "http://jwxt.hfnu.edu.cn/(arezfqaeu12awkft0yuoe1qg)/xskbcx.aspx";
//验证码下载网址
String checkCodeURL = "http://jwxt.hfnu.edu.cn/(arezfqaeu12awkft0yuoe1qg)/CheckCode.aspx";
//创建浏览器对象
HttpClient httpClient = new HttpClient();
//先访问验证码页面,获取验证码
GetMethod getMethod1 = new GetMethod(checkCodeURL);
try {
//设置HttpClient接收Cookie
httpClient.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);
httpClient.executeMethod(getMethod1);
//获取访问后的Cookie
Cookie[] cookies1 = httpClient.getState().getCookies();
StringBuffer tmpcookies1 = new StringBuffer();
for(Cookie c1 : cookies1) {
tmpcookies1.append(c1.toString()+";");
System.out.println("访问页面cookies : "+c1.toString());
cookie1 = tmpcookies1.toString();
//cookie1 = c1.toString();
}
//验证码保存路径
File storeFile = new File("D:\\java爬虫jar包\\verifycode\\vc.gif");
InputStream is = getMethod1.getResponseBodyAsStream();
FileOutputStream fos = new FileOutputStream(storeFile);
byte[] b = new byte[1024];
int n;
while((n = is.read(b)) != -1) {
fos.write(b,0,n);
}
is.close();
fos.close();
//该处代码是用于验证码自动识别
txtSecretCode = ImagePreProcess.getAllOrc("D:\\java爬虫jar包\\verifycode\\vc.gif");
}catch(Exception e) {
e.printStackTrace();
}
//System.out.println("请输入验证码:");
//String txtSecretCode = new Scanner(System.in).next().trim();
System.out.println(txtSecretCode);
System.out.println("测试使用cookie1:"+cookie1);
//模拟登录,按实际服务器端要求选用Post 或 Get请求方式
PostMethod postMethod = new PostMethod(loginURL);
//设置相同的cookie
postMethod.setRequestHeader("cookie",cookie1);
//设置登录时需要的信息,用户名和密码
NameValuePair[] data = {
new NameValuePair("__VIEWSTATE",__VIEWSTATE),
new NameValuePair("Button1",""),
new NameValuePair("hidPdrs",""),
new NameValuePair("hidsc",""),
new NameValuePair("lbLanguage",""),
new NameValuePair("RadioButtonList1",RadioButtonList1),
new NameValuePair("TextBox2",TextBox2),
new NameValuePair("txtSecretCode",txtSecretCode),
new NameValuePair("txtUserName",txtUserName)
};
postMethod.setRequestBody(data);
try {
int statusCode = httpClient.executeMethod(postMethod);
//html = postMethod.getResponseBodyAsString();
System.out.println(statusCode);
//重定向
if(statusCode == 302) {
System.out.println("模拟登录成功!");
//设置HttpClient接收Cookie,用与浏览器一样的策略
httpClient.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);
//获取登录后的Cookie
Cookie[] cookies = httpClient.getState().getCookies();
StringBuffer tmpcookies = new StringBuffer();
for(Cookie c : cookies) {
tmpcookies.append(c.toString()+";");
System.out.println("登录页面cookies : "+c.toString());
}
//System.out.println("-------------------------------InformationFrame------------------------------");
//进行登录后的操作
//访问主页面
GetMethod getMethod2 = new GetMethod(indexURL+"?xh="+txtUserName);
//每次访问需授权的网址时带上前面的cookie作为通行证
getMethod2.setRequestHeader("cookie",tmpcookies.toString());
httpClient.executeMethod(getMethod2);
//访问课程表页面
GetMethod getMethod3 = new GetMethod(dataURL+"?xh="+txtUserName+"&xm=&gnmkdm=");
//每次访问需授权的网址时带上前面的cookie作为通行证
getMethod3.setRequestHeader("referer",indexURL+"?xh="+txtUserName);
getMethod3.setRequestHeader("cookie",tmpcookies.toString());
httpClient.executeMethod(getMethod3);
html = getMethod3.getResponseBodyAsString();
/*//访问主页面
GetMethod getMethod = new GetMethod(indexURL+"?xh="+txtUserName);
//每次访问需授权的网址时带上前面的cookie作为通行证
getMethod.setRequestHeader("cookie",tmpcookies.toString());
httpClient.executeMethod(getMethod);
html = getMethod.getResponseBodyAsString();*/
}else {
System.out.println("登录失败");
}
}catch(Exception e) {
e.printStackTrace();
}
return html;
}
public static void main(String[] args) {
Document doc = Jsoup.parse(LoginTMSystem.getHTML());
//System.out.println(doc);
/*Element link1 = doc.select("span#Label3").first();
String text1 = link1.text();
Element link2 = doc.select("span#xhxm").first();
String text2 = link2.text();
System.out.println(text1+text2);*/
Elements link1 = doc.select("span#Label5");
Elements link2 = doc.select("span#Label6");
Elements link3 = doc.select("span#Label7");
Elements link4 = doc.select("span#Label8");
Elements link5 = doc.select("span#Label9");
String text1 = link1.text();
String text2 = link2.text();
String text3 = link3.text();
String text4 = link4.text();
String text5 = link5.text();
System.out.println("-------------------------------个人信息------------------------------");
System.out.println(text1);
System.out.println(text2);
System.out.println(text3);
System.out.println(text4);
System.out.println(text5);
System.out.println("-------------------------------课程信息------------------------------");
Elements tds1 = doc.select("td[rowspan=2]");
for(int i=0;i
当你在浏览网站的时候,WEB 服务器会先送一些资料放在你的计算机上,Cookie会帮你在网站上所打的文字或是一些选择,都记录下来。当下次你再光临同一个网站,WEB 服务器会先看看有没有它上次留下的 Cookie 资料,有的话,就会依据Cookie里的内容来判断使用者,送出特定的网页内容给你。 Cookie 的使用很普遍,许多有提供个人化服务的网站,都是利用Cookie来辨认使用者,以方便送出使用者量身定做的内容,像是 Web 接口的免费 email 网站,都要用到 Cookie。
具体来说cookie机制采用的是在客户端保持状态的方案,而session机制采用的是在服务器端保持状态的方案。
同时我们也看到,由于采用服务器端保持状态的方案在客户端也需要保存一个标识,所以session机制可能需要借助于cookie机制来达到保存标识的目的,但实际上它还有其他选择。
cookie机制。正统的cookie分发是通过扩展HTTP协议来实现的,服务器通过在HTTP的响应头中加上一行特殊的指示以提示浏览器按照指示生成相应的cookie。然而纯粹的客户端脚本如JavaScript或者VBScript也可以生成cookie。而cookie的使用是由浏览器按照一定的原则在后台自动发送给服务器的。浏览器检查所有存储的cookie,如果某个cookie所声明的作用范围大于等于将要请求的资源所在的位置,则把该cookie附在请求资源的HTTP请求头上发送给服务器。
cookie的内容主要包括:名字,值,过期时间,路径和域。路径与域一起构成cookie的作用范围。若不设置过期时间,则表示这个cookie的生命期为浏览器会话期间,关闭浏览器窗口,cookie就消失。这种生命期为浏览器会话期的cookie被称为会话cookie。会话cookie一般不存储在硬盘上而是保存在内存里,当然这种行为并不是规范规定的。若设置了过期时间,浏览器就会把cookie保存到硬盘上,关闭后再次打开浏览器,这些cookie仍然有效直到超过设定的过期时间。存储在硬盘上的cookie可以在不同的浏览器进程间共享,比如两个IE窗口。而对于保存在内存里的cookie,不同的浏览器有不同的处理方式
session机制。session机制是一种服务器端的机制,服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存信息。当程序需要为某个客户端的请求创建一个session时,服务器首先检查这个客户端的请求里是否已包含了一个session标识(称为sessionid),如果已包含则说明以前已经为此客户端创建过session,服务器就按照sessionid把这个session检索出来使用(检索不到,会新建一个),如果客户端请求不包含sessionid,则为此客户端创建一个session并且生成一个与此session相关联的session id,sessionid的值应该是一个既不会重复,又不容易被找到规律以仿造的字符串,这个session id将被在本次响应中返回给客户端保存。保存这个sessionid的方式可以采用cookie,这样在交互过程中浏览器可以自动的按照规则把这个标识发送给服务器。一般这个cookie的名字都是类似于SEEESIONID。但cookie可以被人为的禁止,则必须有其他机制以便在cookie被禁止时仍然能够把sessionid传递回服务器。
经常被使用的一种技术叫做URL重写,就是把sessionid直接附加在URL路径的后面。还有一种技术叫做表单隐藏字段。就是服务器会自动修改表单,添加一个隐藏字段,以便在表单提交时能够把sessionid传递回服务器。比如:
实际上这种技术可以简单的用对action应用URL重写来代替。
cookie 和session 的区别:
1、cookie数据存放在客户的浏览器上,session数据放在服务器上。
2、cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE操作,考虑到安全应当使用session。
3、session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用COOKIE。
4、单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。
【坑1】
【坑2】