最近打算做一个课表的APP,准备爬取湖北工业大学的课表,因为学校教务系统是http协议的,所以就先拿学校练手了。废话不多说,开工。
首先项目中请添加网络权限,要使用http网络也需要进行单独设置,这部分就不占用版面了,但是灰常重要。
打开教务系统,我这里是火狐浏览器,按下F12捕获,登陆后,可以看到登录的POST操作里包含账号密码和验证码。
要登陆成功我们首先要搞懂cookie的用途,简单的理解(可能不准确),cookie可以比喻成服务器放在你那里准考证,每次你要考试(登录)的时候,发给你一套试卷(验证码),试卷号绑定你的准考证,你做完这套卷子后填好你的信息后上交给老师(服务器),老师检查后确定你做的是自己的试卷(发的验证码和交的一样),信息也是正确的,就准许你毕业(登陆成功)。
所以在操作前我们要先做cookie的管理,我们这里可以使用自带CookieManager,在工具类的构造函数里,新建CookieManager并将其设置为接受所有的cookie。
public class Login_download {
Context context;
Login_download(Context context) {
this.context = context;
CookieManager cookieManager = new CookieManager();
CookieHandler.setDefault(cookieManager);
//接受所有cookie
cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
}
}
再次回到登陆界面,这时候我们要查找登录界面中获取到验证码的操作。验证码一般是图片,所以我们只需要重点寻找类型是图片的。
在响应中可以看到这是验证码,这里只需要我们记录请求网址和方法是“GET”就好
然后是代码部分和使用方法,获取到输入流后就可以直接用BitmapFactory将流中的图片转换为Bitmap。图片可以显示到主页面也可以保存到本地。
public Bitmap getimage(final String line) {
try {
URL url = new URL(line);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//设置为GET
conn.setRequestMethod("GET");
//超时为6000ms
conn.setConnectTimeout(6000);
InputStream inStream = conn.getInputStream();
conn.connect();
bitmap = BitmapFactory.decodeStream(inStream);
} catch (SocketTimeoutException e3){
Log.e("LoginActivity", e3.toString());
return null;
} catch (Exception e) {
Log.e("LoginActivity", e.toString());
return null;
}
return bitmap;
}
使用:
private Login_download dct=null;
private Bitmap bitmap2=null;//在前面定义的全局变量
private void DoGetVerifation(String url_s) {
dct = new Login_download(login.this);
//网络访问这类费时操作不能放到主线程中
new Thread(new Runnable() {
@Override
public void run() {
if (url_s != null) {
这里的bitmap就是我们要的验证码
bitmap2 = dct.getimage(url_s);
if (bitmap2 == null) {
Looper.prepare();
Toast.makeText(login.this, "无法连接到教务系统", Toast.LENGTH_SHORT).show();
Looper.loop();
}
}else{
Message msg = new Message();
changeimage.sendMessage(msg);
//将验证码显示到主界面
}
}
}).start();
}
通过第一步我们已经知道了post里面需要的信息,这里我们找到post对用的网址,进行登录废话少说,放代码。
//po是post的网址,post_words是post的信息,Stringmood是字符的编码(工地英语)
public String postinf(final String po, final String post_words,final String stringmood) {
StringBuilder buffer = new StringBuilder();
if(po.contains("https")){
//https网址的处理,后期会再写一篇博客说这个
}else {
HttpURLConnection connection = null;
try {
URL url = new URL(po);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
//允许输入输出
connection.setDoOutput(true);
connection.setDoInput(true);
//不使用缓存和重定向设置
connection.setUseCaches(false);
connection.setFollowRedirects(true);
//设置消息头,如果登陆失败可以根据学校网站添加修改
connection.setRequestProperty("Connection", "keep-alive");
connection.connect();
} catch (IOException e) {
e.printStackTrace();
}
assert connection != null;
try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(connection.getOutputStream()))) {
//写入登录信息
writer.write(post_words);
writer.flush();
} catch (IOException e1) {
e1.printStackTrace();
}
try {
//如果返回值为200
int responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
InputStream inputStream = connection.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, stringmood);
BufferedReader ddd;
String line;
ddd = new BufferedReader(inputStreamReader);
while ((line = ddd.readLine()) != null) {
buffer.append(line);
}
//返回相应数据
return buffer.toString();
}
} catch (IOException e1) {
e1.printStackTrace();
}
}
//否则返回null
return null;
}
使用:
private void nlogin() {
Minf="开始登陆";
Message msgg = new Message();
setMinf.sendMessage(msgg);
handler.postDelayed(refrush, 100);
new Thread(new Runnable() {
@Override
public void run() {
//这里的sc用来储存网址和拼接登录信息
//POST拼接的数据大概长这个样子,大家可以根据自己学校进行更改
//String body01 = "isRemember=1";
//String body02 = "Role=Student";
//String body03 = "UserName=" + user;
//String body04 = "Password=" + password;
//String body05 = "ValidateCode=" + verifation;
//body = body01 + "&" + body02 + "&" + body03 + "&" + body04 + "&" + body05;
String a=dct.postinf(sc.get_class_login_URL(),sc.log_body(dct,username.getText().toString(),password.getText().toString(),pwdin.getText().toString()),sc.get_class_login_code());
//打印post操作的返回数据
System.out.println(a);
//登陆成功后获取课程表
//String myclass = dct.getinf(sc.get_class_URL(), sc.get_class_code());
//解析课程表部分省略
//Document doc = Jsoup.parse(myclass);
//Elements title=doc.getElementsByAttributeValue("align","center");
//解析课程表部分省略
}
}
}).start();
}
同样的,F12,然后在火狐里查看自己的课表,找到获取课表的那一项,记下网址,操作是GET,部分学校可能是post操作
代码代码:
public String getinf(final String po,final String stringmood) {
StringBuilder getbuffer = new StringBuilder();
if(po.contains("https")){
//https省略,下篇文章再讲一下爬取方正教务的
}else {
HttpURLConnection connection = null;
try {
URL url = new URL(po);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
//get不需要输入
connection.setDoOutput(false);
connection.setDoInput(true);
connection.setUseCaches(false);
connection.setRequestProperty("Connection", "keep-alive");
connection.connect();
} catch (IOException e) {
e.printStackTrace();
}
try {
int responseCode = connection.getResponseCode();
System.out.println(responseCode);
if (responseCode == HttpURLConnection.HTTP_OK) {
InputStream inputStream = connection.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, stringmood);
BufferedReader ddd;
String line;
ddd = new BufferedReader(inputStreamReader);
while ((line = ddd.readLine()) != null) {
getbuffer.append(line);
}
return getbuffer.toString();
}
} catch (IOException e1) {
e1.printStackTrace();
}
}
return null;
}
使用方法在上面的POST部分有,已经被注释了,这里不再展示。
总的爬取过程其实不太复杂,有耐心找对网址,把需要的信息都找对其实很简单就可以实现爬取。