amazon_order 0.1.0 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: e3a6bf0fa3f7452a0d5902ad1f18573a91533e3b
4
- data.tar.gz: 20b21eb7ee25fb98487583bb8369f371acef22bc
2
+ SHA256:
3
+ metadata.gz: ed9bb5a826d4c1d9248638828f0fab21219b2dccba0306e5e3c512801a2ce60e
4
+ data.tar.gz: dd2bcce492a9218a499bc63a3778f3c9d5a1f3baa3f4a018e4fbb416f84c69d4
5
5
  SHA512:
6
- metadata.gz: 56ee5c0283f97849f9cc461b780ceab6cbc4e468fd039066cef4f1ba3968b60b1cc5e34192c100eb8f8ec786435aa5e9d3b0620d2e0009d516fba0a53b00be81
7
- data.tar.gz: 3679036cfa689b836654f8c57c4bcd093fecdc3ca4a17a900f49457ba424d71bb99eb36aa53bd3d2fc0b14c3fb01c2a8b6525ca92e71568ccc4262a6cf5c9b9f
6
+ metadata.gz: 9e0f7903e9248d6e83a75e2bcf7810f2376d607453b8d05fe57c10deaeff21246fffb4d7c6c07e213ddf0aa67480be748c7253f6b0abdd181401d3467780853d
7
+ data.tar.gz: b556a0c0596b71e14d552da3e60aa6e8faf76c35e3a6e1f07469ffcfbe3798e74ad6cecbd76d67b1f9018993ebdc140174291f7b4f582e97f1206f552ee2c5a5
@@ -1,5 +1,7 @@
1
1
  sudo: false
2
2
  language: ruby
3
3
  rvm:
4
- - 2.2.4
5
- before_install: gem install bundler -v 1.14.6
4
+ - 2.5.8
5
+ - 2.6.6
6
+ - 2.7.1
7
+ before_install: gem install bundler -v 1.17.3
data/README.md CHANGED
@@ -37,11 +37,14 @@ Or install it yourself as:
37
37
 
38
38
  [chromedriver](https://sites.google.com/a/chromium.org/chromedriver/downloads) is required. Please [download chromedriver](http://chromedriver.storage.googleapis.com/index.html) and update chromedriver regularly.
39
39
 
40
- Create _.env_ following the instructions of https://github.com/kyamaguchi/amazon_auth
40
+ Create credentials following the instructions of https://github.com/kyamaguchi/amazon_auth
41
+ Use `envchain` or _.env_
41
42
 
42
43
  ```
43
44
  amazon_auth
44
45
 
46
+ envchain amazon ...
47
+ # OR
45
48
  vi .env
46
49
  ```
47
50
 
@@ -53,7 +56,7 @@ In console
53
56
 
54
57
  ```ruby
55
58
  require 'amazon_order'
56
- client = AmazonOrder::Client.new(verbose: true, limit: 10)
59
+ client = AmazonOrder::Client.new(keep_cookie: true, verbose: true, limit: 10)
57
60
  client.fetch_amazon_orders
58
61
  # Fetch orders of specified year
59
62
  client.fetch_orders_for_year(year: 2016)
@@ -65,8 +68,8 @@ client.go_to_amazon_order_page
65
68
  client.fetch_orders_for_year(year: 2015)
66
69
  ```
67
70
 
68
- Downloaded pages will be stored into `order` directory.
69
- You can reset by moving that directory.
71
+ Downloaded pages will be stored into `tmp/orders` directory.
72
+ `tmp` comes from `Capybara.save_path`.
70
73
 
71
74
  Once `fetch_amazon_orders` succeeds, you can load orders information of downloaded pages anytime.
72
75
  (You don't need to fetch pages with launching browser every time.)
@@ -86,7 +89,7 @@ products.size
86
89
  orders.group_by{|o| o.order_placed.strftime('%Y') }.sort_by{|year,_| year }.map{|year,records| puts [year, records.map(&:order_total).sum].inspect };nil
87
90
  ```
88
91
 
89
- Example of data
92
+ #### Example of data
90
93
 
91
94
  ```ruby
92
95
  console> pp orders.first.to_hash
@@ -111,16 +114,24 @@ console> pp products.first.to_hash
111
114
  "https://images-fe.ssl-images-amazon.com/images/I/51TODrMIEnL.jpg"}
112
115
  ```
113
116
 
117
+ #### Export csv
118
+
119
+ ```ruby
120
+ client.generate_csv
121
+ ```
122
+
114
123
  #### Options
115
124
 
116
125
  Limit fetching with number of pages: `client = AmazonOrder::Client.new(limit: 5)`
117
- `limit: nil` for no limit. default is 5
126
+ (`limit: nil` for no limit. default is 5)
118
127
 
119
128
  Set year range: `client = AmazonOrder::Client.new(year_from: 2012, year_to: 2013)`
120
- default is Time.current.year
129
+ (default is Time.current.year)
121
130
 
122
131
  ##### Options of amazon_auth gem
123
132
 
133
+ Keep cookies(keep signin): `keep_cookie: true`
134
+
124
135
  Firefox: `driver: :firefox`
125
136
 
126
137
  Output debug log: `debug: true`
@@ -21,10 +21,10 @@ Gem::Specification.new do |spec|
21
21
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
22
  spec.require_paths = ["lib"]
23
23
 
24
- spec.add_runtime_dependency "amazon_auth", "~> 0.3.3"
25
- spec.add_development_dependency "bundler", "~> 1.14"
26
- spec.add_development_dependency "rake", "~> 10.0"
27
- spec.add_development_dependency "rspec", "~> 3.0"
24
+ spec.add_runtime_dependency "amazon_auth", "~> 0.4.0"
25
+ spec.add_development_dependency "bundler"
26
+ spec.add_development_dependency "rake"
27
+ spec.add_development_dependency "rspec"
28
28
  spec.add_development_dependency "byebug"
29
29
  spec.add_development_dependency "pry-rescue"
30
30
  spec.add_development_dependency "pry-stack_explorer"
@@ -3,6 +3,7 @@ require "amazon_order/version"
3
3
  require "amazon_order/client"
4
4
  require "amazon_order/parsers/base"
5
5
  require "amazon_order/parsers/order"
6
+ require "amazon_order/parsers/shipment"
6
7
  require "amazon_order/parsers/product"
7
8
  require "amazon_order/parser"
8
9
  require "amazon_order/writer"
@@ -6,11 +6,14 @@ module AmazonOrder
6
6
 
7
7
  def initialize(options = {})
8
8
  @options = options
9
- @base_dir = @options.fetch(:base_dir, 'orders')
10
9
  @client = AmazonAuth::Client.new(@options)
11
10
  extend(AmazonAuth::SessionExtension)
12
11
  end
13
12
 
13
+ def base_dir
14
+ options.fetch(:base_dir, 'orders')
15
+ end
16
+
14
17
  def year_from
15
18
  options.fetch(:year_from, Time.current.year)
16
19
  end
@@ -37,7 +40,7 @@ module AmazonOrder
37
40
 
38
41
  def load_amazon_orders
39
42
  orders = []
40
- Dir.glob("#{@base_dir}/*html").each do |filepath|
43
+ Dir.glob(file_glob_pattern).each do |filepath|
41
44
  log "Loading #{filepath}"
42
45
  parser = AmazonOrder::Parser.new(filepath)
43
46
  orders += parser.orders
@@ -45,13 +48,34 @@ module AmazonOrder
45
48
  orders.sort_by{|o| -o.fetched_at.to_i }.uniq(&:order_number)
46
49
  end
47
50
 
51
+ def file_glob_pattern
52
+ File.join(Capybara.save_path, base_dir, '*html')
53
+ end
54
+
55
+ def generate_csv
56
+ writer.generate_csv
57
+ end
58
+
59
+ def writer
60
+ @_writer ||= AmazonOrder::Writer.new(file_glob_pattern)
61
+ end
62
+
48
63
  def sign_in
49
64
  @client.sign_in
50
65
  end
51
66
 
52
67
  def go_to_amazon_order_page
68
+ if doc.css('.cvf-account-switcher').present?
69
+ log "Account switcher page was displayed"
70
+ session.first('.cvf-account-switcher-profile-details').click
71
+ wait_for_selector('#nav-main') # Wait for page loading
72
+ end
53
73
  link = links_for('a').find{|link| link =~ %r{/order-history} }
54
- session.visit link
74
+ if link.present?
75
+ session.visit link
76
+ else
77
+ log "Link for order history wasn't found in #{session.current_url}"
78
+ end
55
79
  end
56
80
 
57
81
  def fetch_orders_for_year(options = {})
@@ -83,7 +107,7 @@ module AmazonOrder
83
107
  def save_page_for(year, page)
84
108
  log "Saving year:#{year} page:#{page}"
85
109
  path = ['order', year.to_s, "p#{page}", Time.current.strftime('%Y%m%d%H%M%S')].join('-') + '.html'
86
- session.save_page(File.join(@base_dir, path))
110
+ session.save_page(File.join(base_dir, path))
87
111
  end
88
112
 
89
113
  def selected_year
@@ -6,6 +6,7 @@ module AmazonOrder
6
6
  def initialize(node, options = {})
7
7
  @node = node
8
8
  @fetched_at = options[:fetched_at]
9
+ @containing_object = options[:containing_object]
9
10
  end
10
11
 
11
12
  def inspect
@@ -3,7 +3,6 @@ module AmazonOrder
3
3
  class Order < Base
4
4
  ATTRIBUTES = %w[
5
5
  order_placed order_number order_total
6
- shipment_status shipment_note
7
6
  order_details_path
8
7
  all_products_displayed
9
8
  ]
@@ -17,36 +16,55 @@ module AmazonOrder
17
16
  end
18
17
 
19
18
  def order_total
20
- @_order_total ||= @node.css('.order-info .a-col-left .a-column')[1].css('.value').text.strip.gsub(/[^\d\.]/,'').to_f
19
+ @_order_total ||= @node.css('.order-info .a-col-left .a-column')[1].css('.value').text.strip.gsub(/[^\d\.]/, '').to_f
21
20
  end
22
21
 
23
- def shipment_status
24
- # class names like "shipment-is-delivered" in '.shipment' node may be useful
25
- @_shipment_status ||= @node.css('.shipment .shipment-top-row').present? ? @node.css('.shipment .shipment-top-row .a-row')[0].text.strip : nil
22
+ def order_details_path
23
+ @_order_details_path ||= @node.css('.order-info .a-col-right .a-row')[1].css('a.a-link-normal')[0].attr('href')
26
24
  end
27
25
 
28
- def shipment_note
29
- @_shipment_note ||= @node.css('.shipment .shipment-top-row').present? ? @node.css('.shipment .shipment-top-row .a-row')[1].text.strip : nil
26
+ def order_type
27
+ if @node.css('[id^=Leave-Service-Feedback]').present?
28
+ return :service_order
29
+ elsif @node.css('.shipment').present?
30
+ :shipment_order
31
+ else
32
+ :digital_order
33
+ end
30
34
  end
31
35
 
32
- def order_details_path
33
- @_order_details_path ||= @node.css('.order-info .a-col-right .a-row')[1].css('a.a-link-normal')[0].attr('href')
36
+ def shipments
37
+ @_shipments ||= @node.css('.shipment')
38
+ .map do |shipment|
39
+ AmazonOrder::Parsers::Shipment.new(shipment,
40
+ containing_object: self,
41
+ fetched_at: fetched_at)
42
+ end
34
43
  end
35
44
 
36
- def all_products_displayed
37
- @_all_products_displayed ||= @node.css('.a-box.order-info ~ .a-box .a-col-left .a-row').last.css('.a-link-emphasis').present?
45
+ def products
46
+ @products ||= shipment_products + digital_products
38
47
  end
39
48
 
40
- def products
41
- @_products ||= @node.css('.a-box.order-info ~ .a-box .a-col-left .a-row')[0].css('.a-fixed-left-grid').map{|e| AmazonOrder::Parsers::Product.new(e, fetched_at: fetched_at) }
49
+ def shipment_products
50
+ @shipment_products ||= shipments.flat_map(&:products)
51
+ end
52
+
53
+ def digital_products
54
+ @_products ||= @node.css('.a-box:not(.shipment) .a-fixed-left-grid').map { |e| AmazonOrder::Parsers::Product.new(e, fetched_at: fetched_at) }
42
55
  end
43
56
 
57
+ # might be broken now that orders have multiple shipments
58
+ def all_products_displayed
59
+ @_all_products_displayed ||= @node.css('.a-box.order-info ~ .a-box .a-col-left .a-row').last.css('.a-link-emphasis').present?
60
+ end
44
61
 
45
62
  def to_hash
46
63
  super do |hash|
47
64
  hash.merge!(products: products.map(&:to_hash))
48
65
  end
49
66
  end
67
+
50
68
  end
51
69
  end
52
70
  end
@@ -21,7 +21,10 @@ module AmazonOrder
21
21
  end
22
22
 
23
23
  def image_url
24
- @_image_url ||= get_original_image_url(@node.css('.a-col-left img')[0].attr('src'))
24
+ @_image_url ||= begin
25
+ img = @node.css('.a-col-left img')[0]
26
+ get_original_image_url(img.attr('data-a-hires').presence || img.attr('src'))
27
+ end
25
28
  end
26
29
  end
27
30
  end
@@ -0,0 +1,38 @@
1
+ module AmazonOrder
2
+ module Parsers
3
+ class Shipment < Base
4
+ ATTRIBUTES = %w[
5
+ shipment_status
6
+ shipment_note
7
+ ]
8
+
9
+ # TODO shipment_date
10
+
11
+ def order
12
+ @containing_object
13
+ end
14
+
15
+ def shipment_status
16
+ # class names like "shipment-is-delivered" in '.shipment' node may be useful
17
+ @_shipment_status ||= @node.css('.shipment-top-row').present? ? @node.css('.shipment .shipment-top-row .a-row')[0].text.strip : nil
18
+ end
19
+
20
+ def shipment_note
21
+ @_shipment_note ||= case order.order_type
22
+ when :shipment_order
23
+ @node.css('.shipment-top-row').present? ? @node.css('.shipment .shipment-top-row .a-row')[1].text.strip : nil
24
+ when :service_order
25
+ nil
26
+ when :digital_order
27
+ nil
28
+ end
29
+ end
30
+
31
+
32
+ def products
33
+ @_products ||= @node.css('.a-fixed-left-grid').map { |e| AmazonOrder::Parsers::Product.new(e, fetched_at: fetched_at) }
34
+ end
35
+
36
+ end
37
+ end
38
+ end
@@ -1,3 +1,3 @@
1
1
  module AmazonOrder
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.5"
3
3
  end
@@ -1,7 +1,7 @@
1
1
  module AmazonOrder
2
2
  class Writer
3
- def initialize(base_dir, options = {})
4
- @base_dir = base_dir
3
+ def initialize(file_glob_pattern, options = {})
4
+ @file_glob_pattern = file_glob_pattern
5
5
  @output_dir = options.fetch(:output_dir, 'tmp')
6
6
  end
7
7
 
@@ -9,7 +9,7 @@ module AmazonOrder
9
9
  data['orders']
10
10
  end
11
11
 
12
- def print_produts
12
+ def print_products
13
13
  data['products']
14
14
  end
15
15
 
@@ -21,7 +21,8 @@ module AmazonOrder
21
21
  csv_file = "#{@output_dir}/#{resource}#{Time.current.strftime('%Y%m%d%H%M%S')}.csv"
22
22
  puts " Writing #{csv_file}"
23
23
  CSV.open(csv_file, 'wb') do |csv|
24
- data[resource].each{|r| csv << r }
24
+ csv << attributes_for(resource)
25
+ data[resource].each { |r| csv << r }
25
26
  end
26
27
  csv_file
27
28
  end
@@ -32,7 +33,7 @@ module AmazonOrder
32
33
  def data
33
34
  @_data ||= begin
34
35
  data = {'orders' => [], 'products' => []}
35
- Dir.glob("#{@base_dir}/*html").each do |filepath|
36
+ Dir.glob(@file_glob_pattern).each do |filepath|
36
37
  puts " Parsing #{filepath}"
37
38
  parser = AmazonOrder::Parser.new(filepath)
38
39
  data['orders'] += parser.orders.map(&:values)
@@ -41,5 +42,14 @@ module AmazonOrder
41
42
  data
42
43
  end
43
44
  end
45
+
46
+ def attributes_for(resource)
47
+ case resource
48
+ when 'orders'
49
+ AmazonOrder::Parsers::Order::ATTRIBUTES
50
+ when 'products'
51
+ AmazonOrder::Parsers::Product::ATTRIBUTES
52
+ end
53
+ end
44
54
  end
45
55
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: amazon_order
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kazuho Yamaguchi
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-07-05 00:00:00.000000000 Z
11
+ date: 2020-05-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: amazon_auth
@@ -16,56 +16,56 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.3.3
19
+ version: 0.4.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.3.3
26
+ version: 0.4.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '1.14'
33
+ version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '1.14'
40
+ version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: '10.0'
47
+ version: '0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - "~>"
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: '10.0'
54
+ version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rspec
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
- version: '3.0'
61
+ version: '0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - "~>"
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
- version: '3.0'
68
+ version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: byebug
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -131,6 +131,7 @@ files:
131
131
  - lib/amazon_order/parsers/base.rb
132
132
  - lib/amazon_order/parsers/order.rb
133
133
  - lib/amazon_order/parsers/product.rb
134
+ - lib/amazon_order/parsers/shipment.rb
134
135
  - lib/amazon_order/version.rb
135
136
  - lib/amazon_order/writer.rb
136
137
  homepage: https://github.com/kyamaguchi/amazon_order
@@ -152,8 +153,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
152
153
  - !ruby/object:Gem::Version
153
154
  version: '0'
154
155
  requirements: []
155
- rubyforge_project:
156
- rubygems_version: 2.6.11
156
+ rubygems_version: 3.0.8
157
157
  signing_key:
158
158
  specification_version: 4
159
159
  summary: Scrape information of amazon orders