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枚の画像を処理できるようになった。

まとめ

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

ReratedPosts

phpの開発環境用のローカルサーバーはビルトインウェブサーバーを使うと良い
PHPフレームワーク「CodeIgniter」のLoaderClassを読み解く
PHPのin_arrayの第3引数にはtrueを使う方が良いという話
Ubuntu18.04.1にphpbrew+php7.2+apache2+MySQL5.7の開発環境を整える方法
phpの__autoload関数とかspl_autoload_registerについて理解したのでまとめておく
PHPでob_startの使い方とか使い道とか