curl php 模拟来源_PHP cURL实现模拟登录与采集使用方法详解教程

对于做过数据采集的人来说,cURL一定不会陌生。虽然在PHP中有file_get_contents函数可以获取远程链接的数据,但是它的可控制性太差了,对于各种复杂情况的采集情景,file_get_contents显得有点无能为力。因此,本文将为你介绍采集神器cURL的使用。

工具

火狐浏览器(FireFox) + Firebug

“工欲善其事,必先利其器。” 在分析案例之前,先让我们学习一下如何利用神器Firebug获取我们必要的信息。

使用F12打开Firebug,我们可以得到如图(一)界面:

箭头图标是“元素选择”工具,单击一次会高亮图标,同时,鼠标在页面内的移动会同时在HTML菜单中选定相应的内容,此时单击内容则表示选定了该元素,图标高亮取消。如图(二)所示:

控制台

JS里面的console.log系列函数的打印就是在这里输出。

HTML

HTML内容,注意这里看到的不一定是采集要解析的内容,采集时候对内容的分析,一律以查看源码(Ctrl+U)为准,这里只是能快速定位元素的结构,然后再选择一个比较特殊的参照,在源码中定位相应的位置。

比如,你在HTML里面看到一个标签是

Demo
,但是你查看源码时候看到的内容可能是
Demo
,如果你对采集内容按照前者去做正则匹配,那么你会得不到结果。

CSS

这里是CSS文件内容

脚本

这里是Javascript文件内容

DOM

Dom节点内容

网络

每一个请求链接的数据,这里是我们采集要关注和分析的地方,它能够显示每一个请求的参数、请求头、Cookie数据等。在页面提交会刷新的情况下,需要使用保持,使得页面请求内容在刷新后仍然留着控制台中,如图(三)所示:

另外,火狐还有一款 Tamper data 扩展也能得到请求数据,必要时可以安装使用。

Cookies

Cookie数据

在图(一)中还看到下面有很多可选的小菜单项,其中保持是我们要关注的,当选择它的时候,即使提交表单刷新了页面,下面内容区域的数据还是会保留,这个对于分析提交数据特别关键。

总结

我们在分析采集请求的时候,主要关心“网络”菜单里的请求数据,必要时候使用“保持”以查看刷新页面的请求数据,请求前可以使用“清除”先清除下面的内容。

案例解析

一、简单的采集

这里所指的简单采集,是指一个单一页面GET请求的采集,它简单得即使通过file_get_contents函数也能轻松获得页面返回结果。

代码片段之file_get_contents

$url='http://demo.zjmainstay.cn/php/curl/simple.html';

$content=file_get_contents($url);

echo $content;

代码片段之cURL

$url='http://demo.zjmainstay.cn/php/curl/simple.html';

$ch=curl_init($url);

curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);//返回数据不直接输出

$content=curl_exec($ch);//执行并存储结果

curl_close($ch);

echo $content;

二、需要参数的采集

这种情况,页面请求需要传入一些参数,可以是GET请求,也可以是POST请求。这种情况的采集,使用file_get_contents外带一些参数还是可以实现的,但是这里我们将不再展示。

代码片段之cURL GET

这种请求,我们可以选择搜索引擎作为演示,比如我百度搜索一个词语“PHP cURL”,在输入回车后,我们会得到一个类似http://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&ch=&tn=baidu&bar=&wd=PHP%20cURL的链接,注意这里的链接可能不同浏览器、不同入口方式访问得到不一样结果,因此不必介意链接是否一样。通过输入多个关键词并观察链接,我们可以确定 wd 参数就是我们要传入的动态参数,而其他参数则可以不变,因此得到我们下面的采集代码。

$keyword='PHP cURL';

$url='http://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&ch=&tn=baidu&bar=&wd='.urlencode($keyword);

$ch=curl_init($url);

curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);//返回数据不直接输出

$content=curl_exec($ch);//执行并存储结果

curl_close($ch);

echo $content;

有些时候,一些参数并不是必须的,这时候我们可以删掉它,比如上面的链接可以只保留http://www.baidu.com/s?ie=utf-8&wd=PHP%20cURL,ie=utf-8 这个参数可能影响结果的编码,所以暂且留着它。就这样简单的代码,我们就可以采集到百度搜索的结果了。

代码片段之cURL POST

对于POST类型的请求,我们平时并不少见,比如有些搜索就是使用POST方式提交,这时候我们就需要使用POST类型来提交参数了。这个在PHP cURL里面有相应的参数:CURLOPT_POST 和 CURLOPT_POSTFIELDS , CURLOPT_POST 的设置可以指定当前提交是否为POST方式,CURLOPT_POSTFIELDS则用于设定提交的参数,可以是参数串,也可以是参数数组,比如:

curl_setopt($ch,CURLOPT_POSTFIELDS,'ie=utf-8&wd=PHP%20cURL');

curl_setopt($ch,CURLOPT_POSTFIELDS,array(

'ie'=>'utf-8',

'wd'=>'PHP%20cURL',

));

下面是我做的一个POST模拟搜索PHP POST 搜索,后端是使用了前面的百度关键词搜索,基本原理就是,客户端提交一个关键词到我服务器,我服务器使用该关键词请求百度的搜索,然后得到结果,返回到客户端。

如图(四)是利用Firebug对请求数据的分析,得到我们需要提交的请求链接和请求参数:

然后下面是我们的代码:

$keyword='PHP cURL';

//参数方法一

// $post = 'wd=' . urlencode($keyword);

//参数方法二

$post=array(

'wd'=>urlencode($keyword),

);

$url='http://demo.zjmainstay.cn/php/curl/search.php';

$ch=curl_init($url);

curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);//返回数据不直接输出

curl_setopt($ch,CURLOPT_POST,1);//发送POST类型数据

curl_setopt($ch,CURLOPT_POSTFIELDS,$post);//POST数据,$post可以是数组,也可以是拼接

$content=curl_exec($ch);//执行并存储结果

curl_close($ch);

var_dump($content);

三、需要Referer的采集

对于一些程序,它可能判断来源网址,如果发现referer不是自己的网站,则拒绝访问,这时候,我们就需要添加CURLOPT_REFERER参数,模拟来路,使得程序能够正常采集。

$keyword='PHP cURL';

//参数方法一

// $post = 'wd=' . urlencode($keyword);

//参数方法二

$post=array(

'wd'=>urlencode($keyword),

);

$url='http://demo.zjmainstay.cn/php/curl/search_refer.php';

$refer='http://demo.zjmainstay.cn/';//来路地址

$ch=curl_init($url);

curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);//返回数据不直接输出

curl_setopt($ch,CURLOPT_REFERER,$refer);//来路模拟

curl_setopt($ch,CURLOPT_POST,1);//发送POST类型数据

curl_setopt($ch,CURLOPT_POSTFIELDS,$post);//POST数据,$post可以是数组,也可以是拼接

$content=curl_exec($ch);//执行并存储结果

curl_close($ch);

var_dump($content);

search_refer.php的源码如下,做了简单的Referer判断拦截:

if(empty($_POST['wd'])){

exit('Deny empty params.');

}

//Referer判断

if(stripos($_SERVER['HTTP_REFERER'],$_SERVER['HTTP_HOST'])===false){

exit('Deny');

}

$keyword=addslashes(trim(strip_tags($_POST['wd'])));

$url='http://www.baidu.com/s?ie=utf-8&wd='.urlencode($keyword);

$ch=curl_init($url);

curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);//返回数据不直接输出

$content=curl_exec($ch);//执行并存储结果

curl_close($ch);

echo $content;

四、需要cookie支持的采集

对于模拟登录的应用,单单提交参数和模拟来路并不能解决问题,这时候我们就需要保存或者提交相应的Cookie参数,这个在PHP cURL里面也提供了相应的参数:

CURLOPT_COOKIE: 直接使用字符串方式提交cookie参数

CURLOPT_COOKIEFILE: 使用文件方式提交cookie参数

CURLOPT_COOKIEJAR: 保存提交后反馈的cookie数据

(一)模拟登录示例

下面是PHP100的模拟登录示例(旧版,已不可用):

header("content-Type: text/html; charset=UTF-8");

$cookie_file=tempnam('./temp','cookie');

$login_url="http://bbs.php100.com/login.php";

$post_fields="cktime=36000&step=2&pwuser=username&pwpwd=password";

//提交登录表单请求

$ch=curl_init($login_url);

curl_setopt($ch,CURLOPT_HEADER,0);

curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);

curl_setopt($ch,CURLOPT_POST,1);

curl_setopt($ch,CURLOPT_POSTFIELDS,$post_fields);

curl_setopt($ch,CURLOPT_COOKIEJAR,$cookie_file);//存储提交后得到的cookie数据

curl_exec($ch);

curl_close($ch);

//登录成功后,获取bbs首页数据

$url="http://bbs.php100.com/index.php";

$ch=curl_init($url);

curl_setopt($ch,CURLOPT_HEADER,0);

curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);

curl_setopt($ch,CURLOPT_COOKIEFILE,$cookie_file);//使用提交后得到的cookie数据做参数

$contents=curl_exec($ch);

curl_close($ch);

//转码显示

echo iconv('gbk','UTF-8',$contents);

(二)自动模拟登录实现

最近研究出来一个自动模拟登录的类,请查看《PHP基于cURL实现自动模拟登录》了解。(补充于2016.7.31)

五、压缩网页采集(gzip)

有些没有接触过压缩页面的朋友估计会在这里被坑死,因为他们会发现采集回来的内容是乱码,并且无论使用iconv还是强大的mb_convert_encoding都无法还原数据,然后又没有概念,各种抓狂却找不到方法,哈哈,我曾经也是这样~

如图(五)是乱码表现形式:

还好最后功夫不负有心人,还是找到了,它就是CURLOPT_ENCODING参数。

比如,采集搜狐的新闻时候就遇到gzip压缩问题,下面是示例:

$url='http://news.sohu.com/';

$ch=curl_init($url);

curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);//返回数据不直接输出

curl_setopt($ch,CURLOPT_ENCODING,"gzip");//指定gzip压缩

$content=curl_exec($ch);//执行并存储结果

curl_close($ch);

echo $content;

手册说明:支持的编码有"identity","deflate"和"gzip"。如果为空字符串"",请求头会发送所有支持的编码类型。

后面一句表明,使用curl_setopt($ch, CURLOPT_ENCODING, "");也是可以的,但是不能不加这个参数。

六、SSL链接的采集

有些请求链接是https类型的,这时候使用cURL采集可能会失败,这时候,我们可以使用 var_dump(curl_error($ch));的方法打印错误提示,然后根据错误提示查找相应的解决方案。比如SSL错误常见提示:SSL certificate problem: unable to get local issuer certificate,这时候,我们就需要利用参数:CURLOPT_SSL_VERIFYPEER 和 CURLOPT_SSL_VERIFYHOST 来禁用SSL证书的验证,我尝试过只使用CURLOPT_SSL_VERIFYPEER参数禁用失败,所以大家最好同时使用两个参数。

下面是代码示例:

$searchStr='RC376981638HK';

$post='accion=LocalizaUno&numero='.$searchStr.'&ecorreo=&numeros=';

$url='https://aplicacionesweb.correos.es/localizadorenvios/track.asp';

$ch=curl_init($url);//初始化curl

curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);//返回数据不直接输出

curl_setopt($ch,CURLOPT_POST,1);//发送POST类型数据

curl_setopt($ch,CURLOPT_POSTFIELDS,$post);//POST数据,$post可以是数组,也可以是拼接参数串

curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false);//SSL 报错时使用

curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,false);//SSL 报错时使用

$contents=curl_exec($ch);//执行并存储结果

// var_dump(curl_error($ch)); //获取失败是使用(采集错误提示)

curl_close($ch);

echo $contents;

今天(2016.8.20)遇到一个错误error:14077458:SSL routines:SSL23_GET_SERVER_HELLO:reason(1112),测试追加参数

//值有0-6,请参考手册,值1不行试试其他值

curl_setopt($ch,CURLOPT_SSLVERSION,1);

可解决问题。

七、代理采集

大家都知道,国内存在万恶的墙,所以,假如我们需要获取某些被墙数据时,就需要用到国外代理服务器;又或者我们需要采集大量数据时,需要不断切换IP,也会用到代理。

使用代理在PHP cURL里面有几个相对应的参数:CURLOPT_PROXY、CURLOPT_PROXYPORT 和 CURLOPT_PROXYUSERPWD,还有另外几个,这里不列举。

CURLOPT_PROXY 指定代理IP参数

CURLOPT_PROXYPORT 指定代理端口参数

CURLOPT_PROXYUSERPWD 指定需要验证的代理的账号密码,"[username]:[password]"格式的字符串

关于代理账号获取,大家自己发挥,我这里提供网上搜索到的一个列表:cURL 高匿代理

下面是代理采集示例:

$url='http://demo.zjmainstay.cn/php/curl/dump_ip.php?t='.time();

echo"本地IP:".file_get_contents($url)."\n伪造IP:";

$ip='183.224.1.116';

$port='80';

//伪造请求头参数,如果是高匿代理这里不需要提供

$header=array(

'X-FORWARDED-FOR: '.$ip,

'CLIENT-IP: '.$ip,

);

$ch=curl_init($url);//初始化curl

curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);

curl_setopt($ch,CURLOPT_HTTPHEADER,$header);

curl_setopt($ch,CURLOPT_PROXY,$ip);

curl_setopt($ch,CURLOPT_PROXYPORT,$port);

$content=curl_exec($ch);//执行并存储结果

curl_close($ch);

echo $content;

八、 多线程采集

对于大量采集工作,为了提高采集效率,使用PHP cURL提供的多线程采集是必不可少的。手册上提供的多线程采集例子好像都不太好用,我刚开始也从里面测试了几个例子,但是发现都是执行卡死,根本无法执行完成,前几天突然又测试了一下,然后发现curl_multi_info_read函数下面的Example #1是可以执行的,它的内容在$res上,但是没有打印出来,而且雅虎的请求比较慢,会卡住,前面两个链接都能正常返回。

不过,还好当时的例子不好用,然后我经过搜索找到了一个很厉害的项目,CurlMulti ,它对PHP cURL Multi 进行了一个良性扩展的封装,能够很好地提供采集支持。

关于CurlMulti的使用我就不多介绍,官网上面提供了demo,使用过程有技术难题可以直接加入Q群( PHP cURL高级技术2群 744854777 )讨论,作者@Ares 和其他的采集大牛都会提供技术解答帮助。

下面是PHP cURL Multi的一个简单示例:

$urls=array(

array(

'url'=>'http://demo.zjmainstay.cn/php/curl/curl_multi_1.php',

'id'=>1,

),

array(

'url'=>'http://demo.zjmainstay.cn/php/curl/curl_multi_2.php',

'id'=>2,

),

);

$mh=curl_multi_init();

$conn=array();

foreach($urlsas$urlItem){

$ch=curl_init($urlItem['url']);

$conn[(int)$ch]=$urlItem;//记录资源与参数映射

curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);//不直接输出结果

curl_multi_add_handle($mh,$ch);

}

$active=null;

$res=array();

do{

$status=curl_multi_exec($mh,$active);

$info=curl_multi_info_read($mh);

if(false!==$info){

//采集信息处理

$res[]=array(

'content'=>curl_multi_getcontent($info['handle']),

'info'=>$info,

'param'=>$conn[(int)$info['handle']],

);

curl_close($info['handle']);

}

}while($status===CURLM_CALL_MULTI_PERFORM||$active);

curl_multi_close($mh);

var_dump($res);

九、302跳转(301跳转)

对于一些应用,比如模拟登录,如果遇上302跳转,会导致cookie丢失而使得模拟登录失败,请求现象如图(六)所示:

这个时候,可以使用:

curl_setopt($ch,CURLOPT_FOLLOWLOCATION,true);

关于CURLOPT_FOLLOWLOCATION,手册说明是:

启用时会将服务器服务器返回的"Location: "放在header中递归的返回给服务器,使用CURLOPT_MAXREDIRS可以限定递归返回的数量。

我个人理解,通俗点讲就是后面的跳转会继续跟踪访问,而且cookie在header里面被保留了下来。

十、模拟上传文件

(一)基于本地文件上传

在PHP手册的curl_setopt函数中,关于CURLOPT_POSTFIELDS有如下描述:

全部数据使用HTTP协议中的"POST"操作来发送。要发送文件,在文件名前面加上@前缀并使用完整路径。这个参数可以通过urlencoded后的字符串类似'para1=val1&para2=val2&...'或使用一个以字段名为键值,字段数据为值的数组。如果value是一个数组,Content-Type头将会被设置成multipart/form-data。

对于上传文件,这句话包含两个信息:

1. 要上传文件,post的数据参数必须使用数组,使得Content-Type头将会被设置成multipart/form-data。

2. 要上传文件,在文件名前面加上@前缀并使用完整路径。

注意:PHP 5.5.0起,文件上传建议使用CURLFile代替@

因此,模拟文件上传可以按照如下实现:

(1)单文件上传

//上传D盘下的test.jpg文件,文件必须存在,否则curl处理失败且没有任何提示,Windows下中文文件名上传失败时,可使用iconv('UTF-8', 'GBK//IGNORE', $filename)转码下文件名再上传。

$data=array('name'=>'Foo','file'=>'@d:/test.jpg');

注:PHP5.5.0起,文件上传建议使用CURLFile代替@

$ch=curl_init('http://localhost/upload.php');

curl_setopt($ch,CURLOPT_POST,1);

curl_setopt($ch,CURLOPT_POSTFIELDS,$data);

curl_exec($ch);

本地测试的时候,在upload.php文件中打印出$_POST和$_FILES即可验证是否上传成功,如下:

print_r($_POST);

print_r($_FILES);

输出结果类似:

Array([name]=>Foo)Array([file]=>Array([name]=>test.jpg[type]=>application/octet-stream[tmp_name]=>D:\xampp\tmp\php2EA0.tmp[error]=>0[size]=>139999))

(2)多文件上传

// 注: PHP 5.5.0起,文件上传建议使用CURLFile代替@

// 多文件上传

$data=array(

'input_file[0]'=>newCURLFile('d:/1.txt','text/plain','testfile.txt'),

'input_file[1]'=>newCURLFile('d:/2.txt','text/plain'),

'input_file[2]'=>newCURLFile('d:/3.txt','text/plain'),

);

$ch=curl_init('http://demo.zjmainstay.cn/php/curl/curlUploadHandler.php');

curl_setopt($ch,CURLOPT_POST,1);

curl_setopt($ch,CURLOPT_POSTFIELDS,$data);

curl_exec($ch);

输出结果类似:

Array([upload_file]=>Array([name]=>Array([0]=>1.txt[1]=>2.txt[2]=>3.txt)[type]=>Array([0]=>text/plain[1]=>text/plain[2]=>text/plain)[tmp_name]=>Array([0]=>/tmp/phpkQ75hZ[1]=>/tmp/phpuVB5La[2]=>/tmp/phpu1z5fm)[error]=>Array([0]=>0[1]=>0[2]=>0)[size]=>Array([0]=>2[1]=>2[2]=>2)))

(3)CURLOPT_POSTFIELDS使用字符串与数组的区别

关于CURLOPT_POSTFIELDS的赋值,另外补充一句描述:

传递一个数组到CURLOPT_POSTFIELDS,cURL会把数据编码成multipart/form-data,而然传递一个URL-encoded字符串时,数据会被编码成application/x-www-form-urlencoded。

即:

curl_setopt($ch,CURLOPT_POSTFIELDS,'param1=val1&param2=val2&...');

curl_setopt($ch,CURLOPT_POSTFIELDS,array('param1'=>'val1','param2'=>'val2',...));

相当于html的form表单中:

的区别。

(二)基于采集文件内容上传

对于数据采集回来的文件内容,有时候需要再次上传到其他的文件服务器上,此时,如果本地先存储再利用上面的方式提交到文件服务器,显然会多了一次IO写入和读取操作,对于这种情况,我们可以利用构造模拟上传请求头和构造数据报文,直接利用采集回来的文件内容上传到文件服务器:

/**

* @author 如果的如果

* PHP利用cURL直接以文件内容形式上传文件

* @param string $url 文件上传处理链接

* @param array $fileFields 文件上传数据数组

* @param array $postFields 非文件表单数据数组

* @param array $curlOpt 扩展的CURLOPT_数据

* @return string

*/

functioncurlPostMemoryFile($url,$fileFields,$postFields=array(),$curlOpt=array()){

//构造post数据

$data='';

$delimiter='-------------'.uniqid();

// 表单数据

foreach($postFieldsas$name=>$content){

$data.="--".$delimiter."\r\n";

$data.='Content-Disposition: form-data; name="'.$name.'"';

$data.="\r\n\r\n";

$data.=$content;

$data.="\r\n";

//$data.="--".$delimiter."\r\n";

}

// 文件上传数据

foreach($fileFieldsas$inputName=>$file){

$data.="--".$delimiter."\r\n";

$data.='Content-Disposition: form-data; name="'.$inputName.'";'.

' filename="'.$file['filename'].'"'."\r\n";

$data.='Content-Type: '.$file['type']."\r\n";

$data.="\r\n";

$data.=$file['content']."\r\n";

}

$data.="--".$delimiter."--\r\n";

//post请求提交文件上传数据

$handle=curl_init($url);

curl_setopt($handle,CURLOPT_RETURNTRANSFER,1);//返回数据不直接输出

$header=array(

'Content-Type: multipart/form-data; boundary='.$delimiter,

'Content-Length: '.strlen($data)

);

if(isset($curlOpt[CURLOPT_HTTPHEADER])){

$header=array_merge($header,$curlOpt[CURLOPT_HTTPHEADER]);

unset($curlOpt[CURLOPT_HTTPHEADER]);

}

curl_setopt($handle,CURLOPT_HTTPHEADER,$header);

curl_setopt($handle,CURLOPT_POST,true);

curl_setopt($handle,CURLOPT_POSTFIELDS,$data);

if(!empty($curlOpt)){

foreach($curlOptas$key=>$val){

curl_setopt($handle,$key,$val);

}

}

returncurl_exec($handle);

}

//演示

$url='http://demo.zjmainstay.cn/php/curl/curlUploadHandler.php';

$filename='test.txt';

$fileContent='测试直接文件内容形式上传文件';

$fileFields=array(

'upload_file'=>array(

'filename'=>$filename,

#从正常上传时的post数据中查看,对应$_FILES里的type

'type'=>'text/plain',

'content'=>$fileContent,

),

);

$postFields=array(

'name'=>'Zjmainstay',

'age'=>'26',

);

//此处测试CURLOPT_HTTPHEADER的合并

$header=array(

'Host: demo.zjmainstay.cn',

);

$curlOpt=array(

CURLOPT_HTTPHEADER=>$header,

);

$content=curlPostMemoryFile($url,$fileFields,$postFields,$curlOpt);

var_dump($content);

十一、发送与获取json数据

发送json数据,在控制台中的表现主要如图(七)所示:

第一条发送的是json格式的数据,

第二条发送的是以\n分割的数据,

第三条发送的是以&分割的数据。

这个在ajax请求的时候,只需要添加contentType参数即可,如:

vardata=["name:Zjmainstay","website:http://www.zjmainstay.cn"];

$.ajax({

url:'http://test.com/curl/testPostJsonData.php',

type:'post',

data:data.join("\n"),

contentType:'text/plain',

success:function(result){

console.log(result);

},

error:function(msg){

console.log(msg);

}

});

对于这类发送json数据的请求,复制cURL命令时,你会发现其中根本没有发送数据,如:

curl'http://test.com/curl/testPostJsonData.php'-X POST-H'Accept: */*'-H'Accept-Encoding: gzip, deflate'-H'Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3'-H'Cache-Control: max-age=0'-H'Connection: keep-alive'-H'Content-Length: 48'-H'Content-Type: text/plain'-H'Cookie: __utma=99889051.942646074.1467634856.1467634856.1467636947.2'-H'Host: test.com'-H'Referer: http://test.com/curl/ajaxJsonData.html'-H'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:47.0) Gecko/20100101 Firefox/47.0'-H'X-Requested-With: XMLHttpRequest'

对于这种数据,我们要用PHP cURL模拟发送的话,需要发送相应的header参数,示例:

#json数据

$url='http://test.com/curl/testPostJsonData.php';

$data='{"a":"b"}';

$length=strlen($data);

$header=array(

'Content-Length: '.$length,//不是必需的

'Content-Type: text/json',

);

$ch=curl_init($url);//初始化curl

curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);

curl_setopt($ch,CURLOPT_HTTPHEADER,$header);

curl_setopt($ch,CURLOPT_POST,1);

curl_setopt($ch,CURLOPT_POSTFIELDS,$data);

$content=curl_exec($ch);//执行并存储结果

curl_close($ch);

echo $content;

#\n分割数据

$data=[

'name:Zjmainstay',

'website:http://www.zjmainstay.cn',

];

$data=implode("\n",$data);

#&分割数据

$data='name:Zjmainstay&website:http://www.zjmainstay.cn';

对于$.ajax我们常常会使用这种写法来指定返回json格式数据:

$.ajax({

url:url,

dataType:'json',

...

});

我们会发现,cURL请求头Accept:部分会多出一些参数:

-H'Accept: application/json, text/javascript, */*; q=0.01'

因此,如果需要指定返回内容作为json格式,我们就需要指定application/json格式。

那么,对于这种给服务器端发送json数据的程序,服务器端是怎么得到请求数据的呢?

如果你们做过尝试,一定会发现此时$_POST是空的,我们要使用php://input进行数据获取,示例:

$postData=file_get_contents('php://input');

十二、POST提交大数据(超过1024字节)异常解决方法

在使用cURL做POST的时候,当要POST的数据大于1024字节的时候,cURL并不会直接就发起POST请求, 而是会分为俩步:

1.发送一个请求,包含一个Expect:100-continue,询问Server是否愿意接受数据

2.接收到Server返回的100-continue应答以后,才把数据POST给Server

解决:

curl_setopt($ch,CURLOPT_HTTPHEADER,array('Expect:'));

十三、获取请求头部和丢弃BODY内容

有时候,被采集的站点把下一次跳转的链接放入了响应头里,这时候,我们需要通过设置CURLOPT_HEADER属性为true,让响应结果携带响应头即可。

curl_setopt($ch,CURLOPT_HEADER,true);

如果我们只需要获取响应头,或者有时候只是为了测试某个链接是否能够正常请求,我们可以通过设置CURLOPT_NOBODY为true,让响应结果不返回BODY内容。

curl_setopt($ch,CURLOPT_NOBODY,true);

总结

PHP cURL自动模拟登录与采集类

通用curl页面采集函数

简易解析cURL命令得到PHP代码程序

PHP cURL是一个很强大的采集工具,curl_setopt里面还有很多参数,读者可以抽空整体看一遍,虽然平时未必用得上,但是至少做到心里有底,知道都有哪些参数,必要时还能找出来使用。

采集是一项大工程,使用过程中遇到的问题还会不少,但是只要学会分析和资料搜索,一切都会迎刃而解的,大家加油!哈哈~~

未经同意禁止转载!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值