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でURLのqueryの配列を作りたい時にはexplode関数を使えば良い感じになる
phpのextract関数の使い方とか逆のことをするcompact関数とかの解説
PHPのissetとis_null、emptyの違いや関係を調べてみる
PHPフレームワーク「CodeIgniter」のLoaderClassを読み解く
CentOS7にphpbrewとphpを入れてPHPの開発環境を構築する方法
PHPでob_startの使い方とか使い道とか