PHP cURL实现模拟登录与采集使用方法详解教程
本文将通过案例,整合浏览器工具与PHP程序,教你如何让数据 唾手可得 。
对于做过数据采集的人来说,cURL一定不会陌生。虽然在PHP中有file_get_contents函数可以获取远程链接的数据,但是它的可控制性太差了,对于各种复杂情况的采集情景,file_get_contents显得有点无能为力。因此,本文将为你介绍采集神器cURL的使用。
-
箭头图标是“元素选择”工具,单击一次会高亮图标,同时,鼠标在页面内的移动会同时在HTML菜单中选定相应的内容,此时单击内容则表示选定了该元素,图标高亮取消。如图(二)所示:
-
控制台
JS里面的console.log系列函数的打印就是在这里输出。 - HTML
HTML内容,注意这里看到的不一定是采集要解析的内容,采集时候对内容的分析,一律以查看源码(Ctrl+U)为准,这里只是能快速定位元素的结构,然后再选择一个比较特殊的参照,在源码中定位相应的位置。
比如,你在HTML里面看到一个标签是<div id="demo" class="demo">Demo</div>
,但是你查看源码时候看到的内容可能是<div class="demo" id="demo">Demo</div>
,如果你对采集内容按照前者去做正则匹配,那么你会得不到结果。 - CSS
这里是CSS文件内容 - 脚本
这里是Javascript文件内容 - DOM
Dom节点内容 - 网络
每一个请求链接的数据,这里是我们采集要关注和分析的地方,它能够显示每一个请求的参数、请求头、Cookie数据等。在页面提交会刷新的情况下,需要使用保持,使得页面请求内容在刷新后仍然留着控制台中,如图(三)所示:
另外,火狐还有一款 Tamper data 扩展也能得到请求数据,必要时可以安装使用。 - Cookies
Cookie数据
在图(一)中还看到下面有很多可选的小菜单项,其中保持是我们要关注的,当选择它的时候,即使提交表单刷新了页面,下面内容区域的数据还是会保留,这个对于分析提交数据特别关键。
总结
我们在分析采集请求的时候,主要关心“网络”菜单里的请求数据,必要时候使用“保持”以查看刷新页面的请求数据,请求前可以使用“清除”先清除下面的内容。
案例解析
一、简单的采集
这里所指的简单采集,是指一个单一页面GET请求的采集,它简单得即使通过file_get_contents函数也能轻松获得页面返回结果。
- 代码片段之file_get_contents
<?php
$url = 'upload/201704101114577826.jpg" class="popupImg" style="color: rgb(0, 136, 204); text-decoration: none;">
然后下面是我们的代码:
<?php
$keyword = 'PHP cURL';
//参数方法一
// $post = 'wd=' . urlencode($keyword);
//参数方法二
$post = array(
'wd' => urlencode($keyword),
);
$url = 'upload/201704101115013055.jpg" class="popupImg" style="color: rgb(0, 136, 204); text-decoration: none;">
还好最后功夫不负有心人,还是找到了,它就是CURLOPT_ENCODING参数。
比如,采集搜狐的新闻时候就遇到gzip压缩问题,下面是示例:<?php
$url = 'upload/201704101115053346.png" class="popupImg" style="color: rgb(0, 136, 204); text-decoration: none;">
这个时候,可以使用:
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
关于CURLOPT_FOLLOWLOCATION,手册说明是:
启用时会将服务器服务器返回的"Location: "放在header中递归的返回给服务器,使用CURLOPT_MAXREDIRS可以限定递归返回的数量。
我个人理解,通俗点讲就是后面的跳转会继续跟踪访问,而且cookie在header里面被保留了下来。
十、模拟上传文件
(一)基于本地文件上传
在PHP手册的curl_setopt函数中,关于CURLOPT_POSTFIELDS有如下描述:
全部数据使用HTTP协议中的"POST"操作来发送。要发送文件,在文件名前面加上@前缀并使用完整路径。这个参数可以通过urlencoded后的字符串类似'para1=val1¶2=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');
注: PHP 5.5.0起,文件上传建议使用CURLFile代替@
$ch = curl_init('upload/201704101115067834.png" class="popupImg" style="color: rgb(0, 136, 204); text-decoration: none;">
第一条发送的是json格式的数据,
第二条发送的是以\n
分割的数据,
第三条发送的是以&
分割的数据。
这个在ajax请求的时候,只需要添加contentType参数即可,如:var data = ["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参数,示例:
<?php
#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:'));
总结
通用curl页面采集函数:PHP通用curl页面采集函数
简易解析cURL命令得到PHP代码程序:简易解析cURL命令得到PHP代码程序
PHP cURL是一个很强大的采集工具,curl_setopt里面还有很多参数,读者可以抽空整体看一遍,虽然平时未必用得上,但是至少做到心里有底,知道都有哪些参数,必要时还能找出来使用。
采集是一项大工程,使用过程中遇到的问题还会不少,但是只要学会分析和资料搜索,一切都会迎刃而解的,大家加油!哈哈~~
原文地址:PHP cURL实现模拟登录与采集使用方法详解教程,首发自 Zjmainstay学习笔记
-