因为毕设需要学生和老师的数据,所以研究了一下正方系统的爬取,使用的是tp框架,所以源代码就以tp为例,如果你用的不是tp,那也只需要修改几个地方就可以.如果看完这篇博客后,还有什么疑问,可以在下方留言,我会尽量去解答,如果这篇博客对你有用,记得点赞。
如果想书写一个爬虫,首先应该通过浏览器将你登陆时,本地与服务器之间的信息传递通过抓包的方式获得,然后通过编程语言去模拟这种信息传递。
第一次抓包的信息如上,主要提交了两次,第一次是向default2.aspx进行post提交
,虽然被重定向,但是这一次提交,完成了数据的验证,验证的字段如图所示,第一个字段是登陆界面的一个隐藏字段,可以通过正则获取到,txtSecretCode是验证码,这是正方系统的一个小bug,在我们模拟登陆的时候可以忽略,RadioButtonList1代表的是学生。
上图中我们可以看到Request URL中附加了一个字段,这个字段是随即的,经过测试,得出正方系统有两种登陆方式,一种是通过cookie来确认用户,另一种是通过随即字符串的形式,现在我们校网所使用的是随机字符串的形式。在第一次向default2.aspx 进行post提交时,可能是通过js产生了随即字符串并被附着在url中,验证通过之后会被重定向到xs_main.aspx页面,访问此页面通过的是get方式。
此时的随即字符串和上次post提交时的是相同的。这一次信息交换之后,即标志着登陆成功。登陆成功之后,如果想获得学生的个人信息和课表信息,通过再次抓包,来获得需要模拟的信息。我就不贴图了,下方代码的getkebiao函数和getperinfo函数都有这种模拟过程。还有一点,正方的网页编码使用的是gb2312,所以如果不想你爬到的结果是一片乱码,那就将它转换为utf-8吧
代码如下:
<?php
namespace Home\Controller;
use Think\Controller;
class SpiderController extends Controller {
public $sid = '';
public $password = '';
public $identity = '学生';
/*
*此处的作用是:
*获得url中的随即参数和__VIEWSTATE
*
*/
function getView(){
$res;
$url = 'http://211.87.155.19/default2.aspx';
$result = $this->curl_request($url);
if (empty($result)) {
return array(
'status' => "0",
'message' => "模拟登陆失败,网址可能以改变",
);
}
preg_match('/Location: \/\((.*)\)/', $result,$temp);
$pattern = '/<input type="hidden" name="__VIEWSTATE" value="(.*?)" \/>/is';
preg_match_all($pattern, $result, $matches);
$res[0] = $matches[1][0];
$res[1] = $temp[1];
if (empty($res)) {
return array(
'status' => "0",
'message' => "获取随即参数或_VIEWSTATE失败",
);
}
return array(
'status' => "1",
'message' => $res,
);
}
//参数1:访问的URL,参数2:post数据(不填则为GET),3是否需要加referer url
function curl_request($url,$post='',$referer=''){//$cookie='', $returnCookie=0,
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)');
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($curl, CURLOPT_AUTOREFERER, 1);
curl_setopt($curl, CURLOPT_HEADER, 1);
curl_setopt($curl, CURLOPT_REFERER, "http://211.87.155.19/default2.aspx");
curl_setopt($curl, CURLOPT_TIMEOUT, 10);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
if($post) {
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($post));
}
if ($referer) {
curl_setopt($curl, CURLOPT_REFERER, $referer);
}
$data = curl_exec($curl);
curl_close($curl);
return $data;
}
/*
*此处的作用是:
*模拟登陆校网,如果返回学生姓名,则登陆成功
*
*/
function login($temp){
$url = 'http://211.87.155.19/('.$temp[1].')/default2.aspx';
$post['__VIEWSTATE'] = $temp[0];
$post['txtUserName'] = $this->sid;
$post['TextBox2'] = $this->password;
$post['txtSecretCode'] = '';
$post['lbLanguage'] = '';
$post['RadioButtonList1'] = iconv('utf-8', 'gb2312', $this->identity);
$post['Button1'] = '';//iconv('utf-8', 'gb2312', '登录');
$result = $this->curl_request($url,$post);
if (empty($result)) {
return array(
'status' => "0",
'message' => "模拟登陆失败",
);
}
$referer = 'http://211.87.155.19/('.$temp[1].')/xs_main.aspx?xh='.$post['txtUserName'];
$result = $this->curl_request($referer,'',$url);
$result = iconv('gb2312', 'utf-8//IGNORE', $result);
preg_match('/<span id=\"xhxm\">(.*)<\/span>/',$result, $name);
if (empty($name)) {
return array(
'status' => "0",
'message' => "得不到您的姓名",
);
}
return array(
'status' => "1",
'message' => $name[1],
);
}
/*
*此处的作用是:
*得到校网上老师和对应课程的数组
*
*/
function getkebiao($temp)
{
$post_m['xh'] = $this->sid;
$post_m['xm'] = iconv('utf-8','gb2312','' );
$post_m['gnmkdm'] = 'N121603';
$temp_info = http_build_query($post_m);
$referer = 'http://211.87.155.19/('.$temp[1].')/xs_main.aspx?xh='.$sid;
$url = 'http://211.87.155.19/('.$temp[1].')/xskbcx.aspx?'.$temp_info;
$result = $this->curl_request($url,'',$referer);
$result = iconv('gb2312', 'utf-8', $result);
if (empty($result)) {
return array(
'status' => "0",
'message' => "得到课表信息失败",
);
}
$pattern = '/<td align=\"Center\" rowspan=\"2\"( width=\"7%\"){0,1}>([^<]*?)<br>([^<]*?)<br>([^<]*?)<br>([^<]*?)<br>([^<]*?)<\/td>/';
preg_match_all($pattern, $result, $mm);
$info_tea_cou_a = array_combine($mm[2], $mm[5]);
$pattern ='/<td align=\"Center\" rowspan=\"2\"( width=\"7%\"){0,1}>([^<]*?)<br>([^<]*?)<br>([^<]*?)<br>([^<]*?)<br>([^<]*?)<br>(<br><font color=\'red\'>.*?<\/font><br>){0,1}<br>([^<]*?)<br>([^<]*?)<br>([^<]*?)<br>([^<]*?)<br>([^<]*?)(<br><br><font color=\'red\'>.*?<\/font>){0,1}<\/td>/';
preg_match_all($pattern, $result, $tt);
$info_tea_cou_b = array_combine($tt[2], $tt[5]);
$info_tea_cou_c = array_combine($tt[8], $tt[11]);
$info_temp = array_merge($info_tea_cou_a,$info_tea_cou_b,$info_tea_cou_c);
if (empty($info_temp)) {
return array(
'status' => "0",
'message' => "您的课表信息为空",
);
}
return array(
'status' => "1",
'message' => $info_temp,
);
}
/*
*此处的作用是:
*得到学生校网上的部分信息,包括出生日期,专业,学院,联系方式,入学日期,照片
*
*/
function getPerInfo($temp)
{
$post_m['xh'] = $this->sid;
$post_m['xm'] = iconv('utf-8','gb2312','' );
$post_m['gnmkdm'] = 'N121501';
$temp_info = http_build_query($post_m);
$referer = 'http://211.87.155.19/('.$temp[1].')/xs_main.aspx?xh='.$sid;
$url = 'http://211.87.155.19/('.$temp[1].')/xsgrxx.aspx?'.$temp_info ;
$result = $this->curl_request($url,'',$referer);
if (empty($result)) {
return array(
'status' => "0",
'message' => "得到个人信息失败",
);
}
$result = iconv('gb2312', 'utf-8', $result);
preg_match('/\"lbl_csrq\">(.*)<\/span>/',$result, $temp_info);
$info['birthday'] = $temp_info[1];
preg_match('/\"lbl_zymc\">(.*)<\/span>/', $result, $temp_info);
$info['profession'] = $temp_info[1];
preg_match('/\"lbl_xy\">(.*)<\/span>/', $result, $temp_info);
$info['depart'] = $temp_info[1];
preg_match('/\"lbl_lxdh\">(.*)<\/span>/', $result, $temp_info);
$info['phone'] = $temp_info[1];
preg_match('/\"lbl_rxrq\">(.*)<\/span>/', $result, $temp_info);
$info['entry_date'] = $temp_info[1];
preg_match('/\"lbl_xzb\">(.*)<\/span/', $result,$temp_info);
$info['class'] = $temp_info[1];
preg_match('/id=\"xszp\" src=\"(.*?)\" /', $result, $temp_info);
$info['photo'] = $temp_info[1];
$photo_add ='http://211.87.155.19/('.$temp[1].')/readimagexs.aspx?xh='.$this->sid;
GrabImage($photo_add,$this->sid);
if (empty($info)) {
return array(
'status' => "0",
'message' => "您的个人信息为空",
);
}
return array(
'status' => "1",
'message' => $info,
);
}
function test($value='')
{
$temp = $this->getView();
$cc = $this->login($temp['message']);
$aa = $this-> getPerInfo($temp['message']);
$bb = $this->getkebiao($temp['message']);
var_dump($bb);
exit;
}
}
最后如果有人需要老师模拟登陆的代码,可以在下方留言。