AmazonPriceTrackerBridge.php 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. <?php
  2. class AmazonPriceTrackerBridge extends BridgeAbstract {
  3. const MAINTAINER = 'captn3m0';
  4. const NAME = 'Amazon Price Tracker';
  5. const URI = 'https://www.amazon.com/';
  6. const CACHE_TIMEOUT = 3600; // 1h
  7. const DESCRIPTION = 'Tracks price for a single product on Amazon';
  8. const PARAMETERS = array(
  9. array(
  10. 'asin' => array(
  11. 'name' => 'ASIN',
  12. 'required' => true,
  13. 'exampleValue' => 'B071GB1VMQ',
  14. // https://stackoverflow.com/a/12827734
  15. 'pattern' => 'B[\dA-Z]{9}|\d{9}(X|\d)',
  16. ),
  17. 'tld' => array(
  18. 'name' => 'Country',
  19. 'type' => 'list',
  20. 'required' => true,
  21. 'values' => array(
  22. 'Australia' => 'com.au',
  23. 'Brazil' => 'com.br',
  24. 'Canada' => 'ca',
  25. 'China' => 'cn',
  26. 'France' => 'fr',
  27. 'Germany' => 'de',
  28. 'India' => 'in',
  29. 'Italy' => 'it',
  30. 'Japan' => 'co.jp',
  31. 'Mexico' => 'com.mx',
  32. 'Netherlands' => 'nl',
  33. 'Spain' => 'es',
  34. 'United Kingdom' => 'co.uk',
  35. 'United States' => 'com',
  36. ),
  37. 'defaultValue' => 'com',
  38. ),
  39. ));
  40. protected $title;
  41. /**
  42. * Generates domain name given a amazon TLD
  43. */
  44. private function getDomainName() {
  45. return 'https://www.amazon.' . $this->getInput('tld');
  46. }
  47. /**
  48. * Generates URI for a Amazon product page
  49. */
  50. public function getURI() {
  51. if (!is_null($this->getInput('asin'))) {
  52. return $this->getDomainName() . '/dp/' . $this->getInput('asin') . '/';
  53. }
  54. return parent::getURI();
  55. }
  56. /**
  57. * Scrapes the product title from the html page
  58. * returns the default title if scraping fails
  59. */
  60. private function getTitle($html) {
  61. $titleTag = $html->find('#productTitle', 0);
  62. if (!$titleTag) {
  63. return $this->getDefaultTitle();
  64. } else {
  65. return trim(html_entity_decode($titleTag->innertext, ENT_QUOTES));
  66. }
  67. }
  68. /**
  69. * Title used by the feed if none could be found
  70. */
  71. private function getDefaultTitle() {
  72. return 'Amazon.' . $this->getInput('tld') . ': ' . $this->getInput('asin');
  73. }
  74. /**
  75. * Returns name for the feed
  76. * Uses title (already scraped) if it has one
  77. */
  78. public function getName() {
  79. if (isset($this->title)) {
  80. return $this->title;
  81. } else {
  82. return parent::getName();
  83. }
  84. }
  85. /**
  86. * Returns a generated image tag for the product
  87. */
  88. private function getImage($html) {
  89. $imageSrc = $html->find('#main-image-container img', 0);
  90. if ($imageSrc) {
  91. $imageSrc = $imageSrc ? $imageSrc->getAttribute('data-old-hires') : '';
  92. return <<<EOT
  93. <img width="300" style="max-width:300;max-height:300" src="$imageSrc" alt="{$this->title}" />
  94. EOT;
  95. }
  96. }
  97. /**
  98. * Return \simple_html_dom object
  99. * for the entire html of the product page
  100. */
  101. private function getHtml() {
  102. $uri = $this->getURI();
  103. return getSimpleHTMLDOM($uri) ?: returnServerError('Could not request Amazon.');
  104. }
  105. /**
  106. * Scrape method for Amazon product page
  107. * @return [type] [description]
  108. */
  109. public function collectData() {
  110. $html = $this->getHtml();
  111. $this->title = $this->getTitle($html);
  112. $imageTag = $this->getImage($html);
  113. $asinData = $html->find('#cerberus-data-metrics', 0);
  114. // <div id="cerberus-data-metrics" style="display: none;"
  115. // data-asin="B00WTHJ5SU" data-asin-price="14.99" data-asin-shipping="0"
  116. // data-asin-currency-code="USD" data-substitute-count="-1" ... />
  117. $currency = $asinData->getAttribute('data-asin-currency-code');
  118. $shipping = $asinData->getAttribute('data-asin-shipping');
  119. $price = $asinData->getAttribute('data-asin-price');
  120. $item = array(
  121. 'title' => $this->title,
  122. 'uri' => $this->getURI(),
  123. 'content' => "$imageTag<br/>Price: $price $currency",
  124. );
  125. if ($shipping !== '0') {
  126. $item['content'] .= "<br>Shipping: $shipping $currency</br>";
  127. }
  128. $this->items[] = $item;
  129. }
  130. }