PHP 楽天とYahooショッピングの検索結果をページング処理


お世話になります。
以前(http://q.hatena.ne.jp/1375374890)色々教えていただき、検索結果は取得できたのですが、これをページングさせたく、再度質問させて頂きます。


<?php
~前略(前回と同じ)~

$yahoo_data = array();
foreach ($yxml->Result->Hit as $Hit) {
$yahoo_data[] = array('itemName'=>(string)$Hit->Name,
//~中略~
'yitemCount'=>(string)$totalResultsAvailable);
}

$merge_data = array_merge($rakuten_data,$yahoo_data);

//~中略(教えて頂いたソート方法)~

foreach(array_slice($merge_data,0,21) as $result) {
?>

<?=mb_substr($result[$itemName],0,25,'UTF-8')?>
//~中略~
<?php } ?>


この後にページング処理を入れたく、以下などを参考にしたのですがうまくいきません。
http://tenderfeel.xsrv.jp/php/639/
http://rasukaru55.sitemix.jp/pageing.php

検索結果の数を取得できないと話にならないと思い、

$totalResultsAvailable = $yxml->attributes()->totalResultsAvailable;
……
'yitemCount'=>(string)$totalResultsAvailable);

を入れることでヤフーの検索結果数は取得できたのですが、楽天はできていません。

できれば楽天の取得方法、又はページングの方法だけでもご教授いただけませんでしょうか。
文字数の関係で中略が多く恐縮です。

回答の条件
  • 1人50回まで
  • 登録:2013/08/13 00:03:12
  • 終了:2013/08/18 13:05:09

ベストアンサー

id:holoholobird No.1

holoholobird回答回数574ベストアンサー獲得回数1042013/08/13 03:27:01

ポイント500pt

$merge_dataにはソート済みの結果が格納されているのですよね?
例えば1ページ当たり30件のデータを表示する場合は、
nページ目の時には30*(n-1)から30件分取り出せばいいので、
では

<?php
//ページ番号取得。ないときには1ページ目を表示。
$page=1;
if(isset($_GET['page'])){
    $page=$_GET['page']);
}
//1件当たりの表示件数。30だと1ページにつき30件表示します。
$echo_num=30;
$start_num=$echo_num*($page-1);
:
foreach(array_slice($merge_data,$start_num,$echo_num) as $result) {
?>

<?=mb_substr($result[$itemName],0,25,'UTF-8')?>
//~中略~
<?php } ?>

でいいと思います。
30件ずつ表示する設定で1ページ目を表示してみると、
$start_num=0;$echo_num=30;となり、このとき
array_slice($merge_data,$start_num,$echo_num)

array_slice($merge_data,0,30)
と同値になります。

id:cafe-beret

ご回答いただきありがとうございます。

>$merge_dataにはソート済みの結果が格納されているのですよね?
ソート前のデータが入っています。


ココから
//この前に、楽天とYahooのデータを取得する処理
$merge_data = array_merge($rakuten_data,$yahoo_data);

function cmp_func($a, $b)
{
global $SORT_field;
$field = $SORT_field;
if ($a[$field] == $b[$field]) {
return 0;
}
return ($a[$field] < $b[$field]) ? -1 : 1;
}

$SORT_field = 'itemPrice';
usort($merge_data, "cmp_func");

foreach(array_slice($merge_data,0,21) as $result) {
?>


ココまで


という形です。 ご教授頂いたやり方で試してみたのですが、うまくいきませんでした。すみません。 GETで取得しているpageは、APIのパラメーターのpageということでしょうか?

2013/08/15 21:17:34

その他の回答(0件)

id:holoholobird No.1

holoholobird回答回数574ベストアンサー獲得回数1042013/08/13 03:27:01ここでベストアンサー

ポイント500pt

$merge_dataにはソート済みの結果が格納されているのですよね?
例えば1ページ当たり30件のデータを表示する場合は、
nページ目の時には30*(n-1)から30件分取り出せばいいので、
では

<?php
//ページ番号取得。ないときには1ページ目を表示。
$page=1;
if(isset($_GET['page'])){
    $page=$_GET['page']);
}
//1件当たりの表示件数。30だと1ページにつき30件表示します。
$echo_num=30;
$start_num=$echo_num*($page-1);
:
foreach(array_slice($merge_data,$start_num,$echo_num) as $result) {
?>

<?=mb_substr($result[$itemName],0,25,'UTF-8')?>
//~中略~
<?php } ?>

でいいと思います。
30件ずつ表示する設定で1ページ目を表示してみると、
$start_num=0;$echo_num=30;となり、このとき
array_slice($merge_data,$start_num,$echo_num)

array_slice($merge_data,0,30)
と同値になります。

id:cafe-beret

ご回答いただきありがとうございます。

>$merge_dataにはソート済みの結果が格納されているのですよね?
ソート前のデータが入っています。


ココから
//この前に、楽天とYahooのデータを取得する処理
$merge_data = array_merge($rakuten_data,$yahoo_data);

function cmp_func($a, $b)
{
global $SORT_field;
$field = $SORT_field;
if ($a[$field] == $b[$field]) {
return 0;
}
return ($a[$field] < $b[$field]) ? -1 : 1;
}

$SORT_field = 'itemPrice';
usort($merge_data, "cmp_func");

foreach(array_slice($merge_data,0,21) as $result) {
?>


ココまで


という形です。 ご教授頂いたやり方で試してみたのですが、うまくいきませんでした。すみません。 GETで取得しているpageは、APIのパラメーターのpageということでしょうか?

2013/08/15 21:17:34
id:cafe-beret

ご回答いただきありがとうございました。

結果的には、まだ処理できていないため、もう少し考えてみようと思います。

ありがとうございました。

  • id:rouge_2008
    「出力パラメーター」の項目を確認してみてください。
    「count」に検索結果の総商品数が入っているようです。

    http://webservice.rakuten.co.jp/api/ichibaitemsearch/
  • id:cafe-beret
    コメント頂きありがとうございます。

    $xml->Body->ItemSearch->count
    または
    $xml->Body->ItemSearch->Items->count

    で取得しようとしたのですが、できなかったため途方に暮れております…
  • id:cafe-beret
    度々すみません。以下で取得することが出来ました。


    header("Content-Type:text/plain;charset=UTF-8");
    $root = simplexml_load_file($file,'SimpleXMLElement',LIBXML_NOWARNING);

    print $root->Body->children('itemSearch',true)->ItemSearch->children("")->count;


    しかし、ページングはやはりできていません。。。
  • id:rouge_2008
    前回の質問でやりたい事を確認しましたが、双方の検索結果を混ぜた結果の中から30件を表示し、さらにページング処理を行って2ページ目以降を表示するのはかなり複雑な処理になると思います。
    1ページ目のデータをそれぞれ何件分取得しているのでしょう?

    http://q.hatena.ne.jp/1375374890
    ----------------------------------------------------------------------
    ■やりたいこと
    楽天とYahooショッピングの商品検索APIの結果を混ぜ、条件でソートした30件を表示。
    ----------------------------------------------------------------------


    Yahoo!ショッピングの商品検索APIで1回に取得できるのは20~50件です。

    http://developer.yahoo.co.jp/webapi/shopping/shopping/v1/itemsearch.html
    ----------------------------------------------------------------------
    hits integer
    (デフォルト:20) 取得する検索結果数。デフォルトは20、最大値は50。
    ----------------------------------------------------------------------


    楽天商品検索APIで1回に取得できるのは1~30件です。

    ----------------------------------------------------------------------
    1ページあたりの取得件数 hits int - 30 1から30までの整数
    ----------------------------------------------------------------------


    双方からそれぞれ15件ずつ取得した合計の30件をソートして表示するのでしたら可能だと思いますが、価格(?)など何らかの条件でのソートした結果を正確に30件ずつ表示したい場合は、かなり難しくなると思います。
    前回の質問を見る限り、結合後のデータから上位30件分を抜き出して表示しているようですので、前記の後者に該当すると思います。
    場合によってはページング処理は諦める必要があると思います。
  • id:cafe-beret
    rouge_2008さん

    ありがとうございます。
    仰るとおり、双方の結果をソートして、上限を決めることなく表示させてページングさせようとしております。

    やはりかなり難しいんですね。。
    ありがとうございます。

    もう少し自分の中でも噛み砕いてみたいと思います。

    ポイントを差し上げたいのですが、コメントにはできないんでしょうか。
    とにかく、ありがとうございました。
  • id:tobeoscontinue
    既に解決済みかもしれませんが
    ページング処理をする場合
    1:ある程度の商品点数を取り込んで自分でページング処理をする方法です。が多くの商品点数を取り込むと時間もかかりますし、それほど多くのページも閲覧されとは思われないので処理の割に効果が見込めないと思います。また多くの商品点数を毎回取り込むと無駄ですからキャッシュも必要かもしれません。
    2:ページ単位で商品点数を取り込む方法です。ソートの整合性は多少失われますがこれまでの処理の流れが使えます。

    2のやりかたで説明します。
    データを取り込む際にpageとhitsを指定できるようにします。またソートされた結果を取り込む必要があるのでsortも指定できるようにする必要があります。
    function pagingはhttp://tenderfeel.xsrv.jp/php/639/のものを使うものとします。
    パラメータとしてqueryとpageの二つが必要になります。
    index.php?query=vaio vaioを商品検索して1ページ目を表示します。(最初にアクセスする必要があります。)
    index.php?page=n 以前のqueryでnページ目を表示します。
    本来はindex.php?query=vaio&page=nとなったほうが簡単なのですがpageingを変更しないといけないのでsessionを使ってqueryの値を保存するという方法をとっています。

    sort項目として幾つかありますが共通するのはこの三つのようです。
    itemPrice | price
    reviewCount | review_count
    affiliateRat | affiliate


    前回はsortでグローバル変数を使って値を引き渡していたのですがPHP5.3から無名関数で設定済みの変数の値を引き継ぐuseというものが使えるようです。
    こちらの方が多少スマートのように思います。

    define ('RAKUTEN_SHOP','https://app.rakuten.co.jp/services/api/IchibaItem/Search/20130805?applicationId=??');
    define ('YAHOO_SHOP','http://shopping.yahooapis.jp/ShoppingWebService/V1/itemSearch?appid=??');
    // defineのRAKUTEN_SHOPとYAHOO_SHOPはアプリケーションIDやアフィリエイトID、その他などを付加あるいは変更する必要があります。
    // 楽天はバージョンによってurlが異なります。それによってxmlへのアクセス方法が異なるかもしれません。このコードでは20130805のものです。

    function rakuten_shop_api($query, $page, $hits, $s, $o='%2b') {
    $sort_key = array('ItemPrice'=>'itemPrice','ReviewCount'=>'reviewCount','affiliateRat'=>'affiliateRat');
    $url = RAKUTEN_SHOP.'&keyword='.urlencode($query).'&page='.$page.'&hits='.$hits.'&sort='.$o.$sort_key[$s];
    echo $url."<br>\n";
    $data = file_get_contents($url);
    return simplexml_load_string($data);
    }

    function yahoo_shop_api($query, $page, $hits, $s, $o='%2b') {
    $sort_key = array('ItemPrice'=>'price','ReviewCount'=>'review_count','affiliateRat'=>'affiliate');
    $offset = ($page-1)*$hits;
    $url = YAHOO_SHOP.'&query='.urlencode($query).'&offset='.$offset.'&hits='.$hits.'&sort='.$o.$sort_key[$s];
    echo 'yahoo='.$url."<br>\n";
    return simplexml_load_string(file_get_contents($url));
    }


    session_start();
    if (!isset($_SESSION["cafe"]))
    $_SESSION["cafe"] = array('',1,15,'ItemPrice'); // 最初のsessionでは初期値を設定します。
    list($query, $limit, $hits, $sort) = $_SESSION["cafe"];
    // sessionを使って$query, $limit, $hits, $sortの変数の値を引き継ぎます。

    if (isset($_GET["query"])) $query = $_GET["query"];

    $page = empty($_GET["page"]) ? 1 : intval($_GET["page"]); //ページ番号

    if ($page > $limit) $page = $limit; // limitの取扱いはあまり上手くありません。

    $xml = rakuten_shop_api($query, $page, $hits, $sort);
    # var_dump($xml);
    $data = array();
    foreach ($xml->Items->Item as $item) {
    $data[] = array('ItemName'=>(string)$item->itemName,
    'ItemPrice'=>(string)$item->itemPrice,
    'smallImageUrl'=>(string)$item->smallImageUrls->imageUrl,
    'affiliateUrl'=>(string)$item->affiliateUrl,
    'affiliateRat'=>(string)$item->affiliateRat,
    'ItemCaption'=>(string)$item->itemCaption,
    'ReviewCount'=>(string)$item->reviewCount);
    } // 楽天のデータを取り込み$dataに格納します。

    # var_dump($yxml);
    $yxml = yahoo_shop_api($query, $page, $hits, $sort);
    foreach ($yxml->Result->Hit as $Hit) {
    $data[] = array('ItemName'=>(string)$Hit->Name,
    'ItemPrice'=>(string)$Hit->Price,
    'smallImageUrl'=>(string)$Hit->Image->Small,
    'affiliateUrl'=>'',
    'affiliateRat'=>(string)$Hit->Affiliate->Rate,
    'ItemCaption'=>(string)$Hit->Description,
    'ReviewCount'=>(string)$Hit->Review->Count);
    }} // Yahooのデータを取り込み同じく$dataに格納します。そうすることでarray_mergeする必要が無くなりました。

    if (isset($_GET["query"])) $limit = floor(($xml->count + $yxml->attributes()->totalResultsAvailable + $hits - 1)/$hits);
    echo 'count='.$xml->count."<br>\n";
    echo 'totalResultsAvailable='.$yxml->attributes()->totalResultsAvailable."<br>\n";
    echo 'limit='.$limit."<br>\n";

    $_SESSION["cafe"] = array($query, $limit, $hits, $sort); // 現在の値を次回に引き継ぐためセッション変数に格納します。

    usort($data, function ($a, $b) use ($sort) {
    return ($a["$sort"] == $b["$sort"]) ? 0 :
    (($a["$sort"] < $b["$sort"]) ? -1 : 1);
    });

    foreach($data as $result) {
    echo mb_substr($result["ItemName"],0,25,'UTF-8').' '.$result["ItemPrice"]."円<br>";
    echo '<a href="'.$result["affiliateUrl"].'" target="blank"><img src="'.$result["smallImageUrl"].'"></a>';
    echo $result["ItemCaption"].'<br><br>';
    }

    paging($limit, $page, 10);
  • id:cafe-beret
    tobeoscontinueさん

    度々ありがとうございます。

    格が違うというか、自分にはとても思いつかない、思いつくとも思えない内容です。
    本当に感謝申し上げます。

    こちらを参考に、今一度構築してみます。
    できればポイントを差し上げたいのですが、できないようなので、カラースターというのを付けさせていただきました(これに価値があるのか、わからないのですが……)

    また何かありましたら、是非よろしくお願い致します。
  • id:cafe-beret
    tobeoscontinueさん

    度々申し訳ありません。

    usort($data, function ($a, $b) use ($sort) {
    return ($a["$sort"] == $b["$sort"]) ? 0 :
    (($a["$sort"] < $b["$sort"]) ? -1 : 1);
    });

    の部分でエラーが出るようなのですが、原因などお分かりになるでしょうか。
  • id:tobeoscontinue
    無名関数でuseが使えるのはPHP 5.3以降なのでバージョンの違いでしょうか。

    以前のcmp_funcで書き換えて下さい。
    ただ名前を$SORT_fieldから$sortと名前を変えたので書き換える必要があります。
    function cmp_func($a, $b)
    {
    global $sort;
    $field = $sort;
    if ($a[$field] == $b[$field]) {
    return 0;
    }
    return ($a[$field] < $b[$field]) ? -1 : 1;
    }
    とりあえず動作を確認するだけならusortしなくてもいいです。
    usortについては昇順、降順に対応するために今後も変更が必要になる部分です。
  • id:cafe-beret
    ありがとうございます。
    これで色々試させていただきます。

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません