Created
March 7, 2018 20:15
-
-
Save eatoncw/ac5703825e55f2acde048e1006c02902 to your computer and use it in GitHub Desktop.
Sample api request - find certain Best Buy products that are on sale and save to database
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#utilize a background job - using sidekiq with redis queue | |
class ApisSalesFinders::BestbuySalesFinderWorker < ApisSalesFinders::SalesFinders | |
include Sidekiq::Worker | |
require './app/models/scrape_constants/collections' #ebay product categories | |
def perform | |
current_items = Product.where(retailer: "best buy") | |
discount = 10 | |
minimum_price = 75 #used to filter out some accessory products | |
current_products_urls_arr = [] #used to purge database of old records | |
bestbuy = Apis::BestbuyApi.new | |
begin | |
ProductCollections.bestbuy_search_queries.each_with_index do |collection, i| | |
puts "fetching #{collection[:name]} collection from bestbuy" | |
# first iteration to get total pages | |
page_number = 1 | |
puts "fetching page #{page_number}" | |
response = bestbuy.get_all_listings(URI.encode(collection[:query_string]),page_number) #api request | |
products = filter_bestbuy_products(bestbuy,response,discount,minimum_price) | |
products.each {|product| current_products_urls_arr << product.url } | |
save_or_update_items(products, current_items) # add to database | |
# loop through additional pages | |
total_pages = response['totalPages'].to_i ||= 1 | |
puts "#{total_pages} pages in the #{collection[:name]} collection" | |
additional_pages = total_pages - 1 | |
additional_pages.times do |i| | |
page_number = i + 2 | |
puts "fetching page #{page_number}" | |
response = bestbuy.get_all_listings(URI.encode(collection[:query_string]),page_number) | |
products = filter_bestbuy_products(bestbuy,response,discount,minimum_price) | |
products.each {|product| current_products_urls_arr << product.url } | |
save_or_update_items(products, current_items) # add to database | |
end | |
end | |
# purge old records | |
old_products = current_items.where.not(url: current_products_urls_arr) | |
puts "destroying #{old_products.size} old products" | |
old_products.delete_all | |
puts "#{Product.where(retailer:"best buy").count} Bestbuy products in our database" | |
rescue StandardError => e | |
Honeybadger.notify(e) | |
end | |
end | |
def filter_bestbuy_products(bestbuy,response,discount,minimum_price) | |
products = discount_filter(bestbuy.to_products(response), discount) #json to ruby objects and filter | |
products.reject!{|product| product.price < minimum_price} | |
products | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Apis::BestbuyApi < Apis::ApiConnector | |
base_uri "https://api.bestbuy.com/v1" | |
default_params apiKey: ENV["BESTBUY_APIKEY"], LID: ENV["BESTBUY_AFFILIATE_TRACKING_ID"], format: "json", pageSize: 100, show: 'name,salePrice,onSale,regularPrice,image,linkShareAffiliateUrl,shortDescription,depth,height,width' | |
# max is 100 products per page | |
def initialize | |
end | |
def get_all_listings(query_string,page_number) | |
self.class.get("/products(#{query_string})", param: {page: page_number}) | |
end | |
def to_products(response) #only commit to ruby objects if response contains sales criteria | |
arr = response['products'] | |
arr = arr ||= [] | |
arr.reject! {|item| item['onSale'] == false } | |
Dish(arr, Apis::BestbuyProduct) | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Apis::BestbuyProduct < Apis::ApiProduct | |
def initialize(items_array) | |
@retailer = "best buy" | |
@name = items_array.andand['name'] | |
@description = items_array.andand['shortDescription'] | |
@image_url = items_array.andand['image'] | |
@url = items_array.andand['linkShareAffiliateUrl'] | |
@unit_dimensions = "inches" | |
@item_length = return_measurement(items_array.andand['width']) | |
@item_width = return_measurement(items_array.andand['depth']) | |
@item_height = return_measurement(items_array.andand['height']) | |
current_price = items_array['salePrice'] | |
original_price = items_array['regularPrice'] | |
check_sale(original_price, current_price) #returns prices, onsale boolean, and discount | |
@category = "appliances" #currently we are only looking for appliances | |
end | |
def return_measurement(measurement) | |
(measurement == nil) ? 0 : measurement.split(" ")[0] | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#to run | |
rails runner ApisSalesFinders::BestbuySalesFinderWorker.perform_async |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def ProductCollections.bestbuy_search_queries #these filter out unwanted products using bestbuy defined classes and departments etc | |
[ | |
{name: "dishwashers", query_string: "search=dishwasher&department=appliance&subclass=dishwash*"}, | |
{name: "washing machines", query_string: "search=washing machine&class=laundry&department=appliance"}, | |
{name: "dryers", query_string: "search=dryer&class=laundry&department=appliance"}, | |
{name: "ovens", query_string: "search=oven&department=appliance&subclass=walloven*|search=oven&department=appliance&subclass=range*" }, | |
{name: "ranges", query_string: "search=range&class=cooking&department=appliance|search=range&class=built-ins&department=appliance"}, | |
{name: "refrigerators and freezer", query_string: "class=refri*&department=appliance"} | |
] | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class ApisSalesFinders::SalesFinders | |
def discount_filter(array, discount) | |
array.select{ |item| ((item.price - item.onsale_price) / item.price) >= (discount.to_f / 100) } | |
end | |
def save_or_update_items(products, current_items) | |
products.each do |product| | |
existing_product = current_items.find_by(url: product.url) #check if product exists | |
if existing_product.nil? | |
new_sales_item = Product.new(product.instance_values) #instance_values method convert product object into hash for database save | |
new_sales_item.save | |
puts "saved new item #{new_sales_item.name} with a category of #{new_sales_item.category}" | |
elsif (existing_product.onsale_price != product.onsale_price) #check if prices are the same | |
existing_product.update(product.instance_values) | |
puts "the price has changed" | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment