[{"data":1,"prerenderedAt":323},["ShallowReactive",2],{"$ft6jtkd6xhw3c":3,"$f5q2471qfh32m":263},{"featured":4,"latest":129,"categories":227},[5,14,27,37,48,56,66,76,86,96,106,114,122],{"slug":6,"title":7,"date":8,"excerpt":9,"image":10,"categories":11},"custom-database-tables","Custom DataBase Tables","2015-11-24T02:29:34","You can create the new own table freely in the your WordPress database via this plugin. Then, you can make the management of table or (as view or entry or edit) data in a simple user interface.\\nAlso,","\u002Fassets\u002Fuploads\u002F2016\u002F02\u002Fcdbt-overview.png",[12],{"slug":13,"name":7},"cdbt",{"slug":15,"title":16,"date":17,"excerpt":18,"image":19,"categories":20},"10_php_tips_for_developers","PHP開発者が心得ておくべき10の鉄則","2016-01-11T18:38:09","PHPだけに限った話ではないが、プログラミングを行うに当たって、心得て、準備しておくと失敗が劇的に減る事柄をまとめてある良い記事を見つけたので、私なりの解釈で意訳しつつ、経験則を踏まえてあらためてまとめてみた。 オリジナ…","\u002Fassets\u002Fuploads\u002F2016\u002F01\u002Feyecatch-php-10-tips.jpg",[21,24],{"slug":22,"name":23},"column","コラム",{"slug":25,"name":26},"development","開発関連",{"slug":28,"title":29,"date":30,"excerpt":31,"image":32,"categories":33},"jquery-timeline-v1","2種類の横型タイムラインを簡単に作成できる「jQuery.Timeline」をリリース","2017-05-29T14:55:46","現在開発しているサービスで利用するべく、横型タイムラインを生成できるjQueryプラグインを自作したので、そこだけ単独でリリースしてみた。 ソースコード等はGitHubの方にリリースしてあるので、興味のある方は、そち…","\u002Fassets\u002Fuploads\u002F2017\u002F05\u002Fjquery_timeline_image.png",[34],{"slug":35,"name":36},"jqtl","jQuery.Timeline",{"slug":38,"title":39,"date":40,"excerpt":41,"image":42,"categories":43},"optimize-browser-cache-of-static-resources","更新されたJS、CSS、画像のみブラウザキャッシュを破棄して読み込ませる","2018-01-31T15:47:47","WEBサービスの保守や開発をやっていると、JavaScriptやスタイルシート、画像などの静的リソースを更新した際、しばしば「確認したけど、更新されてないよ」とか云われて、「ブラウザのキャッシュを消してからもう一度見て…",null,[44,47],{"slug":45,"name":46},"codes","コード集",{"slug":25,"name":26},{"slug":49,"title":50,"date":51,"excerpt":52,"image":53,"categories":54},"jquery-timeline","jQuery.Timeline version2 – full documentation","2019-03-04T20:40:48","Plugin Overview The jQuery.Timeline plugin provides you two types of the horizontal timeline. You can create a…","\u002Fassets\u002Fuploads\u002F2019\u002F03\u002Fjquery.timeline_v2.jpg",[55],{"slug":35,"name":36},{"slug":57,"title":58,"date":59,"excerpt":60,"image":61,"categories":62},"released-the-sloth","Released the Sloth of mobile-first CSS micro framework!","2019-04-16T18:04:25","I released the “Sloth” that is mobile-first CSS micro framework. I have long used frontend framewo…","\u002Fassets\u002Fuploads\u002F2019\u002F04\u002Fsloth_doc_head.png",[63],{"slug":64,"name":65},"sloth","Sloth",{"slug":67,"title":68,"date":69,"excerpt":70,"image":71,"categories":72},"challenge-to-conceal-the-wordpress-site","WordPressサイトを徹底的に秘匿化する","2020-02-02T23:59:58","私は自分の個人サイトをはじめ、仕事でもWordPressサイトを運用している。WordPressは気軽にサイトを立ち上げられてカスタマイズも簡単な、素晴らしいオープンソースなのだが、世界中で使われまくっているその知名度…","\u002Fassets\u002Fuploads\u002F2020\u002F02\u002Fshutterstock_1878005929.jpg",[73],{"slug":74,"name":75},"wordpress","WordPress関連",{"slug":77,"title":78,"date":79,"excerpt":80,"image":81,"categories":82},"what-is-forkor","Made a shortened URL app called Forkor","2020-07-07T22:27:01","What’s Forkor? Forkor is a service that provides a shortened URL feature that allows you to redirect any…","\u002Fassets\u002Fuploads\u002F2020\u002F07\u002Fforkor.png",[83],{"slug":84,"name":85},"forkor","Forkor",{"slug":87,"title":88,"date":89,"excerpt":90,"image":91,"categories":92},"manual-about-svg-japan","インタラクティブな日本地図を生成するJSプラグイン「SVG Japan」","2020-11-16T21:19:58","各都道府県をそれぞれ選択・クリック可能なインタラクティブな日本地図を生成するネイティブJavaScript建てのプラグイン「SVG Japan」を作ったので、その紹介と使い方をまとめておく。ちなみにソースコードはgit…","\u002Fassets\u002Fuploads\u002F2020\u002F11\u002Fsvg-japan.png",[93],{"slug":94,"name":95},"svg-japan","SVG Japan",{"slug":97,"title":98,"date":99,"excerpt":100,"image":101,"categories":102},"wp-ignitor-plugin-to-conceal-wordpress-site","WordPressサイトを秘匿化するプラグイン「WP Ignitor」","2021-01-19T15:28:21","以前「WordPressサイトを徹底的に秘匿化する」という記事で、WordPress建てのサイトを秘匿化する方法を取り上げたのだが、あれをサイト構築時に毎度実施するとなるととても労力が必要であった。そこで、もっとお手軽…","\u002Fassets\u002Fuploads\u002F2021\u002F01\u002Fbanner-1554x500-1.png",[103],{"slug":104,"name":105},"wp-ignitor","WPイグナイタ",{"slug":107,"title":108,"date":109,"excerpt":110,"image":111,"categories":112},"tastewp","無料でWordPressサイトを複数作成できるWEBサービス「TasteWP」","2021-03-25T20:21:59","私が日本語翻訳に協力しているWEBサービス「TasteWP」について紹介しようと思う。 https:\u002F\u002Ftastewp.com このサービス、サインアップすることなく無料で自分用のWordPressサイトを作れるとい…","\u002Fassets\u002Fuploads\u002F2021\u002F03\u002FTasteWP_screenshot.png",[113],{"slug":74,"name":75},{"slug":115,"title":116,"date":117,"excerpt":118,"image":119,"categories":120},"monster-hunter-rise-skill-simulator","モンハンライズのスキルシミュレータを作ってみた！","2021-06-28T20:24:52","コラムで連載していたNintendo Switch版『モンスターハンターライズ』のスキルシミュレータ開発がやっと一段落して一通り完了した。いやぁ、記事書きながら同時並行で開発すると思っていた以上に時間がかかるもんだなぁ…","\u002Fassets\u002Fuploads\u002F2021\u002F06\u002Fmhrss_v100.png",[121],{"slug":25,"name":26},{"slug":123,"title":124,"date":125,"excerpt":126,"image":42,"categories":127},"comparison-of-javascript-date-libraries","JavaScriptの日時ライブラリを比較してみた","2021-07-28T22:39:19","ネイティブJavaScriptで日時を取り扱う場合、ビルトインされているDateオブジェクトを使うことになるのだが、このDateオブジェクトは取り扱いにクセが多く、直感的に日時を操作できない点でも有名である。そこで、専…",[128],{"slug":25,"name":26},[130,141,153,165,175,184,192,195,198,206,213,220],{"slug":131,"title":132,"date":133,"excerpt":134,"image":135,"categories":136},"pulllog_launched","ガチャ履歴を記録・分析できるWebサービス「PullLog」","2025-08-22T13:05:30","このたび、新しい個人開発サービスとして 「PullLog（プルログ）」 をリリースした。 URLはこちら https:\u002F\u002Fpulllog.net PullLogとは？ PullLogは、ソーシャルゲームのガチャ履歴を記録…","\u002Fassets\u002Fuploads\u002F2025\u002F08\u002Fpulllog_stats_jp.png",[137,140],{"slug":138,"name":139},"industries","プロダクト",{"slug":25,"name":26},{"slug":142,"title":143,"date":144,"excerpt":145,"image":146,"categories":147},"mockapi-php-openapi-schema-generation","モックAPIのレスポンスから OpenAPI 3.0 スキーマを自動生成するPHPツール","2025-04-17T09:31:52","私自身がそうなのですが、OpenAPI仕様書を毎回手作業で書いていて「面倒だな」と思ったことはありませんか？ そんな（私と）あなたにぴったりのツールがあります。 レスポンスの例さえ用意すれば、OpenAPI 3.0 スキ…","\u002Fassets\u002Fuploads\u002F2025\u002F04\u002Fswaggerui-preview.png",[148,151,152],{"slug":149,"name":150},"mockapi-php","MockAPI-PHP",{"slug":138,"name":139},{"slug":25,"name":26},{"slug":154,"title":155,"date":156,"excerpt":157,"image":158,"categories":159},"ambient_playlist_customize","Ambientでメメントモリのラメントプレイヤーを作る","2023-11-30T17:32:39","「Ambient」の最新バージョン 1.2.0で実装した「疑似フェーダー」機能を使って、ソーシャルゲーム「メメントモリ」のYouTube公式チャンネルで公開されているMVを集約したラメント専用プレイヤーを作ってみた。 ラ…","\u002Fassets\u002Fuploads\u002F2023\u002F11\u002Fambient_mememori_1.png",[160,163,164],{"slug":161,"name":162},"ambient","Ambient",{"slug":138,"name":139},{"slug":25,"name":26},{"slug":166,"title":167,"date":168,"excerpt":169,"image":170,"categories":171},"released_ambient_demo_version","Ambientメディアプレイヤーのクラウド版デモを公開","2023-11-22T13:47:36","つい先日「Ambient」の最新バージョン 1.1.0をリリースして、それに合わせてクラウド版デモサイトも公開してみた。 なお、クラウド版デモでローカルのホストコンピュータのメディアを再生するには、そのメディアファイルも…","\u002Fassets\u002Fuploads\u002F2023\u002F10\u002FAmbientMediaPlayer-typologo.png",[172,173,174],{"slug":161,"name":162},{"slug":138,"name":139},{"slug":25,"name":26},{"slug":176,"title":177,"date":178,"excerpt":179,"image":170,"categories":180},"ambient-media-player","YouTubeと自分のPC内メディアを同時に再生できるメディアプレイヤーを作ってみた","2023-10-20T00:00:25","私はよくPCで何か作業をするときには音楽を垂れ流していることが多い。 そういう時にかける曲は、手持ちのアルバムCD等からPCに取り込んだ音源だったり、さらにはYouTubeの動画だったりとメディアや再生環境がバラバラだ。…",[181,182,183],{"slug":161,"name":162},{"slug":138,"name":139},{"slug":25,"name":26},{"slug":185,"title":186,"date":187,"excerpt":188,"image":189,"categories":190},"what-is-the-sunorhc","Sunorhc is a date-time library for JavaScript","2021-08-25T22:55:55","Sunorhc is a lightweight library for handling dates and times for JavaScript. The library wraps a native JavaS…","\u002Fassets\u002Fuploads\u002F2021\u002F08\u002Fshutterstock_1091212919_resized.jpg",[191],{"slug":25,"name":26},{"slug":123,"title":124,"date":125,"excerpt":126,"image":42,"categories":193},[194],{"slug":25,"name":26},{"slug":115,"title":116,"date":117,"excerpt":118,"image":119,"categories":196},[197],{"slug":25,"name":26},{"slug":199,"title":200,"date":201,"excerpt":202,"image":203,"categories":204},"mhrise-skill-simulator-creation-chapter-12","モンスターハンターライズのスキルシミュレータを作ってみる！ 第12回","2021-06-21T13:11:46","今回は「マイセット登録」と護石データの「エクスポート／インポート」機能の追加をしていく。折り良く（悪く？）「FF7リメイク・インターグレード」や「FORTNITEシーズン7」が出たこともあって、そっちをプレイしてたらこ…","\u002Fassets\u002Fuploads\u002F2021\u002F04\u002Fb6ca09e9a7f6faf27641f62dabe64c6ff97b4f326aa478379e3c112aa28eb9ab.jpg",[205],{"slug":22,"name":23},{"slug":207,"title":208,"date":209,"excerpt":210,"image":203,"categories":211},"mhrise-skill-simulator-creation-chapter-11","モンスターハンターライズのスキルシミュレータを作ってみる！ 第11回","2021-06-07T14:52:31","さて、今回はユーザー個別データの管理部分を開発していく予定だが、まずその前にやっておくことがある。 新スキル「風雷合一」に対応する Ver.3.0の大型無料アップデートで追加された新スキルに「風雷合一」というのがある…",[212],{"slug":22,"name":23},{"slug":214,"title":215,"date":216,"excerpt":217,"image":203,"categories":218},"mhrise-skill-simulator-creation-chapter-10","モンスターハンターライズのスキルシミュレータを作ってみる！ 第10回","2021-06-02T00:29:10","今回は、護石管理画面の作成だ。この護石管理では、ユーザーごとに護石の登録を行う機能と、登録した護石を削除する機能を持つ仕様になる。この画面から登録した護石データはデータベースに格納するので、フロントエンド側からのリクエス…",[219],{"slug":22,"name":23},{"slug":221,"title":222,"date":223,"excerpt":224,"image":203,"categories":225},"mhrise-skill-simulator-creation-chapter-9","モンスターハンターライズのスキルシミュレータを作ってみる！ 第9回","2021-05-22T23:56:27","さて、今回はVuexによるデータ・キャッシュの実装だ。一度データベースから読み込んだデータをフロントエンド側で再利用可能なストアに格納することで、データベースへの接続回数を減らしてシステム負荷を下げるとともに、UX的な…",[226],{"slug":22,"name":23},[228,230,232,236,238,239,240,241,242,244,247,248,250,252,254,258,261],{"slug":161,"name":162,"count":229},3,{"slug":13,"name":7,"count":231},7,{"slug":233,"name":234,"count":235},"csnp","Custom Sticky Notes",2,{"slug":84,"name":85,"count":237},1,{"slug":35,"name":36,"count":229},{"slug":149,"name":150,"count":237},{"slug":64,"name":65,"count":237},{"slug":94,"name":95,"count":237},{"slug":74,"name":75,"count":243},37,{"slug":245,"name":246,"count":237},"wpqt","WP Qiita",{"slug":104,"name":105,"count":237},{"slug":22,"name":23,"count":249},29,{"slug":45,"name":46,"count":251},16,{"slug":138,"name":139,"count":253},5,{"slug":255,"name":256,"count":257},"lifelog","ライフログ",64,{"slug":259,"name":260,"count":235},"uncategorized","未分類",{"slug":25,"name":26,"count":262},45,{"type":264,"post":265},"post",{"slug":266,"title":267,"date":268,"excerpt":269,"image":42,"categories":270,"modified":273,"html":274,"tags":275,"related":288,"prev":308,"next":315},"compared-to-goutte-and-phpquery-of-scraping-library-for-php","PHPのWebスクレイピング・ライブラリ「Goutte」と「phpQuery」を比較してみた","2015-02-02T12:06:34","Custom DataBase Tablesなど自作のWordPressプラグインを公式SVNに登録していると、ダウンロード状況等のステータスを毎度WordPress.orgまで見に行くのが億劫になってくるのはオレだけだ…",[271,272],{"slug":22,"name":23},{"slug":25,"name":26},"2021-02-03T20:42:30","\u003Cp>Custom DataBase Tablesなど自作のWordPressプラグインを公式SVNに登録していると、ダウンロード状況等のステータスを毎度WordPress.orgまで見に行くのが億劫になってくるのはオレだけだろうか。で、自動でこっちのブログ側にその情報だけスクレイピングしてきて表示しちまえば楽できてイイだろうなぁ…とか思ったわけ。\u003C\u002Fp>\n\u003Cp>しかし、スクレイピングかぁ…。\u003Cbr \u002F>\nオレ的にスクレイピング=鬼門なんだよねぇ（笑）\u003Cbr \u002F>\n以前、自前でスクレイピング処理を書くのはやったことがあるんだが、その時はソース元のHTMLが汚かったこともあって、非常に面倒だった記憶だけが強烈に残っているのがその原因。まぁ、他所のサイトの、しかも一世代前のXHTMLあたりで書かれた（おそらくシステムが自動で吐き出していると思われる）構造だけが複雑なHTMLのパース処理をコーディングをしていると、モチベーションがただひたすらに下がっていくんだよねぇ…。\u003Cbr \u002F>\nああいう苦い経験は今回はしたくない。\u003C\u002Fp>\n\u003Cp>そんなわけで、今回はPHPのスクレイピングツールを利用して、サクっと作ってみようと思った次第。検索してみたところ、引っかかった中では「Goutte」と「phpQuery」が一番使い易そうだった。今回の記事では、この二つのライブラリでスクレイピング処理を書いて、実際に動かして、ベンチマーク取ってみて比較してみた。\u003C\u002Fp>\n\u003Ch2>導入状況を比較\u003C\u002Fh2>\n\u003Cp>まず、それぞれのライブラリのスペックを比較してみる。\u003C\u002Fp>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth align=\"center\">＼\u003C\u002Fth>\n\u003Cth align=\"center\">Goutte\u003C\u002Fth>\n\u003Cth align=\"center\">phpQuery\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd align=\"center\">配布元\u003C\u002Ftd>\n\u003Ctd align=\"center\">\u003Ca href=\"https:\u002F\u002Fgithub.com\u002FFriendsOfPHP\u002FGoutte\">https:\u002F\u002Fgithub.com\u002FFriendsOfPHP\u002FGoutte\u003C\u002Fa>\u003C\u002Ftd>\n\u003Ctd align=\"center\">\u003Ca href=\"https:\u002F\u002Fcode.google.com\u002Fp\u002Fphpquery\u002F\">https:\u002F\u002Fcode.google.com\u002Fp\u002Fphpquery\u002F\u003C\u002Fa>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd align=\"center\">インストール方法\u003C\u002Ftd>\n\u003Ctd align=\"center\">実行ファイルをインクルード\u003C\u002Ftd>\n\u003Ctd align=\"center\">実行ファイルをインクルード\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd align=\"center\">実行ファイル名\u003C\u002Ftd>\n\u003Ctd align=\"center\">\u003Cstrong>goutte.phar\u003C\u002Fstrong> \u003Cbr \u002F>(Pharアーカイブ形式)\u003C\u002Ftd>\n\u003Ctd align=\"center\">\u003Cstrong>phpQuery-onefile.php\u003C\u002Fstrong> \u003Cbr \u002F>(PHPファイル)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd align=\"center\">ファイルサイズ\u003C\u002Ftd>\n\u003Ctd align=\"center\">720KB\u003C\u002Ftd>\n\u003Ctd align=\"center\">164KB\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd align=\"center\">最新バージョン\u003C\u002Ftd>\n\u003Ctd align=\"center\">2.0\u003C\u002Ftd>\n\u003Ctd align=\"center\">0.9.5\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd align=\"center\">推奨PHPバージョン\u003C\u002Ftd>\n\u003Ctd align=\"center\">5.4 以降\u003C\u002Ftd>\n\u003Ctd align=\"center\">5.2 以降\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd align=\"center\">必要な依存ライブラリ\u003C\u002Ftd>\n\u003Ctd align=\"center\">Guzzle 4.*\u003C\u002Ftd>\n\u003Ctd align=\"center\">特になし\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd align=\"center\">備考\u003C\u002Ftd>\n\u003Ctd align=\"center\">PHP 5.3系で利用する場合はGoutte1.0.6+Guzzle3が必要\u003C\u002Ftd>\n\u003Ctd align=\"center\">CLIもあり、コマンドラインからも利用できる\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>\u003Cem>※ 2015年1月30日時点\u003C\u002Fem>\u003C\u002Fp>\n\u003Cp>導入のし易さとしては、特に依存関係のあるライブラリもなく、対応するPHPバージョンも幅があるので、 \u003Ccode>phpQuery\u003C\u002Fcode> の方にやや軍配が上がるかなぁ。まぁ、\u003Ccode>Goutte\u003C\u002Fcode> にしてもコマンド一発で依存系含めてインストールできるので、特に導入に手間取ることはなかっし、導入時のスペック差はあまりないという印象だ。\u003C\u002Fp>\n\u003Ch2>コーディング仕様を比較\u003C\u002Fh2>\n\u003Cp>ここでは実際にコードを見てもらうのが早いかと思うので、それぞれのライブラリで同じ処理を書いてみた。処理内容としては、WordPress.org の任意のプラグイン（テーマも可）のステータス状況のページから各種利用状況系のデータだけを取得して、再利用し易いPHPの配列に格納するという、まぁWebスクレイピングを使った、いわゆるクローラー的な処理である。\u003C\u002Fp>\n\u003Cp>まずは、 \u003Cstrong>Goutteを利用したスクレイピング処理\u003C\u002Fstrong> の例:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>&lt;?php\n\u002F\u002F Plugin Name\n$extend_type = 'plugins'; \u002F\u002F or themes\n$extend_name = 'custom-database-tables';\n\nrequire_once '\u002Fwp-content\u002Fthemes\u002Fmy_theme\u002Flib\u002Fvendor\u002Fgoutte.phar';\n\nuse GoutteClient;\n\n\u002F\u002F Create Goutte Object\n$client = new Client();\n\n\u002F\u002F Get Data Source\n$crawler = $client-&gt;request('GET', \"https:\u002F\u002Fwordpress.org\u002F{$extend_type}\u002F{$extend_name}\u002Fstats\u002F\");\n\n\u002F\u002F Get DOM Objects\n$plugin_title = $crawler-&gt;filter('div#plugin-title h2');\nif ($extend_type == 'plugins') {\n    $contents_path = 'div#pagebody div.wrapper div.col-10 div div.col-3 p';\n} else {\n    $contents_path = 'div#fyi ul';\n}\n$sidebar_info = $crawler-&gt;filter($contents_path);\n$history = $crawler-&gt;filter('div#history');\n\n$stats = array(ucfirst(rtrim($extend_type, 's')) . ' Name' =&gt; $plugin_title-&gt;text());\n\n$sidebar_info-&gt;each(function ($node) use ($extend_type, &amp;$stats) {\n    $labels = array();\n\n    $text_source = $node-&gt;text();\n\n    $children = $node-&gt;filter('strong');\n    $children-&gt;each(function ($node) use (&amp;$labels) {\n        $labels[] = $node-&gt;text();\n    });\n\n    foreach (array_reverse($labels) as $label) {\n        if (preg_match(\"\u002F{$label}\u002F\", $text_source)) {\n            list($text_source, $value) = explode($label, $text_source);\n            $label = rtrim(trim($label), ':');\n            if ($extend_type == 'themes') {\n                list($value, ) = preg_split('\u002F[s]{1,}\u002F', trim($value));\n            }\n            $stats[$label] = trim($value);\n        }\n    }\n\n});\n\n$history-&gt;each(function ($node) use (&amp;$stats) {\n    $labels = array();\n\n    $rows = $node-&gt;filter('tr');\n    $rows-&gt;each(function ($node) use (&amp;$stats) {\n        $key = trim($node-&gt;filter('th')-&gt;text());\n        $value = trim($node-&gt;filter('td')-&gt;text());\n        $stats[$key] = $value;\n    });\n\n});\n\nvar_dump($stats);\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>次に、\u003Cstrong>phpQueryを利用したスクレイピング処理\u003C\u002Fstrong> の例:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>&lt;?php\n\u002F\u002F Plugin Name\n$extend_type = 'plugins'; \u002F\u002F or themes\n$extend_name = 'custom-database-tables';\n\nrequire_once '\u002Fwp-content\u002Fthemes\u002Fmy_theme\u002Flib\u002Fvendor\u002FphpQuery-onefile.php';\n\n\u002F\u002F Get Data Source\n$html = file_get_contents(\"https:\u002F\u002Fwordpress.org\u002F{$extend_type}\u002F{$extend_name}\u002Fstats\u002F\");\n\n\u002F\u002F Get DOM Object\n$dom = phpQuery::newDocument($html);\n\n\u002F\u002F Parse DOM Objects\n$plugin_title = $dom['div#plugin-title h2'];\nif ($extend_type == 'plugins') {\n    $contents_path = 'div#pagebody div.wrapper div.col-10 div div.col-3 p:first';\n} else {\n    $contents_path = 'div#fyi ul';\n}\n$sidebar_info = $dom[$contents_path];\n$history = $dom['div#history table'];\n\n$stats = array(ucfirst(rtrim($extend_type, 's')) . ' Name' =&gt; $plugin_title-&gt;text());\n\n$text_source = $sidebar_info-&gt;text();\n$labels = array();\nforeach ($sidebar_info-&gt;find('strong') as $label) {\n    $labels[] = pq($label)-&gt;text();\n}\n\nforeach (array_reverse($labels) as $label) {\n    if (preg_match(\"\u002F{$label}\u002F\", $text_source)) {\n        list($text_source, $value) = explode($label, $text_source);\n        $label = rtrim(trim($label), ':');\n        if ($extend_type == 'themes') {\n            list($value, ) = preg_split('\u002F[s]{1,}\u002F', trim($value));\n        }\n        $stats[$label] = trim($value);\n    }\n}\n\nforeach ($history-&gt;find('tr') as $row) {\n    $key = trim(pq($row)-&gt;find('th')-&gt;text());\n    $value = trim(pq($row)-&gt;find('td')-&gt;text());\n    $stats[$key] = $value;\n}\n\nvar_dump($stats);\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>実行すると、どちらも下記のようにプラグインの利用状況をWordPress.orgから取得してきて、再利用し易いPHPの配列にスクレイピングしてくれる。\u003C\u002Fp>\n\u003Cp>\u003Cstrong>スクレイピング元となるWordPress.orgのプラグイン利用状況ページ\u003C\u002Fstrong>\u003Cbr \u002F>\n\u003Cimg data-recalc-dims=\"1\" decoding=\"async\" src=\"\u002Fassets\u002Fuploads\u002F2015\u002F01\u002Fweb_scraping_base.jpg\" alt=\"WordPress.orgのプラグイン利用状況ページ\" title=\"WordPress.orgのプラグイン利用状況ページ\" \u002F>\u003C\u002Fp>\n\u003Cp>\u003Cstrong>スクレイピングの結果\u003C\u002Fstrong>\u003Cbr \u002F>\n\u003Cimg data-recalc-dims=\"1\" decoding=\"async\" src=\"\u002Fassets\u002Fuploads\u002F2015\u002F01\u002Fweb_scraping_done.png\" alt=\"スクレイピング結果表示\" title=\"スクレイピング結果表示\" \u002F>\u003C\u002Fp>\n\u003Cp>コーディングのし易さでも、\u003Ccode>phpQuery\u003C\u002Fcode> の方がコード量が少なくて済むので扱い易い印象があった。 \u003Ccode>Goutte\u003C\u002Fcode> では名前空間を利用しているので、グローバル空間側で定義した変数などを \u003Ccode>Client\u003C\u002Fcode> クラスに受け渡す場合や、 \u003Ccode>Client\u003C\u002Fcode> クラス内のメソッドへ変数を受け渡す時などに、リファレンス扱いで参照渡ししないとそれぞれの名前空間のスコープで変数が共存できなかったりしてちょいと面倒だな…と感じた次第。まぁ、この辺は好き嫌いの範疇だなぁ…。\u003Cbr \u002F>\n特筆すべき点としては、スクレイピング元のURLからファイルを取得する処理の差だろうか。というのも、 \u003Ccode>Goutte\u003C\u002Fcode> では専用の \u003Ccode>request()\u003C\u002Fcode> メソッドがあって、そこでは\u003Ccode>GET\u003C\u002Fcode>以外に\u003Ccode>POST\u003C\u002Fcode>メソッドタイプにてファイル取得ができる点が優れている。これによってSubmit後にしか表示できないようなURLにも対応できる可能性があるのだ。一方で、 \u003Ccode>phpQuery\u003C\u002Fcode> ではファイル取得はライブラリに依存しない形で別途コーディングしないといけない。例では \u003Ccode>file_get_contents()\u003C\u002Fcode> 関数で取得しているが、POSTメソッドを指定してアクセスしたい場合などは結構手間が増えるかもしれない。\u003Cbr \u002F>\n取得したデータをDOMパースした後のコンテンツ捜査性については、どちらもあまり差はなく、CSSのセレクタ形式（jQueryのセレクタと同じ）のパスで要素を指定できる。そして、セレクタ形式パス指定で取得したDOMオブジェクト（PHPオブジェクト）に対してはメソッドを指定してデータ取得が行えるのも同じだ。まぁ、この部分の差があるとすれば、 \u003Ccode>phpQuery\u003C\u002Fcode> の方がJQueryのメソッド名に近しいので、jQuery知っているならこちらの方が扱い易い程度かなぁ。\u003C\u002Fp>\n\u003Ch2>パフォーマンスの比較\u003C\u002Fh2>\n\u003Cp>さて、ここでは前項で紹介した同じスクレイピング処理をパフォーマンスの点で比較してみた。まずは、処理時間からだ。\u003C\u002Fp>\n\u003Ch3>処理時間の比較\u003C\u002Fh3>\n\u003Cp>テスト内容としては、30回同じURLに対してスクレイピングリクエストを実行して、まず外部ライブラリを読み込んで初期化完了するまでの時間、次にURLリクエストの応答と取得データのDOMオブジェクトパース処理の時間、最後にコンテンツ捜査処理が完了するまでの時間、そしてトータルの全処理時間の平均値を出してみた。 \u003Ccode>Goutte\u003C\u002Fcode> のみPOSTメソッドでもスクレイピングを実行してみたので、その際の平均値は（）内に記載してある。\u003C\u002Fp>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth align=\"center\">＼\u003C\u002Fth>\n\u003Cth align=\"right\">Goutte\u003C\u002Fth>\n\u003Cth align=\"right\">phpQuery\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd align=\"center\">ライブラリ初期化\u003C\u002Ftd>\n\u003Ctd align=\"right\">0.001300057 (0.003100181)\u003C\u002Ftd>\n\u003Ctd align=\"right\">0.001366655\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd align=\"center\">URLリクエスト応答＋\u003Cbr \u002F>DOMオブジェクト生成\u003C\u002Ftd>\n\u003Ctd align=\"right\">0.716607642 (0.760643625)\u003C\u002Ftd>\n\u003Ctd align=\"right\">0.869116362\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd align=\"center\">コンテンツ捜査\u003C\u002Ftd>\n\u003Ctd align=\"right\">0.039035694 (0.039702058)\u003C\u002Ftd>\n\u003Ctd align=\"right\">0.016300988\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd align=\"center\">全処理合計\u003C\u002Ftd>\n\u003Ctd align=\"right\">0.756943393 (0.803445864)\u003C\u002Ftd>\n\u003Ctd align=\"right\">0.886784005\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>結果としては、 \u003Ccode>Goutte\u003C\u002Fcode> の方がパフォーマンスが良かった。URLリクエストで取得したデータ（html）からDOMオブジェクトを生成する処理で差が大きかった感じだ。なお、 \u003Ccode>Goutte\u003C\u002Fcode> では同一URLへのGETメソッドでのリクエストをキャッシュするようで、初回のリクエストより後は処理時間が短くなっていた（一方、POSTメソッドでは毎回同じような処理時間だった）。面白いのが、生成したDOMオブジェクトに対してのコンテンツ操作性能では \u003Ccode>phpQuery\u003C\u002Fcode> の方が優れていた点だ。捜査時間が \u003Ccode>Goutte\u003C\u002Fcode> の半分以下である。\u003Cbr \u002F>\n全体の処理時間性能としては \u003Ccode>Goutte\u003C\u002Fcode> に軍配が上がりそうだが、一度URLリクエスト応答して取得済みのオブジェクトから様々な異なるコンテンツ捜査を複数回行うような処理の場合は、コンテンツ捜査性能が高い \u003Ccode>phpQuery\u003C\u002Fcode> の方が有利になるかもしれない。\u003C\u002Fp>\n\u003Ch3>使用メモリの比較\u003C\u002Fh3>\n\u003Cp>テスト内容は前述の処理時間と一緒だが、回数重ねてもほぼ近似値しか得られなかったので、それぞれ10回ずつで検証してみた。\u003Cbr \u002F>\nなお、メモリの場合、プロセスに割り当てられるメモリの最大値に対して実プロセスでどれだけメモリを使用しているかを測ることで、そのアプリケーション（ライブラリ）がどの程度効率的にメモリを使っているのかとかもわかる。項目が多いのでそれぞれのライブラリでまとめてみる。\u003C\u002Fp>\n\u003Ch4>phpQuery の使用メモリ\u003C\u002Fh4>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth align=\"center\">＼\u003C\u002Fth>\n\u003Cth align=\"right\">使用メモリ量(KB)\u003C\u002Fth>\n\u003Cth align=\"right\">割り当てメモリ最大値(KB)\u003C\u002Fth>\n\u003Cth align=\"right\">メモリ効率\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd align=\"center\">ライブラリ初期化\u003C\u002Ftd>\n\u003Ctd align=\"right\">708.8133\u003C\u002Ftd>\n\u003Ctd align=\"right\">717.793\u003C\u002Ftd>\n\u003Ctd align=\"right\">98.75%\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd align=\"center\">URLリクエスト応答＋\u003Cbr \u002F>DOMオブジェクト生成\u003C\u002Ftd>\n\u003Ctd align=\"right\">36.04688\u003C\u002Ftd>\n\u003Ctd align=\"right\">41.8125\u003C\u002Ftd>\n\u003Ctd align=\"right\">86.21%\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd align=\"center\">コンテンツ捜査\u003C\u002Ftd>\n\u003Ctd align=\"right\">10.92188\u003C\u002Ftd>\n\u003Ctd align=\"right\">159.8391\u003C\u002Ftd>\n\u003Ctd align=\"right\">6.83%\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd align=\"center\">全処理合計\u003C\u002Ftd>\n\u003Ctd align=\"right\">755.782\u003C\u002Ftd>\n\u003Ctd align=\"right\">919.4445\u003C\u002Ftd>\n\u003Ctd align=\"right\">82.20%\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>コンテンツ捜査にかなり余裕を持ってメモリを割り当てている。だからコンテンツ捜査性能がいいんだねぇ…。まぁ、全体的にメモリ割り当て効率に無駄がなくて、賢いライブラリという印象を受けた。この辺はさすがGoogleと言ったところかな（笑）\u003C\u002Fp>\n\u003Ch4>Goutte の使用メモリ\u003C\u002Fh4>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth align=\"center\">＼\u003C\u002Fth>\n\u003Cth align=\"right\">使用メモリ量(KB)\u003C\u002Fth>\n\u003Cth align=\"right\">割り当てメモリ最大値(KB)\u003C\u002Fth>\n\u003Cth align=\"right\">メモリ効率\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd align=\"center\">ライブラリ初期化\u003C\u002Ftd>\n\u003Ctd align=\"right\">326.4375\u003C\u002Ftd>\n\u003Ctd align=\"right\">369.2656\u003C\u002Ftd>\n\u003Ctd align=\"right\">88.40%\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd align=\"center\">URLリクエスト応答＋\u003Cbr \u002F>DOMオブジェクト生成\u003C\u002Ftd>\n\u003Ctd align=\"right\">1217.562\u003C\u002Ftd>\n\u003Ctd align=\"right\">1266.816\u003C\u002Ftd>\n\u003Ctd align=\"right\">96.11%\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd align=\"center\">コンテンツ捜査\u003C\u002Ftd>\n\u003Ctd align=\"right\">410.6547\u003C\u002Ftd>\n\u003Ctd align=\"right\">375.4781\u003C\u002Ftd>\n\u003Ctd align=\"right\">109.37%\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd align=\"center\">全処理合計\u003C\u002Ftd>\n\u003Ctd align=\"right\">1954.654\u003C\u002Ftd>\n\u003Ctd align=\"right\">2011.56\u003C\u002Ftd>\n\u003Ctd align=\"right\">97.17%\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>うお！？ ちょっと、コンテンツ捜査処理で使用されるメモリが割り当て値を超えちゃってますよ（笑）これではせっかくその前までのプロセスがパフォーマンス良くても、ここの処理いかんでは詰まってしまう可能性があるかもねぇ。その辺が \u003Ccode>phpQuery\u003C\u002Fcode> よりコンテンツ捜査性能が悪い原因かもしれん。全処理としてのメモリ効率はかなりイイだけに、この内部プロセスのメモリ割り当てを最適化すればかなり良いパフォーマンスになるんではないだろうか？　しかし、まぁ \u003Ccode>Goutte\u003C\u002Fcode> は結構メモリ使うななぁ…。\u003C\u002Fp>\n\u003Cp>というわけで、使用メモリを比較した結果は、圧倒的に \u003Ccode>phpQuery\u003C\u002Fcode> の勝ちですな。\u003Cbr \u002F>\n\u003Ccode>Goutte\u003C\u002Fcode> でのスクレイピングは2MB程度のメモリを食うが、 \u003Ccode>phpQuery\u003C\u002Fcode> はその半分以下のメモリでサクサク動いているという感じ。\u003C\u002Fp>\n\u003Ch2>総評\u003C\u002Fh2>\n\u003Cp>なかなか甲乙付けがたい結果ではあるんだが、あえて判定するなら、スクレイピング・ライブラリとしては \u003Ccode>phpQuery\u003C\u002Fcode> が僅差で勝ちって感じかなぁ。あくまで私の主観での総評になるが、比較結果は下記のようになるかと。\u003C\u002Fp>\n\u003Cul>\n\u003Cli>導入敷居の低さ： \u003Cstrong>phpQuery\u003C\u002Fstrong> > Goutte （依存系ライブラリがなく、素で対応するPHPバージョンが多い）\u003C\u002Fli>\n\u003Cli>コーディング： \u003Cstrong>phpQuery\u003C\u002Fstrong> ≒ \u003Cstrong>Goutte\u003C\u002Fstrong> （コード量では \u003Ccode>phpQuery\u003C\u002Fcode> だが、機能面では \u003Ccode>Goutte\u003C\u002Fcode> の方がやや優秀か）\u003C\u002Fli>\n\u003Cli>パフォーマンス（処理時間）： phpQuery &lt; \u003Cstrong>Goutte\u003C\u002Fstrong> （今回は総処理時間で \u003Ccode>Goutte\u003C\u002Fcode> に分があったが、コンテンツ捜査処理いかんでは逆転するリスクを含んでいる）\u003C\u002Fli>\n\u003Cli>パフォーマンス（使用メモリ）： \u003Cstrong>phpQuery\u003C\u002Fstrong> > Goutte （使用メモリ効率として97%の \u003Ccode>Goutte\u003C\u002Fcode> は無駄がなくて良いのだが、総メモリ使用量と各プロセスにおける割り当てメモリの分配の仕方は \u003Ccode>phpQuery\u003C\u002Fcode> の方が優秀だった）\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>どっちを使うかは好み次第だなぁ…という結論になった。\u003Cbr \u002F>\nちなみにオレは、jQuery好きなことも手伝って、 \u003Ccode>phpQuery\u003C\u002Fcode> を選ぼうかと。使用メモリ量が少なくて済むしね。\u003C\u002Fp>\n",[276,279,282,285],{"slug":277,"name":278},"goutte","Goutte",{"slug":280,"name":281},"php","PHP",{"slug":283,"name":284},"phpquery","phpQuery",{"slug":286,"name":287},"scraping","Scraping",[289,293,298,303],{"slug":15,"title":16,"date":17,"excerpt":18,"image":19,"categories":290},[291,292],{"slug":22,"name":23},{"slug":25,"name":26},{"slug":142,"title":143,"date":144,"excerpt":145,"image":146,"categories":294},[295,296,297],{"slug":149,"name":150},{"slug":138,"name":139},{"slug":25,"name":26},{"slug":166,"title":167,"date":168,"excerpt":169,"image":170,"categories":299},[300,301,302],{"slug":161,"name":162},{"slug":138,"name":139},{"slug":25,"name":26},{"slug":176,"title":177,"date":178,"excerpt":179,"image":170,"categories":304},[305,306,307],{"slug":161,"name":162},{"slug":138,"name":139},{"slug":25,"name":26},{"slug":309,"title":310,"date":311,"excerpt":312,"image":42,"categories":313},"for-ajax-in-ruby-on-rails-part1","Ruby on RailsのAjax処理のおさらい","2015-01-20T19:41:34","何気に、アプリケーションで取り扱うデータ量が増えた場合や、大容量データをデータベースとやり取りする時なんかは、Ajaxを使ってデータ通信をバックエンド側に押しやることで、WEBフロント側のUXからパフォーマンスの悪さを改…",[314],{"slug":25,"name":26},{"slug":316,"title":317,"date":318,"excerpt":319,"image":320,"categories":321},"my-web-relations-map","マイWebリレーションマップ","2015-02-09T14:29:39","2015年2月現在、オレが常習的に利用しているWEB（サービス）のリレーションマップを作成してみた。 利用してるWebサービスが多くなりすぎて、一旦整理しようと思ったからだ。マップに含めなかったが、アカウント的には他に「…","\u002Fassets\u002Fuploads\u002F2015\u002F02\u002Fmy_web_relation_map.jpg",[322],{"slug":255,"name":256},1793391398604]