PHPでスクレイピングの高速化にはfile_get_contensよりもcurlの方が良いよって話

表題の通り、PHPでスクレイピングをする際には、file_get_contentsよりもcurlの方が柔軟でかつ高速な処理ができるので紹介。

結論から言うと、以下のコードを使えば良い。

<?php
    function my_file_get_contents($url){  // 引数にはスクレピングしたいurlを入れる
        static $curl;
        if(empty($curl)){
            $curl = curl_init();     
            curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);  
            curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10);  
            $agent = 'Mozilla/5.0 (Windows NT 6.2; WOW64; rv:17.0) Gecko/20100101 Firefox/17.0';
            curl_setopt($curl, CURLOPT_USERAGENT, $agent);
        }

        curl_setopt($curl, CURLOPT_URL, $url);
        $html = curl_exec($curl); 
        
        return $html;
    }

開発環境

  • php 7.3
  • WIndows10

今回はWindows10の環境で試したが、別にLinuxでもMacでも同様の結果が得られる。また、ベンチマークをするために、以下の簡単なクラスを用意した。

<?php

class BenchMark {
    private $time_start;

    public function start(){
        $this->time_start = microtime(true);
    }

    public function end(){
        $time = microtime(true) - $this->time_start;
        echo "{$time} 秒";
    }
}

file_get_contentsでスクレイピングをする。

まずは、以下のコードのようにfile_get_contensを使って50枚の画像をスクレイピングしてみる。

<?php
    function my_file_get_contents($url){
        $html = file_get_contents($url); 
        return $html;
    }

結果は116.4426138401 秒。50枚の画像でこれだとストレスが溜まるし、使い物にはならないだろう。

curlを使ってスクレピング

それでは、一般的にfile_get_contensよりも高速だと言われているcurlを使ってスクレイピングをしてみる。

<?php
    function my_file_get_contents($url){
        $curl = curl_init();   
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);  
        curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10);  
        $agent = 'Mozilla/5.0 (Windows NT 6.2; WOW64; rv:17.0) Gecko/20100101 Firefox/17.0';
        curl_setopt($curl, CURLOPT_USERAGENT, $agent);
        
        curl_setopt($curl, CURLOPT_URL, $url);
        $html = curl_exec($curl); 

        return $html;
    }

早くなるかと思いきや、結果は177.45514988899 秒と逆に遅くなっている。原因としては、2行目の$curl = curl_init();のcurlの初期化をしている部分にあって、新たな画像をスクレイピングする度に初期化をしているので、結果として遅くなってしまう。

curlの改善案

と言う事で、上記の改善案として、static変数を使うことっでcurlは1回しか初期化しないようにしてみる。

<?php
    function my_file_get_contents($url){
        static $curl;
        if(empty($curl)){
            $curl = curl_init();     
            curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);  
            curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10);  
            $agent = 'Mozilla/5.0 (Windows NT 6.2; WOW64; rv:17.0) Gecko/20100101 Firefox/17.0';
            curl_setopt($curl, CURLOPT_USERAGENT, $agent);
        }

        curl_setopt($curl, CURLOPT_URL, $url);
        $html = curl_exec($curl); 
        
        return $html;
    }

結果は、25.590156078339 秒とかなり高速になった。最終的には、1秒で2枚の画像を処理できるようになった。

まとめ

非同期処理を行えばもっと早くなるかなと感じているが、これは後で試す。