curl采集设置CURLOPT_FOLLOWLOCATION不起作用的解决办法
curl抓取页面时,如果页面会发生301,302跳转,则需要对curl进行参数设置。
curl_setopt($ch, CURLOPT_MAXREDIRS,20);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION,1);
0
1
curl_setopt($ch,CURLOPT_MAXREDIRS,20);
curl_setopt($ch,CURLOPT_FOLLOWLOCATION,1);
CURLOPT_FOLLOWLOCATION即表示自动进行跳转抓取,CURLOPT_MAXREDIRS表示最多允许跳转多少次。
不过在使用时需要注意:CURLOPT_FOLLOWLOCATION需要在安全模式关闭未设置open_basedir的情况下才能使用。open_basedir是php.ini中的一项设置,功能是将用户可操作的文件限制在某目录下。
如果开户了安全模式,或者设置了open_basedir,则无法使用自动跳转抓取,此时可以采用连续抓取的办法来抓取最终页面。为加快速度和减少不必要的开销,可以在中间非目标页面的抓取过程中使用:
curl_setopt($rch, CURLOPT_HEADER, TRUE);
curl_setopt($rch, CURLOPT_NOBODY, TRUE);
0
1
curl_setopt($rch,CURLOPT_HEADER,TRUE);
curl_setopt($rch,CURLOPT_NOBODY,TRUE);
只抓取头信息,不抓取页面内容,对header信息的状态码(301,302)进行判断。如需跳转,则从Location中获取到跳转的地址,再次进行抓取,直至状态码为200状态。最后再对目标页面进行抓取。
下面是在我项目是摘出来的静态方法,仅供参考:
/**
* 以测试请求头信息开始,直到状态码返回200后才进行实际的采集工作
* @param string $url
* @param array $options
* @return array|bool|mixed
*/
public static function testCollect($url, $options=[])
{
$curl = curl_init();
$index = 5;
$headers = array(
"User-Agent" => self::$ua
);
if(!empty($options['headers'])){
$headers = $options['headers'];
}
while($index){
if(stripos($url,"https://")!==FALSE){
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($curl, CURLOPT_SSLVERSION, 1); //CURL_SSLVERSION_TLSv1
}
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_HEADER, TRUE);
curl_setopt($curl, CURLOPT_NOBODY, TRUE);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1 ); // 以文件流的形式返回
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
$content = curl_exec($curl);
$info = curl_getinfo($curl);
$code = $info['http_code'];
$headers['Referer'] = $url; // 当前链接就是下一个请求的来路
if($code == 301 || $code == 302 || $code == 303 || $code == 307){
if(!empty($info['redirect_url'])){
$url = $info['redirect_url'];
}else{
preg_match('/Location:(.*?)\n/', $content, $matches);
$url = trim(array_pop($matches));
}
$index--;
continue;
}
$index = 0;
}
self::$httpCode = $code;
if($code == 200){
$options['headers'] = $headers;
return self::get($url, $options); // 采集页面信息
}
curl_close($curl);
return [$code, $content];
}
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/**
* 以测试请求头信息开始,直到状态码返回200后才进行实际的采集工作
* @param string $url
* @param array $options
* @return array|bool|mixed
*/
publicstaticfunctiontestCollect($url,$options=[])
{
$curl=curl_init();
$index=5;
$headers=array(
"User-Agent"=>self::$ua
);
if(!empty($options['headers'])){
$headers=$options['headers'];
}
while($index){
if(stripos($url,"https://")!==FALSE){
curl_setopt($curl,CURLOPT_SSL_VERIFYPEER,FALSE);
curl_setopt($curl,CURLOPT_SSL_VERIFYHOST,FALSE);
curl_setopt($curl,CURLOPT_SSLVERSION,1);//CURL_SSLVERSION_TLSv1
}
curl_setopt($curl,CURLOPT_URL,$url);
curl_setopt($curl,CURLOPT_HEADER,TRUE);
curl_setopt($curl,CURLOPT_NOBODY,TRUE);
curl_setopt($curl,CURLOPT_RETURNTRANSFER,1);// 以文件流的形式返回
curl_setopt($curl,CURLOPT_HTTPHEADER,$headers);
$content=curl_exec($curl);
$info=curl_getinfo($curl);
$code=$info['http_code'];
$headers['Referer']=$url;// 当前链接就是下一个请求的来路
if($code==301||$code==302||$code==303||$code==307){
if(!empty($info['redirect_url'])){
$url=$info['redirect_url'];
}else{
preg_match('/Location:(.*?)\n/',$content,$matches);
$url=trim(array_pop($matches));
}
$index--;
continue;
}
$index=0;
}
self::$httpCode=$code;
if($code==200){
$options['headers']=$headers;
returnself::get($url,$options);// 采集页面信息
}
curl_close($curl);
return[$code,$content];
}
如果想做采集,也可以换一种语言采集,比如使用我的另一篇文章写的关于Python的scrapy框架采集