wfrmls 0.3.1 → 0.3.2

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.
@@ -1,9 +1,20 @@
1
- === 0.3.0 / 2010-01-22
2
-
3
- * 1 major enhancement
1
+ === 0.3.2 / 2010-02-25
4
2
 
5
- * Birthday!
3
+ * Short sale is included except for comps
4
+ * Tax data is finding fewer false positives
5
+ * Added CLI option -o # no tax data
6
+ * Clear search before starting new address search
7
+ * Show house details when comping
8
+ * No address will take you to search page
9
+ * Show Parking type and size
6
10
 
7
11
  === 0.3.1 / 2010-01-27
8
12
 
9
13
  * Added ability to comp
14
+
15
+ === 0.3.0 / 2010-01-22
16
+
17
+ * Login to site
18
+ * Search for property
19
+ * Show results in browser
20
+
data/bin/wfrmls CHANGED
@@ -22,6 +22,13 @@ password = config['password']
22
22
  ie = Watir::Browser.new
23
23
  mls = Wfrmls::IE.new(ie, username, password)
24
24
 
25
+ if options.address.empty?
26
+ begin
27
+ mls.lookup_address(nil)
28
+ rescue
29
+ exit
30
+ end
31
+ end
25
32
 
26
33
  addr = StreetAddress::US.parse(options.address)
27
34
  if addr.nil?
@@ -31,7 +38,11 @@ end
31
38
  puts addr
32
39
 
33
40
  if options.comp?
34
- mls.comp(addr)
41
+ details = mls.collect_property_details(addr)
42
+ puts details.to_yaml
43
+ mls.comp(addr, details)
44
+ elsif options.opposition?
45
+ mls.lookup_opposition(addr)
35
46
  else
36
47
  puts mls.collect_property_details(addr).to_yaml
37
48
  mls.lookup_address(addr)
@@ -1,7 +1,7 @@
1
1
  require 'wfrmls/ie'
2
2
 
3
3
  module Wfrmls
4
- VERSION = '0.3.1'
4
+ VERSION = '0.3.2'
5
5
 
6
6
  end
7
7
 
@@ -11,10 +11,8 @@ module Wfrmls #:nodoc:
11
11
  attr_reader :address
12
12
 
13
13
  def initialize(*args)
14
- address = ''
15
-
16
14
  argv = args.flatten
17
-
15
+
18
16
  opt = OptionParser.new do |opt|
19
17
  opt.banner = "Usage: #{script_name} [options] <address>"
20
18
  opt.version = version
@@ -27,25 +25,33 @@ module Wfrmls #:nodoc:
27
25
  @comp = true
28
26
  end
29
27
 
28
+ opt.on("-o", "Check opposition's sale") do
29
+ @opposition = true
30
+ end
31
+
30
32
  opt.on("-h", "-?", "--help", "Show this message") do
31
33
  puts opt
32
34
  exit
33
35
  end
34
-
36
+
35
37
  opt.on("-v", "--version", "Show #{script_name}'s version (#{version})") do
36
- puts version
38
+ puts version
37
39
  exit
38
- end
40
+ end
39
41
  end
40
-
42
+
41
43
  opt.parse!(argv)
42
44
  @address = argv.dup.join(' ')
43
- end
45
+ end
44
46
 
45
47
  def comp?
46
48
  @comp
47
49
  end
48
50
 
51
+ def opposition?
52
+ @opposition
53
+ end
54
+
49
55
  private
50
56
  def version
51
57
  Wfrmls::VERSION
@@ -11,6 +11,132 @@ module Wfrmls
11
11
  @ie = ie
12
12
  end
13
13
 
14
+ def lookup_address(addr)
15
+ find_address_on_search_page(addr)
16
+
17
+ if search_results_availible?
18
+ show_full_listings
19
+ else
20
+ show_tax_data(addr)
21
+ end
22
+ end
23
+
24
+ def lookup_opposition(addr)
25
+ find_address_on_search_page(addr)
26
+ show_listings
27
+ end
28
+
29
+ def comp(addr, house_details = collect_property_details(addr))
30
+ goto_search_page
31
+ historical_data
32
+ status
33
+ city(addr.city)
34
+ short_sale(false)
35
+
36
+ @ie.text_field(:id, 'days_back_status').set('120')
37
+
38
+
39
+ @ie.text_field(:name,'tot_sqf1').set((house_details[:house_size]-200).to_s)
40
+ @ie.text_field(:name,'tot_sqf2').set((house_details[:house_size]+200).to_s)
41
+
42
+ @ie.text_field(:name,'yearblt1').set((house_details[:year_built]-6).to_s)
43
+ @ie.text_field(:name,'yearblt2').set((house_details[:year_built]+6).to_s)
44
+
45
+ sleep_until(3) {
46
+ @ie.dd(:id,'left_search_criteria').text.include? 'Year Built at most'
47
+ }
48
+
49
+ show_full_listings
50
+ end
51
+
52
+ def collect_property_details(addr)
53
+ show_tax_data(addr) unless @ie.url.include? 'taxdata/details'
54
+
55
+ doc = @ie.xmlparser_document_object
56
+
57
+ details = {}
58
+
59
+ doc.search('tr/th').each do |item|
60
+ case nbsp2sp(item.text)
61
+ when /NAME:/
62
+ details[:owner] = item.parent.search('td').text
63
+ when /ADDRESS:/
64
+ details[:address] = item.parent.search('td').text.strip
65
+ when /PARCEL SPECIFIC INFO:/
66
+ nbsp2sp(item.parent.search('td').text) =~ /Total Acres: ([.0-9]+)/
67
+ details[:lot_size] = $1
68
+ when /VALUATION SPECIFIC INFO:/
69
+ nbsp2sp(item.parent.search('td').text) =~ /Final Value: (\$[0-9,]+)/
70
+ details[:tax_value] = $1
71
+ when /GENERAL INFO:/
72
+ nbsp2sp(item.parent.search('td').text) =~ /Yr Built: ([0-9]+)/
73
+ details[:year_built] = $1.to_i
74
+ when /AREA INFO:/
75
+ house_size = 0
76
+ data = nbsp2sp(item.parent.search('td').text)
77
+ data =~ /Main Floor Area: ([,0-9]+)/
78
+ house_size += $1.sub(',','').to_i if $1
79
+ data =~ /Basement Area: ([,0-9]+)/
80
+ house_size += $1.sub(',','').to_i if $1
81
+ data =~ /Upper Floor Area: ([,0-9]+)/
82
+ house_size += $1.sub(',','').to_i if $1
83
+ details[:house_size] = house_size
84
+ when /EXTERIOR:/
85
+ details[:exterior] ||= {}
86
+ data = nbsp2sp(item.parent.search('td').text)
87
+ data =~ /Ext. Wall Type: (\w+)/
88
+ details[:exterior][:wall] = $1
89
+ data =~ /Masonry Trim: (\w+)/
90
+ details[:exterior][:masonry_trim] = $1
91
+ when /CARPORT & GARAGE INFO:/
92
+ data = nbsp2sp(item.parent.search('td').text)
93
+ data =~ /(.*): ([0-9]+)/
94
+ details[:parking] = nil
95
+ if $1
96
+ details[:parking] = {}
97
+ details[:parking][$1] = $2.to_i
98
+ end
99
+ end
100
+ end
101
+
102
+ details
103
+ end
104
+
105
+ def show_tax_data(addr)
106
+ goto "http://www.utahrealestate.com/taxdata/index?county%5B%5D=2&county%5B%5D=8&searchtype=house&searchbox=#{addr.number}"
107
+
108
+ rows = find_tax_data_rows_by_house_and_street(addr)
109
+
110
+ case rows.size
111
+ when 0
112
+ puts "#{addr} not found in tax data"
113
+ when 1
114
+ click_link rows[0]
115
+ else
116
+ puts 'Possible matches:'
117
+ rows.each do |item|
118
+ puts item.cell(:class, 'last-col').text
119
+ end
120
+ regex = /\b#{addr.prefix}\b.*\b#{addr.suffix}/
121
+ rows = rows.inject([]) do |c, item|
122
+ c << item if regex.match item.cell(:class, 'last-col').text
123
+ c
124
+ end
125
+ case rows.size
126
+ when 0
127
+ puts "#{addr} not found with #{regex}"
128
+ when 1
129
+ click_link rows[0]
130
+ else
131
+ puts 'Possible matches:'
132
+ rows.each do |item|
133
+ puts item.cell(:class, 'last-col').text
134
+ end
135
+ end
136
+ end
137
+ end
138
+
139
+ private
14
140
  def login
15
141
  @ie.goto 'http://www.utahrealestate.com/auth/login/login_redirect//force_redirect/1'
16
142
  begin
@@ -24,57 +150,55 @@ module Wfrmls
24
150
  end
25
151
  end
26
152
 
27
- def residential_full_search
153
+ def historical_data
28
154
  @ie.radio(:id, 'historical_data_yes').set
29
155
  end
30
156
 
31
- def lookup_address(addr)
32
- goto 'http://www.utahrealestate.com/search/form/type/1/name/full?advanced_search=1'
33
- residential_full_search
157
+ def find_address_on_search_page(addr)
158
+ goto_search_page
159
+ historical_data
34
160
  status
161
+ short_sale
35
162
  address(addr)
163
+ end
36
164
 
37
- result_count = @ie.span(:id, 'action_search_count').text.to_i
38
-
39
- if result_count > 0
40
- show_full_listings
165
+ def short_sale(includes=true)
166
+ if includes
167
+ @ie.radio(:id, 'o_shortsale_4').click
41
168
  else
42
- show_tax_data(addr)
169
+ @ie.radio(:id, 'o_shortsale_8').click
43
170
  end
171
+ @ie.checkbox(:id, 'shortsale_2').click
172
+ @ie.checkbox(:id, 'shortsale_4').click
44
173
  end
45
174
 
46
- def show_full_listings
175
+ def search_results_availible?
176
+ result_count = @ie.span(:id, 'action_search_count').text.to_i > 0
177
+ end
178
+
179
+ def show_listings
180
+ return false unless search_results_availible?
47
181
  @ie.button(:id, 'SEARCH_button').click
48
182
  sleep_until { @ie.checkbox(:id, 'ListingController').exists? }
183
+ true
184
+ end
185
+
186
+ def show_full_listings
187
+ return unless show_listings
49
188
  @ie.checkbox(:id, 'ListingController').click
50
189
  @ie.select_list(:id, 'report-selector').set('Full Report')
51
190
  end
52
191
 
53
- def comp(addr)
54
- # TODO remove the sleeps
55
- house_details = collect_property_details(addr)
56
- goto 'http://www.utahrealestate.com/search/form/type/1/name/full?advanced_search=1'
57
-
58
- @ie.button(:id, 'CLEAR_button').click
59
-
60
- sleep 3
61
-
62
- residential_full_search
63
- status
64
- city(addr.city)
65
-
66
- @ie.text_field(:id, 'days_back_status').set('120')
67
-
68
-
69
- @ie.text_field(:name, 'tot_sqf1').set((house_details[:house_size] - 200).to_s)
70
- @ie.text_field(:name, 'tot_sqf2').set((house_details[:house_size] + 200).to_s)
71
-
72
- @ie.text_field(:name, 'yearblt1').set((house_details[:year_built] - 6).to_s)
73
- @ie.text_field(:name, 'yearblt2').set((house_details[:year_built] + 6).to_s)
74
-
75
- sleep 3
192
+ def goto_search_page
193
+ url = 'http://www.utahrealestate.com/search/form/type/1/name/full?advanced_search=1'
194
+ goto url
195
+ clear_search
196
+ goto url
197
+ end
76
198
 
77
- show_full_listings
199
+ def clear_search
200
+ @ie.button(:id,'CLEAR_button').click
201
+ sleep_until(3) { @ie.dd(:id, 'left_search_criteria').text !~ /City/ }
78
202
  end
79
203
 
80
204
  def status
@@ -106,30 +230,12 @@ module Wfrmls
106
230
  city(addr.city)
107
231
  end
108
232
 
109
- def sleep_until &block
233
+ def sleep_until max=10, &block
110
234
  count = 0
111
235
  until yield block
112
236
  sleep 1
113
237
  count += 1
114
- exit if count > 10
115
- end
116
- end
117
-
118
- def show_tax_data(addr)
119
- goto "http://www.utahrealestate.com/taxdata/index?county%5B%5D=2&county%5B%5D=8&searchtype=house&searchbox=#{addr.number}"
120
-
121
- rows = find_tax_data_rows_by_house_and_street(addr)
122
-
123
- case rows.size
124
- when 0
125
- puts "#{addr} not found in tax data"
126
- when 1
127
- click_link rows[0]
128
- else
129
- puts 'Possible matches:'
130
- rows.each do |item|
131
- puts item.cell(:class, 'last-col').text
132
- end
238
+ return if count > max
133
239
  end
134
240
  end
135
241
 
@@ -144,7 +250,7 @@ module Wfrmls
144
250
  rows << row
145
251
  end
146
252
  end
147
- rows
253
+ rows
148
254
  end
149
255
 
150
256
  def goto(url)
@@ -155,58 +261,6 @@ module Wfrmls
155
261
  end
156
262
  end
157
263
 
158
- def collect_property_details(addr)
159
- show_tax_data(addr) unless @ie.url.include? 'taxdata/details'
160
-
161
- doc = @ie.xmlparser_document_object
162
-
163
- details = {}
164
-
165
- doc.search('tr/th').each do |item|
166
- case nbsp2sp(item.text)
167
- when /NAME:/
168
- details[:owner] = item.parent.search('td').text
169
- when /ADDRESS:/
170
- details[:address] = item.parent.search('td').text.strip
171
- when /PARCEL SPECIFIC INFO:/
172
- nbsp2sp(item.parent.search('td').text) =~ /Total Acres: ([.0-9]+)/
173
- details[:lot_size] = $1
174
- when /VALUATION SPECIFIC INFO:/
175
- nbsp2sp(item.parent.search('td').text) =~ /Final Value: (\$[0-9,]+)/
176
- details[:tax_value] = $1
177
- when /GENERAL INFO:/
178
- nbsp2sp(item.parent.search('td').text) =~ /Yr Built: ([0-9]+)/
179
- details[:year_built] = $1.to_i
180
- when /AREA INFO:/
181
- house_size = 0
182
- data = nbsp2sp(item.parent.search('td').text)
183
- data =~ /Main Floor Area: ([,0-9]+)/
184
- house_size += $1.sub(',','').to_i if $1
185
- data =~ /Basement Area: ([,0-9]+)/
186
- house_size += $1.sub(',','').to_i if $1
187
- data =~ /Upper Floor Area: ([,0-9]+)/
188
- house_size += $1.sub(',','').to_i if $1
189
- details[:house_size] = house_size
190
- when /EXTERIOR:/
191
- details[:exterior] ||= {}
192
- data = nbsp2sp(item.parent.search('td').text)
193
- data =~ /Ext. Wall Type: (\w+)/
194
- details[:exterior][:wall] = $1
195
- data =~ /Masonry Trim: (\w+)/
196
- details[:exterior][:masonry_trim] = $1
197
- when /CARPORT & GARAGE INFO:/
198
- data = nbsp2sp(item.parent.search('td').text)
199
- data =~ /(.*): ([,0-9]+)/
200
- if $1
201
- key = $1.gsub(/[- ]/, '_').downcase.to_sym
202
- details[key] = $2
203
- end
204
- end
205
- end
206
-
207
- details
208
- end
209
-
210
264
  def nbsp2sp(s)
211
265
  s.gsub("\xC2\xA0", ' ')
212
266
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wfrmls
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - zhon
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-01-27 00:00:00 -07:00
12
+ date: 2010-02-25 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -30,7 +30,7 @@ dependencies:
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 0.3.0
33
+ version: 0.4.1
34
34
  version:
35
35
  - !ruby/object:Gem::Dependency
36
36
  name: hoe