网页抓取数据(就是上文中的验证码地址()数据解析)

优采云 发布时间: 2022-01-31 16:25

  网页抓取数据(就是上文中的验证码地址()数据解析)

  VERIFATIONURL就是上面的验证码地址。首先创建一个post请求,然后创建一个Httpclient,然后HttpResponse就是响应。我们得到的服务器的返回值是通过他得到的,我们创建一个字节数组。首先将响应中得到的数据转换成字节数组,然后通过BitmapFactory.decodeByteArray(bytes, 0, bytes.length);将字节数组编译成位图;方法。这时候我们拿到验证码的Bitmap,直接ImageView.SetBitmap可以吗?当然不是。首先,我们在网页上获取图片是一个耗时的操作,所以我们不能在主线程中进行,第二点是我们只能在主线程中更新UI。我们使用 Thread+Handler 解决方案。以上代码:

  private void DoGetVerifation() {

new Thread(new Runnable() {

@Override

public void run() {

HttpPost httPost = new HttpPost(VERIFATIONURL);

HttpClient client = new DefaultHttpClient();

try {

HttpResponse httpResponse = client.execute(httPost);

byte[] bytes = new byte[1024];

bytes = EntityUtils.toByteArray(httpResponse.getEntity());

bmVerifation = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);

} catch (IOException e) {

e.printStackTrace();

}

Message msg = new Message();

msg.arg1 = 10;

handler.sendMessage(msg);

}

}).start();

}

  在主线程接收到msg后,ivVerifation.setImageBitmap(bmVerifation); 所以我们得到验证码的图片并显示在主界面上

  2.发送 Post 请求登录

  我们现在知道用户名、密码。验证码,下一步就是登录了,登录是一个耗时的操作。当然,必须启动一个新线程。这个没什么好说的,我们也是在发送一个Post请求,上面的代码:

  private void DoLogin(final String user, final String password, final String verifation) {

new Thread(new Runnable() {

@Override

public void run() {

DefaultHttpClient defaultclient = new DefaultHttpClient();

HttpPost httpPost = new HttpPost(LOGINURL);

HttpResponse httpResponse;

//设置post參数

List params = new ArrayList();

params.add(new BasicNameValuePair("__VIEWSTATE", "dDwyODE2NTM0OTg7Oz6ZmvWn7xzjizifHN9MgLoDNTRtjQ=="));

params.add(new BasicNameValuePair("Button1", ""));

params.add(new BasicNameValuePair("hidPdrs", ""));

params.add(new BasicNameValuePair("hidsc", ""));

params.add(new BasicNameValuePair("lbLanguage", ""));

params.add(new BasicNameValuePair("RadioButtonList1", "%D1%A7%C9%FA"));

params.add(new BasicNameValuePair("TextBox2", password));

params.add(new BasicNameValuePair("txtSecretCode", verifation));

params.add(new BasicNameValuePair("txtUserName", user));

//获得个人主界面的HTML

try {

httpPost.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));

httpResponse = defaultclient.execute(httpPost);

Log.i("xyz", String.valueOf(httpResponse.getStatusLine().getStatusCode()));

if (httpResponse.getStatusLine().getStatusCode() == 200) {

StringBuffer sb = new StringBuffer();

HttpEntity entity = httpResponse.getEntity();

MAINBODYHTML = EntityUtils.toString(entity);

IsLoginSuccessful(MAINBODYHTML);

}

} catch (UnsupportedEncodingException e) {

e.printStackTrace();

} catch (ClientProtocolException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}

}

}).start();

}

  首先是创建post,客户端响应,和上一个一样。我们收到了对数据的 Post 请求。比如获取验证码的请求不需要参数,但是我们需要将验证码发送到服务器用户名密码进行登录,所以我们请求的是Post。设置参数

   //设置post參数

List params = new ArrayList();

params.add(new BasicNameValuePair("__VIEWSTATE", "dDwyODE2NTM0OTg7Oz6ZmvWn7xzjizifHN9MgLoDNTRtjQ=="));

params.add(new BasicNameValuePair("Button1", ""));

params.add(new BasicNameValuePair("hidPdrs", ""));

params.add(new BasicNameValuePair("hidsc", ""));

params.add(new BasicNameValuePair("lbLanguage", ""));

params.add(new BasicNameValuePair("RadioButtonList1", "%D1%A7%C9%FA"));

params.add(new BasicNameValuePair("TextBox2", password));

params.add(new BasicNameValuePair("txtSecretCode", verifation));

params.add(new BasicNameValuePair("txtUserName", user));

//获得个人主界面的HTML

try {

httpPost.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));

httpResponse = defaultclient.execute(httpPost);

Log.i("xyz", String.valueOf(httpResponse.getStatusLine().getStatusCode()));

if (httpResponse.getStatusLine().getStatusCode() == 200) {

StringBuffer sb = new StringBuffer();

HttpEntity entity = httpResponse.getEntity();

MAINBODYHTML = EntityUtils.toString(entity);

IsLoginSuccessful(MAINBODYHTML);

}

} catch (UnsupportedEncodingException e) {

e.printStackTrace();

} catch (ClientProtocolException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}

  这些参数就是我们之前使用HttpWatch获取的Post数据。只有带类型的参数,没有值。我们将它们设置为 "" 为空,并使用 httpPost.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8)); 方法来设置我们的 set param 参数集给 httppost。以下与之前,也是通过Response获取response值,但是不是图片而是吃瓜果的String=-=。函数IsLoginSuccessful是用来推断我们是否登录成功的。。这会用到我们将要进行的数据分析下面说说。

  四、数据分析

  1.返回的响应?

  登录后,我们会得到服务器给我们的响应。我们成功登录了火狐的Firebug的模型(HttpWatch也可以个人觉得看响应值Firebug比较方便)。让我们看看他会给我们带来什么

  如图所示,我们可以知道响应值其实就是我们网页的HTML。假设登录成功,其实是返回个人主页

  

  那么假设失败呢?我们模拟一个验证码错误,如下图。可见同样返回一个 HTML

  

  我们注意到这条线

  alert('验证码不对!。');document.getElementById('TextBox2').focus();

  这实际上会弹出一个表单,告诉我们验证码是错误的。下面我们将使用里面的不同提示来推断我们登录的状态

  2.使用Jsoup进行数据解析

  我们创建前面提到的 IsLoginSuccessful 函数

   private void IsLoginSuccessful(String loginresult) {

Document doc = Jsoup.parse(loginresult);

Elements alert = doc.select("script[language]");

Elements success = doc.select("a[href]");

Message msg = new Message();

//先推断是否登录成功。若成功直接退出

for (Element link : success) {

//获取所要查询的URL,这里相应地址button的名字叫成绩查询

if (link.text().equals("*敏*感*词*查询")) {

Log.i("xyz", "登录成功");

msg.arg1 = 6;

handler.sendMessage(msg);

return;

}

}

for (Element link : alert) {

//刷新验证码

DoGetVerifation();

//获取错误信息

if (link.data().contains("验证码不对")) {

Log.i("xyz", "验证码错误");

msg.arg1 = 0;

handler.sendMessage(msg);

} else if (link.data().contains("username不能为空")) {

Log.i("xyz", "username不能为空");

msg.arg1 = 1;

handler.sendMessage(msg);

} else if (link.data().contains("password错误")) {

Log.i("xyz", "password或username错误");

msg.arg1 = 2;

handler.sendMessage(msg);

} else if (link.data().contains("password不能为空")) {

Log.i("xyz", "password不能为空");

msg.arg1 = 3;

handler.sendMessage(msg);

......

}

}

  我正在使用开源库 Jsoup 进行解析。当然,有很多方法可以做到这一点。你可以自己google一下(百度=-=你这个老躺*敏*感*词*)

  你可以看看Jsoup的中文API指南

  首先,我们推断登录成功。我们在成功登录的 HTML 中发现了以下语句。

  

*敏*感*词*查询

  我们通过Elements success = doc.select("a[href]"); 获取以a href" 开头的数据,然后循环推断是否有等级测试查询,假设存在。必须返回的响应是我们的个人主页。也就是说登录成功了,我们在主线程toast中使用Thread+Handler来提醒用户

  然后我们通过Elements alert = doc.select("script[language]"); 得到脚本开头的语句,同样的循环推理,这里需要注意的是它和a href 不同。我们使用的是link.data(),前一个是link.text();

  JsoupAPI 是这样写的

  五、访问个人信息

  我们登录了个人主页,想进一步了解自己,比如四年级和六年级,该怎么办?相同或获取请求

  

  获取验证码网址的方法相同。我们得到了成绩单的网址

  xh=2014117170&xm=">(dlxrmg55j21wlaqv2z5rcdyi)/xsdjkscx.aspx?xh=2014117170&xm=邹德宏&gnmkdm=N121606

  前面的(dlxrmg55j21wlaqv2z5rcdyi)/是我们访问的主机不变。我们所要做的就是获取 xsdjkscx.aspx?

  xh=2014117170&xm=邹德宏&gnmkdm=N121606. 这个问题困扰我很久了。后来突然发现,万智居然是在前面提到的登'lu'cheng'登录成功后返回的html中。所以还是用Jsoup来分析

   Document doc = Jsoup.parse(MAINBODYHTML);

Elements links = doc.select("a[href]");

StringBuffer sb = new StringBuffer();

for (Element link : links) {

//获取所要查询的URL,这里相应地址button的名字叫成绩查询

if (link.text().equals("*敏*感*词*查询")) {

sb.append(link.attr("href"));

}

}

GETSCOREURL = sb.toString();

  GETSCOREURL 是我们想要的地址的后半部分,然后我们添加前半部分来获取 Post 请求。

  这里返回的是一个 Html 表

  

学年学期*敏*感*词*名称准考证号考试日期成绩听力成绩阅读成绩写作成绩综合成绩

2014-20152CET4610041151112625201506483167

1731430

2015-20161CET6610041152209503201512376126

1431070

  同样使用 Jsoup

   private void parse(String parse) {

Document doc = Jsoup.parse(parse);

Elements trs = doc.select("table").select("tr");

for (int i = 0; i < trs.size(); i++) {

Elements tds = trs.get(i).select("td");

for (int j = 0; j < tds.size(); j++) {

String text = tds.get(j).text();

score[i][j] = text;

Log.i("xyz", score[i][j]);

}

}

}

  解析后,我们得到一个分数数组

  六、总结

  博主高二党学习Android开发一年半了,现在终于有了上手的感觉。本教程对于新手来说会有些困难。不过你要保持冷静,博主第一次下载HttpWatch的时候愣了一下。什么都不懂,慢慢摸索后终于有了一点线索。好的,仅此而已。有邮件交流的朋友加我=-=

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线