Class: MagentoMech

Inherits:
Object
  • Object
show all
Defined in:
lib/magento_remote/magento_mech.rb

Overview

The Mech Driver, interacting with a Magento shop page. Note that the Mech does not keep too much state, you have to care about login etc yourself.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(base_uri) ⇒ MagentoMech

Create Mech with base_uri



22
23
24
25
26
27
28
# File 'lib/magento_remote/magento_mech.rb', line 22

def initialize base_uri
  @mech = Mechanize.new
  #@mech.user_agent = 'Mac Safari'
  #@mech.user_agent = ''
  @base_uri = base_uri
  @mech.agent.allowed_error_codes = [429]
end

Instance Attribute Details

#passObject

Returns the value of attribute pass.



9
10
11
# File 'lib/magento_remote/magento_mech.rb', line 9

def pass
  @pass
end

#userObject

Returns the value of attribute user.



8
9
10
# File 'lib/magento_remote/magento_mech.rb', line 8

def user
  @user
end

Class Method Details

.from_config(conf) ⇒ Object

Create Mech from hash Argument conf

values :base_uri, :user, :pass.


14
15
16
17
18
19
# File 'lib/magento_remote/magento_mech.rb', line 14

def self.from_config(conf)
  client = MagentoMech.new(conf[:base_uri])
  client.user = conf[:user]
  client.pass = conf[:pass]
  client
end

Instance Method Details

#add_to_cart(product_id, qty) ⇒ Object

Put stuff in the cart. Returns true if succeeded, false otherwise.



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/magento_remote/magento_mech.rb', line 43

def add_to_cart product_id, qty
  fail "Empty obligatory parameter" if product_id.nil? || qty.to_i <= 0
  url = "#{@base_uri}/checkout/cart/add?product=#{product_id}&qty=#{qty}"

  # Check the returned page name
  result_page = @mech.get url

  # There are multiple reasons of failure:
  #   * product_id unknown
  #   * product out of stock

  # There are multiple ways to detect failure:
  #   * contains a form with post action ending on product/#{product_id}/
  #   * title is different (stays at product page when failing)
  #   * no success msg div is shown.
  #   * body has a different class.
  #
  # Using the last of these options:
  # return result_page.search('.catalog-product-view').empty?

  return !result_page.search('.success-msg span').empty?
end

#add_to_cart!(product_id, qty) ⇒ Object

Puts as many items of given product to cart as possible Returns number of items put to cart.



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/magento_remote/magento_mech.rb', line 68

def add_to_cart! product_id, qty
  # Try to be a bit clever and early find out whether article
  # is out of stock.
  if add_to_cart(product_id, qty)
    # to_i
    return qty
  end
  num_ordered = 0
  # Apparently not enough in stock!

  if qty.to_i > 4
    if !add_to_cart(product_id, 1)
      # out of stock
      return 0
    else
      num_ordered = 1
      qty = qty.to_i - 1
    end
  end
  while qty.to_i > 0 && !add_to_cart(product_id, qty)
    qty = qty.to_i - 1
  end
  qty.to_i + num_ordered
end

#find_product(search_string) ⇒ Object

Search products. Arguments

search_string: sku, name or title, urlencoded for get request.

returns [[name1, product_id1, instock?1],[name2, p_id2…]…]

or nil if not found.


119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/magento_remote/magento_mech.rb', line 119

def find_product search_string
  url = relative_url("/catalogsearch/result/index/?limit=all&q=#{search_string}")
  @mech.get url

  product_li = @mech.page.search('.equal-height .item')

  return nil if product_li.empty?

  products = product_li.map do |product|
    # Add to cart button is missing if out of stock.
    buttons = product.search("button")
    stock = buttons && !buttons[0].nil?

    # Find product ID from wishlist link.
    wishlist_link = product.search("ul li a")[0]
    wishlist_link.attributes['href'].value[/product\/(\d+)/]
    pid = $1

    # Find name from heading.
    name = product.search('h2')[0].text
    [name, pid, stock]
  end

  return products
end

#find_product_id_from(url) ⇒ Object



145
146
147
148
149
150
# File 'lib/magento_remote/magento_mech.rb', line 145

def find_product_id_from url
  page = @mech.get url
  r_pid = page.search(".//input[@name='product']")[0][:value]
  r_name = page.search(".product-name .roundall")
  [r_pid, r_name.text]
end

#get_cart_contentObject

Get the current carts contents



94
95
96
97
98
99
100
101
# File 'lib/magento_remote/magento_mech.rb', line 94

def get_cart_content
  cart_page = @mech.get("#{@base_uri}/checkout/cart/")
  name_links = cart_page.search('td h2 a')
  names = name_links.map &:text
  quantities_inputs = cart_page.search('.qty')
  quantities = quantities_inputs.map {|n| n[:value]}
  names.zip quantities
end

#last_order_productsObject

Get products of last order. Arguments returns [[product_name1, product_sku1, qty_ordered1],[name2, sku2…]…]

or empty list if not found.


182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/magento_remote/magento_mech.rb', line 182

def last_order_products
  orders_url = relative_url("/customer/account/")
  @mech.get orders_url
  order_url = @mech.page.search('.a-center a').first.attributes['href']
  @mech.get order_url
  @mech.page.search('tr.border').map do |tr|
    product_name = tr.children[1].children[0].content
    product_sku = tr.children[3].children[0].content
    product_qty = tr.children[7].children[1].content[/\d+/]
    [product_name, product_sku, product_qty]
  end
end

#log_to!(file) ⇒ Object

Log to given file (-like object).



31
32
33
34
# File 'lib/magento_remote/magento_mech.rb', line 31

def log_to! file
  puts @mech.log
  @mech.log = Logger.new file
end

#loginObject

Login to webpage



37
38
39
# File 'lib/magento_remote/magento_mech.rb', line 37

def 
   @user, @pass
end

#login_with(username, password) ⇒ Object

Login with given credentials



104
105
106
107
108
109
110
111
112
# File 'lib/magento_remote/magento_mech.rb', line 104

def  username, password
   = @mech.get("#{@base_uri}/customer/account/login/")

  form = .form_with(:action => '#', :method => 'POST')
  form.action = "#{@base_uri}/customer/account/loginPost/"
  form.fields.find{|f| f.name == 'login[username]'}.value = username
  form.fields.find{|f| f.name == 'login[password]'}.value = password
  @mech.submit(form)
end

#scrape_products(start_pid, limit) ⇒ Object

Search/scrape products. Arguments

limit: Maximum number of product_ids to check
start_pid: With which product id to start scraping

returns [[name1, product_id1, instock?1],[name2, p_id2…]…]

or nil if not found.

yielding would be nice



159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/magento_remote/magento_mech.rb', line 159

def scrape_products start_pid, limit
  products = []
  limit.times do |idx|
    url = relative_url("/catalog/product/view/id/#{start_pid + idx + 1}")
    @mech.get url rescue next
    #if @mech.response_code
    product_name = @mech.page.search('.product-name .roundall')[0].text
    wishlist_link = @mech.page.search(".link-wishlist")[0]
    wishlist_link.attributes['href'].value[/product\/(\d+)/]
    pid = $1
    products << [product_name, pid]
    if block_given?
      yield [product_name, pid]
    end
  end

  return products
end