最近のやつはこちら

12月 9th, 2017

http://dasalog.hatenablog.jp/


GoutteでCSSセレクタが使えない場合のあれこれ

7月 4th, 2016

phpでスクレイピングといえばGoutte(特に内部で使用しているCssSelector)がちょう便利ですが、とはいえスクレイピング対象のページに都合よくidやclassが振られていなこともままありますね。

今回たまたま某生協の注文サイトから注文状況を取得した際にやったあれこれをいくつかメモ。

パラメータを書き換えてpost

postして遷移するページで、post直前にjsで値を書き換えてからpost、という動作をしている所があった。
細かくコードを追うのは面倒なので、実際にpostされた値に合わせる形でページから値をかき集めてsubmitさせる。
書き換えはsetValues、formからの値の取得はgetValuesで。

$form->disableValidation()->setValues(['osk'=> $prev, 'curosk' => $prev, 'odc' => $form->getValues()['curodc']]);
$this->crawler = $this->client->submit($form);

selectedな要素の次のoptionを選択

「前回の注文情報」というのを取るにあたり、同じURLでpostされたパラメータによって画面遷移するという箇所があったため、「一度現在の注文ページを開き、option要素がselectedになってる要素の次の要素を選択」という条件で取得してみた。

optionの場所が固定なら$crawler->eq(n)で取れるのだが可変なので、順序が保証されているという前提でこんな感じに対応。

<select name="osk">        
  <option value="20160702" >7月2回B週</option>
  <option value="20160701" selected="selected" >7月1回A週</option>
  <option value="20160605" >6月5回D週</option>
</select>

20160605が欲しい

$prev = $this->crawler->filter('.weekOrderSelect select option')->reduce(function($node, $i){
    // 直前のノードがselected
    return (count($node->previousAll()) && $node->previousAll()->first()->attr('selected') == 'selected');
})->attr('value'); 

previousAllが毎回呼ばれるのがイマイチ感がありますがまあこんな感じで。
一個前の取得はpreviousAll->last()ではなくfirst()でとれた。

余計な要素を除外

テーブルからのデータ取得で、よけいなtr(デザイン上の隙間的な何か)を除外。
reduceで頑張る。

$this->crawler->filter("table#wecpwa0010_{$parent} tbody tr")->reduce(function($node) {
            $item = $node->filter('tr.cartSubs');
            return count($item) === 0;
        })->each(function($node) use ($previous) {
            $item = [
                'name' => '',
                'price' => '',
                'quantity' => '',
            ];
/// 後続処理

reduceやeachで無名関数を渡すときはuseで外部変数も渡せるのでなかなかベンリですね。

毎度参考にしている諸々

WebスクレイピングライブラリGoutteで遊んでみる
http://d.hatena.ne.jp/hnw/20120115
hnwさんの2012年の記事ですがわかりやすい

The DomCrawler Component
http://symfony.com/doc/current/components/dom_crawler.html#node-filtering
公式のDomCrawlerドキュメント


phpでurldecodeとかを標準入力で受け取ってさくっと処理したい

12月 1st, 2015

$echo %3D | php -r 'echo(urldecode(file_get_contents("php://stdin")));'
=

file_get_contents(“php://stdin”)で標準入力を受け取れるのでこんな感じで。
(nkf入ってないけどphpあったよ、などの時にたまに役立つかもしれない)