aftermarket_research 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e4ecca47e251a96412c5eca41997580b197ee3f6
4
+ data.tar.gz: 15c0bb6ff8f9d4fc08a05e988e39797ad7f47a7f
5
+ SHA512:
6
+ metadata.gz: 113338a90aa8723ffd2792bc069ac97f6b86785d6867a94ed9f664075b992283f3588515c4d72931d14bf9a82cbb31079b475b44ea7fab9f3f69f8967d8e4750
7
+ data.tar.gz: e135e4ff8f0f141a584c9309b6d55ebbe934e0fff6a5e51dc6b4f12b6b3dbc68250b9524307d0d7557ffed23810b3d66cc15cc8cc5f1b3bffd988d10b73534fc
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'aftermarket_research'
data/bin/runner.rb ADDED
@@ -0,0 +1,4 @@
1
+ # require_relative "../config/environment.rb"
2
+ require_relative "../lib/environment.rb"
3
+
4
+ Runner.new.interface
@@ -0,0 +1,3 @@
1
+ require_relative 'environment.rb'
2
+
3
+ Runner.new.interface
data/lib/analyzer.rb ADDED
@@ -0,0 +1,32 @@
1
+ class Analyzer
2
+
3
+ attr_accessor :num_array
4
+
5
+ def initialize(num_array)
6
+ self.num_array = num_array
7
+ end
8
+
9
+ def mean
10
+ self.num_array.inject(&:+)/num_array.count
11
+ # [a, b, c].inject(&:+) # => ((a + b)+ c)+ d)
12
+ # [b, c, d].inject(a, &:+) # => ((a + b)+ c)+ d)
13
+ end
14
+
15
+ def median
16
+ sorted = self.num_array.sort!
17
+ sorted[sorted.count/2]
18
+ end
19
+
20
+ def mode
21
+ freq = self.num_array.inject(Hash.new(0)) { |h,v| h[v] += 1; h }
22
+ self.num_array.max_by { |v| freq[v] }
23
+ end
24
+
25
+ def print_calculations
26
+ puts "Analysis complete, based on #{num_array.length} craigslist listings!"
27
+ puts "The mean price for your search is #{mean}"
28
+ puts "The median price for your search is #{median}"
29
+ puts "The mode price for your search is #{mode}"
30
+ end
31
+
32
+ end
@@ -0,0 +1,9 @@
1
+ require 'bundler/setup'
2
+ require 'open-uri'
3
+
4
+ Bundler.require
5
+
6
+ require_relative 'scraper.rb'
7
+ require_relative 'query.rb'
8
+ require_relative 'runner.rb'
9
+ require_relative 'analyzer.rb'
data/lib/query.rb ADDED
@@ -0,0 +1,26 @@
1
+ class Query
2
+
3
+ attr_accessor :keyword, :search_query, :min_price, :max_price
4
+
5
+ def parse(query_string)
6
+ query_array = query_string.split(" ")
7
+ self.keyword = query_array.shift
8
+ self.max_price = query_array.pop.to_i
9
+ self.min_price = query_array.pop.to_i
10
+ self.search_query = query_array.join(" ")
11
+ return self
12
+ end
13
+
14
+ def valid_query?
15
+ Runner.keywords.keys.include?(self.keyword) && self.search_query.is_a?(String) && self.max_price.is_a?(Integer) && self.min_price.is_a?(Integer)
16
+ end
17
+
18
+ def keyword_to_url
19
+ if keyword == "nyc"
20
+ ""
21
+ else
22
+ "/#{keyword}"
23
+ end
24
+ end
25
+
26
+ end
data/lib/runner.rb ADDED
@@ -0,0 +1,85 @@
1
+ class Runner
2
+
3
+ def self.keywords
4
+ {
5
+ "mnh" => "Manhattan",
6
+ "brk" => "Brooklyn",
7
+ "que" => "Queens",
8
+ "brx" => "The Bronx",
9
+ "stn" => "Staten Island",
10
+ "jsy" => "New Jersey",
11
+ "lgi" => "Long Island",
12
+ "wch" => "Westchester",
13
+ "fct" => "Fairfield",
14
+ "nyc" => "New York City",
15
+ }
16
+ end
17
+
18
+ def interface
19
+ on = true
20
+
21
+ while on do
22
+
23
+ puts "======================================="
24
+ puts "Hello! Welcome to AfterMarket Research."
25
+ puts
26
+ puts "Please enter your query in the following format:"
27
+ puts "[location keyword] [product query] [min price] [max price]"
28
+ puts
29
+ puts "(Type 'help' for more information, and type 'exit' to exit)"
30
+
31
+ raw_user_command = gets.chomp.downcase
32
+ query = Query.new.parse(raw_user_command)
33
+ # binding.pry
34
+ if query.valid_query?
35
+ puts "running search..."
36
+ puts
37
+ scraper = Scraper.new(query)
38
+ scraper.scrape
39
+ if scraper.product_rows.length > 0
40
+ analyzer = Analyzer.new(scraper.number_extraction)
41
+ analyzer.print_calculations
42
+ # puts
43
+ # puts "Would you like to see your search results? (Y/n)"
44
+ # to_web = gets.chomp.downcase
45
+ # if to_web == "y"
46
+ # binding.pry
47
+ # scraper.open_url
48
+ # end
49
+ else
50
+ puts "Sorry, your search returned no results."
51
+ end
52
+ elsif query.keyword == "help"
53
+ help
54
+ elsif query.keyword == "exit"
55
+ exit
56
+ on = false
57
+ else
58
+ puts "Invalid Query! Please try again. Hit 'enter' to continue."
59
+ gets
60
+ "Invalid Query"
61
+ end
62
+ end
63
+ end
64
+
65
+ def help
66
+ puts "Run a craigslist search by including four query terms, as follows:"
67
+ puts
68
+ puts "FIRST, the area key -- #{Runner.keywords} "
69
+ # area_array = keywords.each_with_object([]) {|key, value, array| array << "#{key}: #{value}"}
70
+ puts
71
+ puts "NEXT, your actual search. Feel free to format however you like, but please write it in quotes."
72
+ puts
73
+ puts "Finally, your minimum and maximum prices, as integers. These will be used to narrow the search."
74
+ puts
75
+ puts "Here is a sample search: \"brk 'macbook pro' 200 800\" "
76
+ puts
77
+ puts "Hit 'enter' to continue."
78
+ gets
79
+ end
80
+
81
+ def exit
82
+ puts "Thanks for using AfterMarket Research! Go get that surplus value!"
83
+ end
84
+
85
+ end
data/lib/scraper.rb ADDED
@@ -0,0 +1,33 @@
1
+ class Scraper
2
+
3
+ attr_accessor :query, :product_rows, :encoded_url
4
+
5
+ def initialize(query_object)
6
+ self.query = query_object
7
+ self.product_rows = []
8
+ end
9
+
10
+ def htmlify(string)
11
+ string.gsub(" ", "+")
12
+ end
13
+
14
+ def scrape
15
+ self.encoded_url = URI.encode("https://newyork.craigslist.org/search/sss#{query.keyword_to_url}?zoomToPosting=&catAbb=sss&query=#{htmlify(query.search_query)}&minAsk=#{query.min_price}&maxAsk=#{query.max_price}&sort=rel&excats=")
16
+ html = open(URI.parse(self.encoded_url)) # /sss?zo
17
+ cl_page = Nokogiri::HTML(html.read)
18
+ cl_page.css('div.content p.row').map do |product_row|
19
+ self.product_rows << product_row
20
+ end
21
+ end
22
+
23
+ def number_extraction
24
+ self.product_rows.map do |product_row|
25
+ product_row.css('span.l2 span.price').text[1..-1].to_i
26
+ end
27
+ end
28
+
29
+ def open_url # in development, not implemented
30
+ `open #{self.encoded_url}`
31
+ end
32
+
33
+ end
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: aftermarket_research
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Daniel Kronovet
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-02-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: nokogiri
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ description: Research and analyze second-hand price information through Craiglist
28
+ email: kronovet@gmail.com
29
+ executables:
30
+ - aftermarket_research
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - bin/aftermarket_research
35
+ - bin/runner.rb
36
+ - lib/aftermarket_research.rb
37
+ - lib/analyzer.rb
38
+ - lib/environment.rb
39
+ - lib/query.rb
40
+ - lib/runner.rb
41
+ - lib/scraper.rb
42
+ homepage: http://rubygems.org/gems/aftermarket_research
43
+ licenses:
44
+ - GNU GPL V2
45
+ metadata: {}
46
+ post_install_message:
47
+ rdoc_options: []
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - '>='
58
+ - !ruby/object:Gem::Version
59
+ version: '0'
60
+ requirements: []
61
+ rubyforge_project:
62
+ rubygems_version: 2.2.1
63
+ signing_key:
64
+ specification_version: 4
65
+ summary: Aftermarket Research from your Terminal
66
+ test_files: []