这周要做一个小项目,需要获得学生的账户名密码后,去本校教务系统验证是否正确并且抓一个网页信息下来。
查网上时候,可以通过发送POST或GET请求来实现,然后尝试用POST先。
首先安装libcurl库
sudo yum install libcurl
安装好后之后代码中添加头文件curl/curl.h就可以使用curl的函数了。
当时需要访问的正方网页(222.24.62.120)需要验证码,但是有另一个网站222.24.162.120/default4.aspx 可以用来验证帐号密码是否正确,从这个网站上拿到Cookie然后带着Cookie去访问正方网站就可以进去了。
然后我们来看看进入网页发送的请求包内容。
这个是带着帐号密码访问该网站时发送的请求包,图中Request Headers是发送包头部信息,Form Data下面还有两个信息分别是帐号密码,它里面是发送包的数据部分,代码访问网站就是模拟这个过程,将这些信息手动加入,然后打包发出去。
过程中用到一共三个函数:
curl_slist_append();
curl_easy_init();
curl_easy_setopt();
curl_easy_perform();
curl_easy_cleanup();
1.curl_easy_init()
函数原型
CURL *curl_easy_init();
函数功能
初始化一个CURL指针,相应的末尾要清理这个指针。
2.curl_easy_setopt()
函数原型
CURLcode curl_easy_setopt(CURL *handle, CURLoption option, parameter);
函数功能
这个参数很重要,要通过它对访问过程做很多设置。基本都是通过第二个参数在设置,所以第二个参数牵扯到很多宏,下面列几个我用到的。
重要宏(option)
- CURLOPT_HTTPHEADER 用来设置HTTP头部字段,第三个参数是一个数组,包含了所有头部信息
- CURLOPT_COOKIEJAR 指定连接结束后保存Cookie信息的文件
- CURLOPT_COOKIEFILE 指定读取Cookie的文件
- CURLOPT_URL 设置要访问的URL
- CURLOPT_WRITEDATA 指定将网页信息写进去的文件
- CURLOPT_POSTFIELDS 全部数据使用HTTP协议中的POST操作来发送。第三个数据指定要发送发送数据。
- CURLOPT_RETURNTRANSFER 将curl_exec()获取的信息以文件流的形式返回,而不是直接输出。
3.curl_easy_perform()
函数原型
CURLcode curl_easy_perform( CURL *easy_handle);
该函数完成curl_easy_setopt指定的所指定的值,返回0意味一切ok,非0代表错误发生。主要错误码说明:
1.CURLE_OK
任务完成一切都好
2.CURLE_UNSUPPORTED_PROTOCOL
不支持的协议,由URL的头部指定
3.CURLE_COULDNT_CONNECT
不能连接到remote 主机或者代理
4.CURLE_REMOTE_ACCESS_DENIED
访问被拒绝
5.CURLE_HTTP_RETURNED_ERROR
Http返回错误
6.CURLE_READ_ERROR
读本地文件错误
1.curl_easy_cleanup()
函数原型
void curl_easy_cleanup(CURL *handle);
函数功能
结束licurl使用时,清理掉curl_easy_init的指针。
6.curl_slist_append()
函数原型
struct curl_slist *curl_slist_append(struct curl_slist *list, const char *string);
函数功能
追加字符串string到链表list尾,返回添加后的链表,在代码中用来将头部信息逐句添加到字符串中。
这一段便可访问到222.24.162.120/default4.aspx 的网站,然后获取到Cookie数据存入文件。
bool postUrl(const char *filename, std::string id, std::string passwd )
{
CURL *curl;
CURLcode res;
FILE *fp;
std::string mess = "__VIEWSTATE=dDwxMTE4MjQwNDc1Ozs%2BYofaNxf5dpXqcC3ZAqYdKfPCdbw%3D&TextBox1="
+ id + "&TextBox2=" + passwd + "&RadioButtonList1=%D1%A7%C9%FA&Button1=+%B5%C7+%C2%BC+";
if( (fp = fopen(filename, "w")) == NULL )
{
return false;
}
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8" );
headers = curl_slist_append(headers, "Accept-Encoding:gzip, deflate");
headers = curl_slist_append(headers, "Accept-Language:zh-CN,zh;q=0.8");
headers = curl_slist_append(headers, "ache-Control:no-cache");
headers = curl_slist_append(headers, "Connection:keep-alive" );
headers = curl_slist_append(headers, "Content-Type:application/x-www-form-urlencoded" );
headers = curl_slist_append(headers, "Host:222.24.62.120");
headers = curl_slist_append(headers, "Origin:http://222.24.62.120");
headers = curl_slist_append(headers, "Pragma:no-cache");
headers = curl_slist_append(headers, "Referer:http://222.24.62.120/default4.aspx");
headers = curl_slist_append(headers, "Upgrade-Insecure-Requests:1");
headers = curl_slist_append(headers, "User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36");
curl = curl_easy_init();
if( curl )
{
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);// 改协议头
curl_easy_setopt(curl, CURLOPT_COOKIEJAR, "/home/yunting/cookie.txt");
curl_easy_setopt(curl,CURLOPT_POSTFIELDS, mess.c_str());
curl_easy_setopt(curl, CURLOPT_URL, "http://222.24.62.120/default4.aspx");
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
}
fclose(fp);
return true;
}
然后用同样的方法,在之前存储Cookie的文件中拿到Cookie数据,就能愉快的获取数据了。
bool postUrl_two(const char *filename,std::string id)
{
CURL *curl;
CURLcode res;
FILE *fp;
std::string mess2 = "http://222.24.62.120/lw_xsxx.aspx?xh=" + id;
std::string mess1 = "Referer: "+mess2;
if((fp = fopen(filename,"w")) == NULL)
{
return false;
}
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8" );
headers = curl_slist_append(headers, "Accept-Encoding:gzip, deflate,sdch");
headers = curl_slist_append(headers, "Accept-Language:zh-CN,zh;q=0.8");
headers = curl_slist_append(headers, "Cache-Control:no-cache");
headers = curl_slist_append(headers, "Connection:keep-alive" );
headers = curl_slist_append(headers, "Host:222.24.62.120");
headers = curl_slist_append(headers, "Pragma:no-cache");
headers = curl_slist_append(headers, mess1.c_str());
headers = curl_slist_append(headers, "Upgrade-Insecure-Requests:1");
headers = curl_slist_append(headers, "User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36");
curl = curl_easy_init();
if( curl )
{
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);// 改协议头
curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "/home/yunting/cookie.txt");
curl_easy_setopt(curl, CURLOPT_URL, mess2.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
}
fclose(fp);
return true;
}
因为当时还需要用从网页中匹配出所需信息,而网页是gb2312编码格式,所以在编码转换上奋战一下午,未果,寻PHP终。。。
PHP实现
思路大概相同,就是函数名有点变化,用到函数有:
curl_init();
curl_setopt();
curl_exec();
curl_getinfo();
curl_close();
其中curl_getinfo()获得一个CURL连接资源句柄的信息,至于获得哪个信息,由参数决定。
同样,PHP中的主要函数还是curl_setopt(),设置主要在参数,可点击下面连接查找。
http://php.net/manual/zh/function.curl-setopt.php
//get请求得到id,passwd,前期判断
<?php
header("content-type:text/html;charset=utf-8");
if(empty($_GET))
{
echo "{\"status\":-2,\"value\":\"GET请求为空\"}";
exit();
}
if(empty($_GET['sid']))
{
echo "{\"status\":-2,\"value\":\"学号不能为空\"}";
exit();
}
if(empty($_GET['passwd']))
{
echo "{\"status\":-2,\"value\":\"密码不能为空\"}";
exit();
}
$sid = $_GET['sid'];
$passwd = $_GET['passwd'];
if( ((preg_match('/[0-2][0-9]1[2-6]\d{4}/', $sid)) == FALSE) || (strlen($sid) != 8) )
{
echo "{\"status\":-2,\"value\":\"输入帐号长度有问题\"}";
}
if( strlen($passwd) < 6 || strlen($passwd) > 16 )
{
echo "{\"status\":-2,\"value\":\"输入密码长度有问题\"}";
}
//定义字符串数组$req_head,添加所有头部信息
"Accept" => "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"Accept-Encoding" => "gzip, deflate",
"Accept-Language" => "zh-CN,zh;q=0.8",
"ache-Control" => "no-cache",
"Connection" => "keep-alive",
"Content-Type" => "application/x-www-form-urlencoded",
"Host" => "222.24.62.120",
"Origin" => "http://222.24.62.120",
"Pragma" => "no-cache",
"Referer" => "http://222.24.62.120/default4.aspx",
"Upgrade-Insecure-Requests" => "1",
"User-Agent" => "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36",
);
//定义请求的$form_data
$form_data = "__VIEWSTATE=dDwxMTE4MjQwNDc1Ozs%2BYofaNxf5dpXqcC3ZAqYdKfPCdbw%3D&TextBox1=".$sid."&TextBox2=".$passwd."&RadioButtonList1=%D1%A7%C9%FA&Button1=+%B5%C7+%C2%BC+";
$to_url = "http://222.24.62.120/default4.aspx";
$curl = curl_init();
$cookie = "cookie";
if($curl)
{
curl_setopt($curl, CURLOPT_HEADER, true);
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_HTTPHEADER, $req_head);
curl_setopt($curl, CURLOPT_COOKIEJAR, $cookie);
curl_setopt($curl, CURLOPT_POSTFIELDS, $form_data);
curl_setopt($curl, CURLOPT_URL, $to_url);
$res = curl_exec($curl);
$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);
if($httpCode == 302)
{
$mes = "http://222.24.62.120/lw_xsxx.aspx?xh=".$sid;
$req_head2 = array(
"Accept" => "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"Accept-Encoding" => "gzip, deflate, sdch",
"Accept-Language" => "zh-CN,zh;q=0.8,en;q=0.6,ia;q=0.4",
"Cache-Control" => "no-cache",
"Connection" => "keep-alive",
"Host" => "222.24.62.120",
"Pragma" => "no-cache",
"Upgrade-Insecure-Requests" => "1",
"User-Agent" => "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36",
);
$curl2 = curl_init();
if($curl2)
{
curl_setopt($curl2, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl2, CURLOPT_HEADER, false);
curl_setopt($curl2, CURLOPT_NOBODY, false);
curl_setopt($curl2, CURLOPT_HTTPGET, true);
curl_setopt($curl2, CURLOPT_HTTPHEADER, $req_head2);
curl_setopt($curl2, CURLOPT_COOKIEFILE, $cookie);
curl_setopt($curl2, CURLOPT_REFERER, $mes);
curl_setopt($curl2, CURLOPT_URL, $mes);
$res2 = curl_exec($curl2);
$httpCode2 = curl_getinfo($curl2, CURLINFO_HTTP_CODE);
if($httpCode2 == 200)
{
$res2 = mb_convert_encoding($res2, "UTF-8","GB2312"); //将$res中的信息从gb2312格式转换为UTF-8
$tmp = htmlentities($res2, ENT_QUOTES, 'UTF-8');
echo "<pre>".$tmp."</pre><hr />";
$dom = new DOMDocument();
//创建DOM树存储信息
$dom ->loadHTML("<meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\">".$res2); //头部添加此信息让来查找的觉得这是UTF-8编码
$user = array();
$user['xh'] = $dom->getElementById('xh')->nodeValue;
$user['xm'] = $dom->getElementById('xm')->nodeValue;
$user['xy'] = $dom->getElementById('xy')->nodeValue;
$user['zy'] = $dom->getElementById('zy')->nodeValue;
$user['xzb'] = $dom->getElementById('xzb')->nodeValue; //查出对应ID的信息
echo json_encode($user,JSON_UNESCAPED_UNICODE); //发送json串
curl_close($curl2);
}
}
}
}
PHP中编码转换函数:
$res = mb_convert_encoding($res, "UTF-8","gb2312");
res指定要转换的字符串变量,第二个参数指定要转换成什么格式,第三个参数指定转换前文本的格式。返回转换结果。例如此函数将gb2312转换为utf-8。
完了!!搞定!为建设中国特色社会主义道路加油奋斗!