一年一度的苹果新品刚发布后的几天,9月12号就正式上市了,按照惯例,果农们又得在网上拼个你死我活了,香港苹果店在12号下午3点后正式开放购买,还没来得及写好脚本,经过不断的按F5和enter,不懈努力之下,抢到了1台!
抢收过后,特意写下这个脚本,监控苹果网上商店是否有货,有货第一时间发出邮件通知我,网上有类似的订阅服务,留个邮件地址也能收到相关的提醒,也有chrom或者firefox的插件能够在浏览器定时监控,有货第一时间发出窗口通知或者播放警告声。
此类服务的原理大多使用同一原理,就是发送get请求,获取苹果服务器的回应json字符串,判断里面的值,比如这次有isBuyable:true/false.获取方法有很多,比如我这次写的php,运行在服务器端,也能用javascript写,在浏览器定时运行,也能做成浏览器插件,接收来自服务器的返回信息并根据对应的回应进行相关的触发提醒。
至于怎么获取或者怎么知道苹果服务器的get url,有开发经验的童鞋肯定用过firefox 的firebug, 打开http://store.apple.com/hk-zh/buy-iphone/iphone6/ 购买的网页后,打开firebug,然后按照正常购买的流程,比如选择"iphone 6 plus"->"金色"->"64GB",留意这些选项都选中之后,在firebug的网络模块里可以看到浏览器发出了"http://store.apple.com/hk-zh/buyFlowSelectionSummary/IPHONE6P?node=home/shop_iphone/family/iphone6&step=select&option.dimensionScreensize=5_5inch&option.dimensionColor=gold&option.dimensionCapacity=128gb&option.carrierModel=UNLOCKED%2FWW&carrierPolicyType=UNLOCKED" 这样的请求,然后打开该请求的响应信息,内容很长,基本如下:
{"head":{"status":"200","data":{}}, "body":{"content":{"pageURL":"5.5-�嘉�幕-128gb-金色-已解�i", "selected":{"productImage":"<img src=\"http://store.storeimages.cdn-apple.com/7872/as-images.apple.com/is/image/AppleInc/aos/published/images/i/ph/iphone6p/gold/iphone6p-gold-select-2014_GEO_HK_LANG_ZH?wid=110&hei=78&fmt=jpeg&qlt=95&op_sharpen=0&resMode=bicub&op_usm=0.5,1.5,0,0&iccEmbed=0&layer=comp&.v=1410265171755\" alt=\"\" width=\"110\" height=\"78\" data-scale-params-2=\"wid=220&hei=156&fmt=jpeg&qlt=95&op_sharpen=0&resMode=bicub&op_usm=0.5,1.5,0,0&iccEmbed=0&layer=comp&.v=1410265171755\" itemprop=\"image\"/>", "productTitle":"iPhone 6 Plus 128GB 金色 已解�i", "purchaseOptions":{"financing":"\n\n\n\n\n\n", "promotions":"\n\n<span class=\"gift-card\">\n\n</span>\n", "shippingPrice":"\n<span class=\"freeshipping promo-text\">免�M�\送</span>", "shippingLead":"\n�A�出��r�g<b>:</b><br/>\n<span class=\"customer_commit_display\">��r�o法提供</span>\n\n", "price":"\n<span class=\"current_price\">\n<span itemscope=\"itemscope\" itemprop=\"offers\" itemtype=\"http://schema.org/Offer\">\n\n<meta itemprop=\"priceCurrency\" content=\"HKD\"/>\n<span itemprop=\"price\">\nHK$8,088\n</span>\n</span>\n</span>\n\n\n", "isBuyable":false}, "partNumber":"MGAF2ZP/A"}, "pageTitle":"iPhone 6 Plus 128GB 金色 已解�i - Apple Store (香港)"}}}
返回的json里面,包含了isBuyable的参数,估计苹果就是利用这个响应来判断是否有存货,并且来控制页面的操作。
知道这个原理后,就可以着手写脚本了,主要是用curl的api来发送请求,将返回的json转换为array,并判断该字段的值,false为无货,true为有货,代码已完成,摘录如下:
<?php $recipient="[email protected],[email protected],[email protected]"; $from="From: [email protected]\r\n"; $subject="iPhone6 available"; $headers = $from."Content-type: text/html\r\n"; $user_agent="Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0"; $iphone6=array( 0=>array('screensize'=>'4_7inch','color'=>'silver','capacity'=>'16gb'), 1=>array('screensize'=>'4_7inch','color'=>'space_gray','capacity'=>'16gb'), 2=>array('screensize'=>'4_7inch','color'=>'gold','capacity'=>'16gb'), 3=>array('screensize'=>'4_7inch','color'=>'silver','capacity'=>'64gb'), 4=>array('screensize'=>'4_7inch','color'=>'space_gray','capacity'=>'64gb'), 5=>array('screensize'=>'4_7inch','color'=>'gold','capacity'=>'64gb'), 6=>array('screensize'=>'4_7inch','color'=>'silver','capacity'=>'128gb'), 7=>array('screensize'=>'4_7inch','color'=>'space_gray','capacity'=>'128gb'), 8=>array('screensize'=>'4_7inch','color'=>'gold','capacity'=>'128gb'), ); $iphone6plus=array( 0=>array('screensize'=>'5_5inch','color'=>'silver','capacity'=>'16gb'), 1=>array('screensize'=>'5_5inch','color'=>'space_gray','capacity'=>'16gb'), 2=>array('screensize'=>'5_5inch','color'=>'gold','capacity'=>'16gb'), 3=>array('screensize'=>'5_5inch','color'=>'silver','capacity'=>'64gb'), 4=>array('screensize'=>'5_5inch','color'=>'space_gray','capacity'=>'64gb'), 5=>array('screensize'=>'5_5inch','color'=>'gold','capacity'=>'64gb'), 6=>array('screensize'=>'5_5inch','color'=>'silver','capacity'=>'128gb'), 7=>array('screensize'=>'5_5inch','color'=>'space_gray','capacity'=>'128gb'), 8=>array('screensize'=>'5_5inch','color'=>'gold','capacity'=>'128gb'), ); // iphone 6 foreach ($iphone6 as $model) { $screensize=$model['screensize']; $color=$model['color']; $capacity=$model['capacity']; $json_url="http://store.apple.com/hk/buyFlowSelectionSummary/IPHONE6?node=home/shop_iphone/family/iphone6&step=select&option.dimensionScreensize=".$screensize."&option.dimensionColor=".$color."&option.dimensionCapacity=".$capacity."&option.carrierModel=UNLOCKED%2FWW&carrierPolicyType=UNLOCKED"; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $json_url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_USERAGENT, $user_agent);//伪装成浏览器 $str=curl_exec($ch); $str_array=json_decode($str,true); curl_close($ch); $available=$str_array['body']['content']['selected']['purchaseOptions']['isBuyable']; $partnumber=$str_array['body']['content']['selected']['partNumber']; if ($available!==false) { echo $screensize."-".$color."-".$capacity.": is available, please go to http://store.apple.com/hk-zh/buy-iphone/iphone6?cppart=UNLOCKED/WW&product=".$partnumber."&step=accessories"."\n"; $iphone6msg.="<p>".$screensize." ".$color." ".$capacity." is available, <a target=_blank href=\"http://store.apple.com/hk-zh/buy-iphone/iphone6?cppart=UNLOCKED/WW&product=".$partnumber."&step=accessories\">http://store.apple.com/hk-zh/buy-iphone/iphone6?cppart=UNLOCKED/WW&product=".$partnumber."&step=accessories</a></p>"; } } // iphone 6 plus foreach ($iphone6plus as $model) { $screensize=$model['screensize']; $color=$model['color']; $capacity=$model['capacity']; $json_url="http://store.apple.com/hk/buyFlowSelectionSummary/IPHONE6P?node=home/shop_iphone/family/iphone6&step=select&option.dimensionScreensize=".$screensize."&option.dimensionColor=".$color."&option.dimensionCapacity=".$capacity."&option.carrierModel=UNLOCKED%2FWW&carrierPolicyType=UNLOCKED"; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $json_url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_USERAGENT, $user_agent); $str=curl_exec($ch); $str_array=json_decode($str,true); curl_close($ch); $available=$str_array['body']['content']['selected']['purchaseOptions']['isBuyable']; $partnumber=$str_array['body']['content']['selected']['partNumber']; if ($available!==false) { echo $screensize."-".$color."-".$capacity.": is available, please go to http://store.apple.com/hk-zh/buy-iphone/iphone6?cppart=UNLOCKED/WW&product=".$partnumber."&step=accessories"."\n"; $iphone6msg.="<p>".$screensize." ".$color." ".$capacity." is available, <a target=_blank href=\"http://store.apple.com/hk-zh/buy-iphone/iphone6?cppart=UNLOCKED/WW&product=".$partnumber."&step=accessories\">http://store.apple.com/hk-zh/buy-iphone/iphone6?cppart=UNLOCKED/WW&product=".$partnumber."&step=accessories</a></p>"; } } if (!empty($iphone6msg)) { mail($recipient,$subject,$iphone6msg,$headers); } //$json_url="http://store.apple.com/hk/buyFlowSelectionSummary/IPHONE6P?node=home/shop_iphone/family/iphone6&step=select&option.dimensionScreensize=".$screensize."&option.dimensionColor=".$color."&option.dimensionCapacity=".$capacity."&option.carrierModel=UNLOCKED%2FWW&carrierPolicyType=UNLOCKED"; //var_dump($i6); ?>
至于该监控是否准确,有待验证,只能坐等苹果有好消息了,希望延迟不会超过10分钟(假如邮件能够正常发送成功的话)。