PHP爬虫之Curl

程序 精帖
2 668
caixiaoxu
2018-06-14

        说到爬虫,大家肯定立刻就想到python那边去了,但是PHP是世界上最好的语言,怎么可能小小的爬虫做不到呢,不存在的好吗

        爬虫,其实就是给定一个URL,分析链接,获取到页面所有信息,然后运用正则表达式获取链接中的内容(我比较喜欢说是洗数据),随着URL内容的更新,周而复始,将数据存储到数据库或指定文件中。

        最简单的PHP爬虫,是php自带的函数file_get_contents,可以将网页的页面信息抓取下来形成一个数组的格式,然后便可以通过正则的方式来截取自己想要的内容。但缺陷还是非常大,就是有安全认证的https网页,抓不了,渣的一批,不提。

        Curl,是正常php写爬取的时候调用的方法,相关的学习方法菜鸟很详细我不多说。

简单的粒子:

function getCurl($url){
$ch = curl_init();

//需要获取的URL地址,也可以在curl_init()函数中设置
curl_setopt($ch, CURLOPT_URL,$url);

//将curl_exec()获取的信息以文件流的形式返回,而不是直接输出
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);

//禁用后cURL将终止从服务端进行验证。使用CURLOPT_CAINFO选项设置证书使用CURLOPT_CAPATH
//选项设置证书目录 如果CURLOPT_SSL_VERIFYPEER(默认值为2)被启用,CURLOPT_SSL_VERIFYHOST需要被设置成TRUE否则设置为FALSE
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

//1 检查服务器SSL证书中是否存在一个公用名(common name)。译者注:
//公用名(Common Name)一般来讲就是填写你将要申请SSL证书的域名 (domain)或子域名(sub domain)。
//2 检查公用名是否存在,并且是否与提供的主机名匹配
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

// 抓取URL并把它传递给浏览器
$result = curl_exec($ch);

//关闭cURL资源,并且释放系统资源
curl_close ($ch);

return $result;
}

然后控制器调用此方法:

$contents =htmlspecialchars(getCurl($url)) ;

htmlspecialchars()是将预定义的字符转为实体。

        这样,你要的页面就拿下来了,然后接下来要做的就是洗数据,就是正则匹配然后截取你要的部分,但是正则这么反人类的东西我确实不太想去接触,还好php有几个函数可以配合一下,完成想要的效果。

        1、mb_strpos($str1,$str2)函数,他的功能是查找字符串str2在字符串str1中首次出现的位置,这里要注意了,首次出现,就是说后面再出现也不会管的。

        2、mb_strlen($str)函数,他的功能是返回数组长度。

        3、mb_substr($str,$begin,$length)函数,他的功能是返回$str从第$begin位开始长度为$length的字符串。

        然后我们就可以配合起来变成下面这个函数了,他的功能是将字符串$str,截取从$begin字符串开始到$end字符串结束的部分,返回的结果不包括$begin和$end。

//截取中间段,前后不要
function take_cut($begin,$end,$str){
$b = mb_strpos($str,$begin) + mb_strlen($begin);
$e = mb_strpos($str,$end) -$b;
return mb_substr($str,$b,$e);
}

        简单的打个比方,例如

$str      = "abcdefghigklnm";
$begin    = "cd";
$end      = "kl";

echo take_cut($begin,$end,$str);

        运行后输出的结果是 :efjhij

        当出现要截取的部分标识符出现多次重复不便截取的时候,例如:

$str      = "ABCDEFABCHIGZZZ";

        想截取第二个ABC后面的内容,那么你就得想将前面的ABC去掉,然后在进行第二次截取。

//砍掉前部分
function all_cut($begin,$str){
$b = mb_strpos($str,$begin) + mb_strlen($begin);
$e = mb_strlen($str) -$b;
return mb_substr($str,$b,$e);
}

        当然这里的这个两个函数只是打一个比方,你可以将函数多种姿势话,具体看你喜欢哪一种了,灵活运用才是真谛。这样,简单是网页内容就可以爬取到了。正常我们要爬网页的文章内容,都是根据标签(ul li div)、样式名称(class="contents")、关键性词语(来源 form)等等来匹配,具体看网页的内容来使用,尽量不大可能出现变动的标识符。这样,简单的爬取就结束了,是不是很简单,正常采用都是先爬取站点里面的链接,存入数据库,然后再进入链接里面爬,再将内容数据存到数据库里。

        出来页面信息,我们还可以将文件,等等存入到我本地的文件下,这里我举例将网页上的图片下载放到站点的目录下。

函数方法:

        图片链接:$file_url,保存地址:$save_to

function dlfile($file_url, $save_to)
{
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL,$file_url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    $result = curl_exec($ch);
    curl_close($ch);
    $downloaded_file = fopen($save_to, 'a');
    fwrite($downloaded_file, $result);
    fclose($downloaded_file);
}

        控制器方法调用:

        图片链接:$photo ,图片将保存的地址与名称:$save,我这里将图片保存在public/static/thumbnail目录下,命名为tu格式为jpg

$save  = 'public/static/thumbnail/tu.jpg';
dlfile($photo,$save);

        这样图片就保存到我们的目录下了,记得保留文件地址和文件名称(存到数据库),之后就可以调用了。

        好了,这两个已经够大部分人用了。

        下面要讲的是Curl如何仿造IP,防屏蔽终端的用法,这两个我还没验证过,转载自:https://www.cnblogs.com/grimm/p/5068048.html

1、简单一点的可以在header伪造X-FORWARDED-FOR,并伪造referer,代码如下:

curl_setopt($ch, CURLOPT_HTTPHEADER, array('X-FORWARDED-FOR:111.222.333.4', 'CLIENT-IP:111.222.333.4'));  
curl_setopt($ch, CURLOPT_REFERER, "http://www.test.com");  

2、上面的方法大多数能糊弄过去,但也有抓到了真实IP的。就使用代理,麻烦在于你有一个有效的代理ip和端口号,有的还需要用户名密码,代码如下:

curl_setopt($ch, CURLOPT_PROXY, "http://111.222.333.4:110");  

另外还有一种情况,就是用浏览器可以访问,用curl就是不行,发现对方检查了useragent,如果没有就认为是抓取等非法来源,那么我们就自己在header加上useragent,代码如下:

curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11");


回帖
  • 模拟提交下载文件:

    $post_data = array (
                "action"=>'download',
                "id" => '31967',
                "uhash"=>'30070d23d5fc436e313364f2'
            );
            $file_url = "https://www.";
            $save_to = 'public/static/torrent/1.torrent';
            //$data = 'action=download&id=31953&uhash=d7df48ad7404ac9dad998b68';
            $ret = curl_b($post_data,$file_url,$save_to);
            dump( $ret);
    function curl_b($data,$url,$save_to){
        $ch = curl_init();
        curl_setopt ($ch, CURLOPT_URL,$url);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt ($ch, CURLOPT_HEADER, 0);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
        $result = curl_exec ($ch);
        curl_close($ch);
        if ($result == NULL) {
            return 0;
        }
        $downloaded_file = fopen($save_to, 'a');
        fwrite($downloaded_file, $result);
        fclose($downloaded_file);
        return $result;
    }


    0 回复
  • file_get_contents获取https方法,没有验证过

    <code>$options = array(
                'http' => array(
                    'method' => 'POST',
                    'header' => 'Content-type:application/x-www-form-urlencoded;charset=UTF-8',
                    'content' => $stringData
                ),
                // 解决SSL证书验证失败的问题
                "ssl"=>array(
                    "verify_peer"=>false,
                    "verify_peer_name"=>false,
                )
            );
            $context = stream_context_create($options);
            $data = file_get_contents($url, false, $context);

    或者修改php.ini的poenssl扩展,将前面的分号删掉


    0 回复