前回の記事「楽天市場ジャンル情報をMySQLに保存」で楽天ジャンルを取得できたので、今回は楽天ランキングを取得する処理を作成してみました。
楽天総合ランキングを保存
楽天ランキングを取得するAPI詳細はこちらから確認できます。
<?php define('DB_HOST', 'MySQLホスト'); define('DB_NAME', 'データベース名'); define('DB_USER', 'ユーザー名'); define('DB_PASS', 'パスワード'); define('DB_TABLE', '登録するテーブル名'); define('R_APID', '楽天アプリID'); //処理時間無制限に設定 set_time_limit(0); ini_set('max_execution_time', 0); //HTTP出力文字コードの設定 mb_http_output('UTF-8'); date_default_timezone_set('Asia/Tokyo'); header('Content-Type: text/html; charset=UTF-8'); $tableName = DB_TABLE; $r_id=R_APID; $dsn = 'mysql:dbname=' . DB_NAME . ';host=' . DB_HOST . ';charset=utf8;'; $pdo = null; try { $pdo = new PDO($dsn, DB_USER, DB_PASS); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); $pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false); } catch (PDOException $e) { die($e->getMessage()); } //テーブルの存在チェック $row=null; $stmt = $pdo->query("SHOW TABLES LIKE '{$tableName}' "); while($result = $stmt->fetch(PDO::FETCH_ASSOC)){ $row[] = $result; } $stmt = NULL; //テーブルが存在しない場合 if($row == null) { $sql=<<<EOF CREATE TABLE `{$tableName}` ( `RankDate` date NOT NULL COMMENT '取得日付', `BaseGenreId` varchar(10) NOT NULL COMMENT '取得ジャンルID', `rank` decimal(5,0) NOT NULL COMMENT '順位', `carrier` int(1) NOT NULL COMMENT 'キャリア', `itemName` varchar(255) NOT NULL COMMENT '商品名', `catchcopy` varchar(255) NOT NULL COMMENT 'キャッチコピー', `itemCode` varchar(50) NOT NULL COMMENT '商品コード', `itemPrice` decimal(10,0) NOT NULL COMMENT '商品価格', `itemCaption` text NOT NULL COMMENT '商品説明文', `itemUrl` varchar(255) NOT NULL COMMENT '商品URL', `affiliateUrl` varchar(255) NOT NULL COMMENT 'アフィリエイトURL', `imageFlag` int(1) NOT NULL COMMENT '商品画像有無フラグ', `ImageUrls1` varchar(255) NOT NULL COMMENT '商品画像', `ImageUrls2` varchar(255) NOT NULL COMMENT '商品画像', `ImageUrls3` varchar(255) NOT NULL COMMENT '商品画像', `availability` int(1) NOT NULL COMMENT '販売可能フラグ', `taxFlag` int(1) NOT NULL COMMENT '消費税フラグ', `postageFlag` int(1) NOT NULL COMMENT '送料フラグ', `creditCardFlag` int(1) NOT NULL COMMENT 'クレジットカード利用可能フラグ', `shopOfTheYearFlag` int(1) NOT NULL COMMENT 'ショップオブザイヤーフラグ', `shipOverseasFlag` int(1) NOT NULL COMMENT '海外配送フラグ', `shipOverseasArea` text NOT NULL COMMENT '海外配送対象地域', `asurakuFlag` int(1) NOT NULL COMMENT 'あす楽フラグ', `asurakuClosingTime` varchar(10) NOT NULL COMMENT 'あす楽〆時間', `asurakuArea` text NOT NULL COMMENT 'あす楽配送対象地域', `affiliateRate` decimal(5,0) NOT NULL COMMENT 'アフィリエイト利用利率', `startTime` datetime NOT NULL COMMENT '販売開始時刻', `endTime` datetime NOT NULL COMMENT '販売終了時刻', `reviewCount` decimal(10,0) NOT NULL COMMENT 'レビュー件数', `reviewAverage` decimal(2,0) NOT NULL COMMENT 'レビュー平均', `pointRate` decimal(3,0) NOT NULL COMMENT '商品別ポイント倍付け', `pointRateStartTime` datetime NOT NULL COMMENT '商品別ポイント倍付け開始日時', `pointRateEndTime` datetime NOT NULL COMMENT '商品別ポイント倍付け終了日時', `shopName` varchar(200) NOT NULL COMMENT '店舗名', `shopCode` varchar(100) NOT NULL COMMENT '店舗コード', `shopUrl` varchar(255) NOT NULL COMMENT '店舗URL', `genreId` varchar(10) NOT NULL COMMENT 'ジャンルID' ) ENGINE=InnoDB DEFAULT CHARSET=utf8; EOF; $pdo->exec($sql); $pdo->exec("ALTER TABLE `{$tableName}` ADD PRIMARY KEY (`RankDate`,`itemCode`,`BaseGenreId`) USING BTREE, ADD KEY `RankDate` (`RankDate`,`BaseGenreId`);"); } $d = function($a,$k) { $rec = ''; if($a==null) return $rec; if(is_array($a)) { if(array_key_exists((string)$k,(array)$a)){ $rec = mb_convert_encoding($a[$k], 'UTF-8'); } } return $rec; }; $s=0; $URL = "https://app.rakuten.co.jp/services/api/IchibaItem/Ranking/20170628?applicationId={$r_id}&formatVersion=2&genreId="; $date = date("Y/m/d"); $sql = <<<EOF REPLACE INTO {$tableName} (`RankDate`,`BaseGenreId`, `rank`, `carrier`, `itemName`, `catchcopy`, `itemCode`, `itemPrice`, `itemCaption`, `itemUrl`, `affiliateUrl`, `imageFlag`, `ImageUrls1`, `ImageUrls2`, `ImageUrls3`, `availability`, `taxFlag`, `postageFlag`, `creditCardFlag`, `shopOfTheYearFlag`, `shipOverseasFlag`, `shipOverseasArea`, `asurakuFlag`, `asurakuClosingTime`, `asurakuArea`, `affiliateRate`, `startTime`, `endTime`, `reviewCount`, `reviewAverage`, `pointRate`, `pointRateStartTime`, `pointRateEndTime`, `shopName`, `shopCode`, `shopUrl`, `genreId`) VALUES (:RankDate, :BaseGenreId, :rank, :carrier, :itemName, :catchcopy, :itemCode, :itemPrice, :itemCaption, :itemUrl, :affiliateUrl, :imageFlag, :ImageUrls1, :ImageUrls2, :ImageUrls3, :availability, :taxFlag, :postageFlag, :creditCardFlag, :shopOfTheYearFlag, :shipOverseasFlag, :shipOverseasArea, :asurakuFlag, :asurakuClosingTime, :asurakuArea, :affiliateRate, :startTime, :endTime, :reviewCount, :reviewAverage, :pointRate, :pointRateStartTime, :pointRateEndTime, :shopName, :shopCode, :shopUrl, :genreId) EOF; $gid = 0; for($page=1;$page<= 34;$page++) { $json = json_decode(file_get_contents($URL.$gid.'&page='.$page,true),true); $rows = $d($json,'Items'); unset($json); if(is_array($rows)) { //$ParentID = $d($d($json,'current'),'genreId'); for($i=0;count($rows) > $i;$i++) { $stmt = $pdo->prepare($sql); $stmt->bindValue(':RankDate',$date,PDO::PARAM_STR); $stmt->bindValue(':BaseGenreId',$gid,PDO::PARAM_STR); $stmt->bindValue(':rank',$d($rows[$i],'rank'),PDO::PARAM_INT); $stmt->bindValue(':carrier',$d($rows[$i],'carrier'),PDO::PARAM_INT); $stmt->bindValue(':itemName',$d($rows[$i],'itemName'),PDO::PARAM_STR); $stmt->bindValue(':catchcopy',$d($rows[$i],'catchcopy'),PDO::PARAM_STR); $stmt->bindValue(':itemCode',$d($rows[$i],'itemCode'),PDO::PARAM_STR); $stmt->bindValue(':itemPrice',$d($rows[$i],'itemPrice'),PDO::PARAM_INT); $stmt->bindValue(':itemCaption',$d($rows[$i],'itemCaption'),PDO::PARAM_STR); $stmt->bindValue(':itemUrl',$d($rows[$i],'itemUrl'),PDO::PARAM_STR); $stmt->bindValue(':affiliateUrl',$d($rows[$i],'affiliateUrl'),PDO::PARAM_STR); $stmt->bindValue(':imageFlag',$d($rows[$i],'imageFlag'),PDO::PARAM_INT); $stmt->bindValue(':ImageUrls1',$d($rows[$i]['mediumImageUrls'],0),PDO::PARAM_STR); $stmt->bindValue(':ImageUrls2',$d($rows[$i]['mediumImageUrls'],1),PDO::PARAM_STR); $stmt->bindValue(':ImageUrls3',$d($rows[$i]['mediumImageUrls'],2),PDO::PARAM_STR); $stmt->bindValue(':availability',$d($rows[$i],'availability'),PDO::PARAM_INT); $stmt->bindValue(':taxFlag',$d($rows[$i],'taxFlag'),PDO::PARAM_INT); $stmt->bindValue(':postageFlag',$d($rows[$i],'postageFlag'),PDO::PARAM_INT); $stmt->bindValue(':creditCardFlag',$d($rows[$i],'creditCardFlag'),PDO::PARAM_INT); $stmt->bindValue(':shopOfTheYearFlag',$d($rows[$i],'shopOfTheYearFlag'),PDO::PARAM_INT); $stmt->bindValue(':shipOverseasFlag',$d($rows[$i],'shipOverseasFlag'),PDO::PARAM_INT); $stmt->bindValue(':shipOverseasArea',$d($rows[$i],'shipOverseasArea'),PDO::PARAM_STR); $stmt->bindValue(':asurakuFlag',$d($rows[$i],'asurakuFlag'),PDO::PARAM_INT); $stmt->bindValue(':asurakuClosingTime',$d($rows[$i],'asurakuClosingTime'),PDO::PARAM_STR); $stmt->bindValue(':asurakuArea',$d($rows[$i],'asurakuArea'),PDO::PARAM_STR); $stmt->bindValue(':affiliateRate',$d($rows[$i],'affiliateRate'),PDO::PARAM_INT); $stmt->bindValue(':startTime',$d($rows[$i],'startTime'),PDO::PARAM_STR); $stmt->bindValue(':endTime',$d($rows[$i],'endTime'),PDO::PARAM_STR); $stmt->bindValue(':reviewCount',$d($rows[$i],'reviewCount'),PDO::PARAM_INT); $stmt->bindValue(':reviewAverage',$d($rows[$i],'reviewAverage'),PDO::PARAM_INT); $stmt->bindValue(':pointRate',$d($rows[$i],'pointRate'),PDO::PARAM_INT); $stmt->bindValue(':pointRateStartTime',$d($rows[$i],'pointRateStartTime'),PDO::PARAM_STR); $stmt->bindValue(':pointRateEndTime',$d($rows[$i],'pointRateEndTime'),PDO::PARAM_STR); $stmt->bindValue(':shopName',$d($rows[$i],'shopName'),PDO::PARAM_STR); $stmt->bindValue(':shopCode',$d($rows[$i],'shopCode'),PDO::PARAM_STR); $stmt->bindValue(':shopUrl',$d($rows[$i],'shopUrl'),PDO::PARAM_STR); $stmt->bindValue(':genreId',$d($rows[$i],'genreId'),PDO::PARAM_STR); $stmt->execute(); $stmt=null; unset($rows[$i]); } } //0.5秒待機 usleep(300000); } ?>
ランキングデータは、日付別(RankDate項目)で蓄積できるようにしました。
また取得したジャンルID(BaseGenreId項目)についても保持するようにしました。
その他ジャンルのランキング保存
一応作成はしたのですがジャンルIDが17,506種類あり、これらを全34ページ取得するとなると595,204ページ読み込みが必要になります。
また1ページあたり15商品が掲載されてますので、1日あたりに取得するレコード数が膨大になります(;^_^A
一応作成したソースが下記になります。
<?php define('DB_HOST', 'MySQLホスト'); define('DB_NAME', 'データベース名'); define('DB_USER', 'ユーザー名'); define('DB_PASS', 'パスワード'); define('DB_TABLE', '登録するテーブル名'); define('DB_MASTER', 'ジャンルIDマスタ名'); define('R_APID', '楽天アプリID'); //処理時間無制限に設定 set_time_limit(0); ini_set('max_execution_time', 0); //HTTP出力文字コードの設定 mb_http_output('UTF-8'); date_default_timezone_set('Asia/Tokyo'); header('Content-Type: text/html; charset=UTF-8'); $tableName = DB_TABLE; $MasterTable = DB_MASTER; $r_id=R_APID; $dsn = 'mysql:dbname=' . DB_NAME . ';host=' . DB_HOST . ';charset=utf8;'; $pdo = null; try { $pdo = new PDO($dsn, DB_USER, DB_PASS); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); $pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false); } catch (PDOException $e) { die($e->getMessage()); } $d = function($a,$k) { $rec = ''; if($a==null) return $rec; if(is_array($a)) { if(array_key_exists((string)$k,(array)$a)){ $rec = mb_convert_encoding($a[$k], 'UTF-8'); } } return $rec; }; $s=0; $URL = "https://app.rakuten.co.jp/services/api/IchibaItem/Ranking/20170628?applicationId={$r_id}&formatVersion=2&genreId="; $date = date("Y/m/d"); $sql=<<<EOF SELECT A.ID FROM {$MasterTable} AS A WHERE not EXISTS(SELECT * FROM {$tableName} AS B WHERE B.BaseGenreId=A.ID AND B.RankDate=:RankDate) LIMIT 200 EOF; $gids = array(); $stmt = $pdo->prepare($sql); $stmt->bindValue(':RankDate',$date,PDO::PARAM_STR); if($stmt->execute()) { while($row = $stmt->fetch(PDO::FETCH_ASSOC)){ $gids[] = $row['ID']; } } $sql = <<<EOF REPLACE INTO {$tableName} (`RankDate`,`BaseGenreId`, `rank`, `carrier`, `itemName`, `catchcopy`, `itemCode`, `itemPrice`, `itemCaption`, `itemUrl`, `affiliateUrl`, `imageFlag`, `ImageUrls1`, `ImageUrls2`, `ImageUrls3`, `availability`, `taxFlag`, `postageFlag`, `creditCardFlag`, `shopOfTheYearFlag`, `shipOverseasFlag`, `shipOverseasArea`, `asurakuFlag`, `asurakuClosingTime`, `asurakuArea`, `affiliateRate`, `startTime`, `endTime`, `reviewCount`, `reviewAverage`, `pointRate`, `pointRateStartTime`, `pointRateEndTime`, `shopName`, `shopCode`, `shopUrl`, `genreId`) VALUES (:RankDate, :BaseGenreId, :rank, :carrier, :itemName, :catchcopy, :itemCode, :itemPrice, :itemCaption, :itemUrl, :affiliateUrl, :imageFlag, :ImageUrls1, :ImageUrls2, :ImageUrls3, :availability, :taxFlag, :postageFlag, :creditCardFlag, :shopOfTheYearFlag, :shipOverseasFlag, :shipOverseasArea, :asurakuFlag, :asurakuClosingTime, :asurakuArea, :affiliateRate, :startTime, :endTime, :reviewCount, :reviewAverage, :pointRate, :pointRateStartTime, :pointRateEndTime, :shopName, :shopCode, :shopUrl, :genreId) EOF; for($gcnt=0;count($gids) > $gcnt;$gcnt++) { $gid = $gids[$gcnt]; unset($gids[$gcnt]); for($page=1;$page<= 3;$page++) { $json = json_decode(file_get_contents($URL.$gid.'&page='.$page,true),true); $rows = $d($json,'Items'); unset($json); if(is_array($rows)) { //$ParentID = $d($d($json,'current'),'genreId'); for($i=0;count($rows) > $i;$i++) { $stmt = $pdo->prepare($sql); $stmt->bindValue(':RankDate',$date,PDO::PARAM_STR); $stmt->bindValue(':BaseGenreId',$gid,PDO::PARAM_STR); $stmt->bindValue(':rank',$d($rows[$i],'rank'),PDO::PARAM_INT); $stmt->bindValue(':carrier',$d($rows[$i],'carrier'),PDO::PARAM_INT); $stmt->bindValue(':itemName',$d($rows[$i],'itemName'),PDO::PARAM_STR); $stmt->bindValue(':catchcopy',$d($rows[$i],'catchcopy'),PDO::PARAM_STR); $stmt->bindValue(':itemCode',$d($rows[$i],'itemCode'),PDO::PARAM_STR); $stmt->bindValue(':itemPrice',$d($rows[$i],'itemPrice'),PDO::PARAM_INT); $stmt->bindValue(':itemCaption',$d($rows[$i],'itemCaption'),PDO::PARAM_STR); $stmt->bindValue(':itemUrl',$d($rows[$i],'itemUrl'),PDO::PARAM_STR); $stmt->bindValue(':affiliateUrl',$d($rows[$i],'affiliateUrl'),PDO::PARAM_STR); $stmt->bindValue(':imageFlag',$d($rows[$i],'imageFlag'),PDO::PARAM_INT); $stmt->bindValue(':ImageUrls1',$d($rows[$i]['mediumImageUrls'],0),PDO::PARAM_STR); $stmt->bindValue(':ImageUrls2',$d($rows[$i]['mediumImageUrls'],1),PDO::PARAM_STR); $stmt->bindValue(':ImageUrls3',$d($rows[$i]['mediumImageUrls'],2),PDO::PARAM_STR); $stmt->bindValue(':availability',$d($rows[$i],'availability'),PDO::PARAM_INT); $stmt->bindValue(':taxFlag',$d($rows[$i],'taxFlag'),PDO::PARAM_INT); $stmt->bindValue(':postageFlag',$d($rows[$i],'postageFlag'),PDO::PARAM_INT); $stmt->bindValue(':creditCardFlag',$d($rows[$i],'creditCardFlag'),PDO::PARAM_INT); $stmt->bindValue(':shopOfTheYearFlag',$d($rows[$i],'shopOfTheYearFlag'),PDO::PARAM_INT); $stmt->bindValue(':shipOverseasFlag',$d($rows[$i],'shipOverseasFlag'),PDO::PARAM_INT); $stmt->bindValue(':shipOverseasArea',$d($rows[$i],'shipOverseasArea'),PDO::PARAM_STR); $stmt->bindValue(':asurakuFlag',$d($rows[$i],'asurakuFlag'),PDO::PARAM_INT); $stmt->bindValue(':asurakuClosingTime',$d($rows[$i],'asurakuClosingTime'),PDO::PARAM_STR); $stmt->bindValue(':asurakuArea',$d($rows[$i],'asurakuArea'),PDO::PARAM_STR); $stmt->bindValue(':affiliateRate',$d($rows[$i],'affiliateRate'),PDO::PARAM_INT); $stmt->bindValue(':startTime',$d($rows[$i],'startTime'),PDO::PARAM_STR); $stmt->bindValue(':endTime',$d($rows[$i],'endTime'),PDO::PARAM_STR); $stmt->bindValue(':reviewCount',$d($rows[$i],'reviewCount'),PDO::PARAM_INT); $stmt->bindValue(':reviewAverage',$d($rows[$i],'reviewAverage'),PDO::PARAM_INT); $stmt->bindValue(':pointRate',$d($rows[$i],'pointRate'),PDO::PARAM_INT); $stmt->bindValue(':pointRateStartTime',$d($rows[$i],'pointRateStartTime'),PDO::PARAM_STR); $stmt->bindValue(':pointRateEndTime',$d($rows[$i],'pointRateEndTime'),PDO::PARAM_STR); $stmt->bindValue(':shopName',$d($rows[$i],'shopName'),PDO::PARAM_STR); $stmt->bindValue(':shopCode',$d($rows[$i],'shopCode'),PDO::PARAM_STR); $stmt->bindValue(':shopUrl',$d($rows[$i],'shopUrl'),PDO::PARAM_STR); $stmt->bindValue(':genreId',$d($rows[$i],'genreId'),PDO::PARAM_STR); $stmt->execute(); $stmt=null; unset($rows[$i]); } } } } ?>
58行目で、「LIMIT 200」としています。
全てのジャンルIDに対して処理を行うと、多大な時間が掛かるため200件分のみ行うようにしました。
またすでにランキングを取得済のジャンルIDについては、除外するようにしましたので、この処理を何度も実行するとである程度の情報を取得できるかと思います。
また80行目で「$page<= 3」としています。
こちらも最大3ページ分のみ取得するようにしました。
まとめ
楽天ジャンルIDを取得するときにも薄々気づいてましたが、全てのジャンルに対してランキングを取得するには、複数の楽天APIアプリIDを用意して、並列にて行うしか無いかと思われます。
待機処理(usleep)を無効にすれば、速度的には早くなりますが、一定時間利用すると楽天側からアクセスを止められてしまいます。
今回の目的としてはw2uiのサンプルを作成することですので、総合ランキングの情報を利用していければと思います。