libcraigscrape 0.5 → 0.6
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.
- data/CHANGELOG +15 -1
- data/README +4 -0
- data/Rakefile +40 -4
- data/bin/craigwatch +33 -14
- data/lib/libcraigscrape.rb +91 -23
- data/test/listing_samples/mia_fua_index8900.5.21.09.html +226 -0
- data/test/test_craigslist_listing.rb +19 -8
- metadata +6 -5
data/CHANGELOG
CHANGED
@@ -1,4 +1,18 @@
|
|
1
1
|
== Change Log
|
2
2
|
|
3
|
+
=== Release 0.6.0 (May 21, 2009)
|
4
|
+
- Added PostFull::flagged_for_removal?
|
5
|
+
- Fixed a couple small parse bugs found in production
|
6
|
+
- Added a ParseError object, which is raised on ... detected Parse errors. This raise will output the buggy parse, please send this over to me if you think CraigsScrape is actually wrong ..
|
7
|
+
- Adjusted the examples in the readme, added a "require 'rubygems'" to the top of the listing so that they would actually work if you tried to run them verbatim (Thanks J T!)
|
8
|
+
- Restructured some of the parsing to be less leinient when scraped values aren't matching their regexp's in the PostSummary
|
9
|
+
- It seems like craigslist returns a 404 on pages that exist, for no good reason on occasion. Added a retry mechanism that wont take no for an answer, unless we get a defineable number of them in a row
|
10
|
+
- Added CraigScrape cattr_accessors : retries_on_fetch_fail, sleep_between_fetch_retries .
|
11
|
+
- Adjusted craigwatch to not commit any database changes until the notification email goes out. This way if there's an error, the user wont miss any results on a re-run
|
12
|
+
- Added a FetchError for http requests that don't return 200 or redirect...
|
13
|
+
- Adjusted craigwatch to use scrape_until instead of scrape_since, this new approach cuts down on the url fetching by assuming that if we come across something we've already tracked, we dont need to keep going any further. NOTE: We still can't use a 'last_scraped_url' on the TrackedSearch model b/c sometimes posts get deleted.
|
14
|
+
- We're tracking all date-relevant posts now in craigwatch, not just the ones that matched the first time aorund, this should significantly speed up our scrapes
|
15
|
+
- Found an example of a screwy listing that was starting date h4's , but not actually listing the dates in them (see mia_fua_index8900.5.21.09.html test case). Added test case - handled appropriately. Seems like a bug in craigslist itself.
|
16
|
+
|
3
17
|
=== Release 0.5.0 (April 30, 2009)
|
4
|
-
|
18
|
+
- First release. Not much to say - hopefully someone else finds this useful.
|
data/README
CHANGED
@@ -21,6 +21,7 @@ Install via RubyGems:
|
|
21
21
|
|
22
22
|
Using the search url http://miami.craigslist.org/search/sss?query=apple
|
23
23
|
|
24
|
+
require 'rubygems'
|
24
25
|
require 'libcraigscrape'
|
25
26
|
require 'date'
|
26
27
|
require 'pp'
|
@@ -34,6 +35,7 @@ Using the search url http://miami.craigslist.org/search/sss?query=apple
|
|
34
35
|
|
35
36
|
Under the category url http://miami.craigslist.org/apa/
|
36
37
|
|
38
|
+
require 'rubygems'
|
37
39
|
require 'libcraigscrape'
|
38
40
|
require 'pp'
|
39
41
|
|
@@ -46,6 +48,7 @@ Under the category url http://miami.craigslist.org/apa/
|
|
46
48
|
|
47
49
|
This grabs the full details under the specific post http://miami.craigslist.org/mdc/sys/1140808860.html
|
48
50
|
|
51
|
+
require 'rubygems'
|
49
52
|
require 'libcraigscrape'
|
50
53
|
|
51
54
|
post = CraigScrape.scrape_full_post 'http://miami.craigslist.org/mdc/sys/1140808860.html'
|
@@ -55,6 +58,7 @@ This grabs the full details under the specific post http://miami.craigslist.org/
|
|
55
58
|
|
56
59
|
This grabs the post summaries of the single listings at http://miami.craigslist.org/search/sss?query=laptop
|
57
60
|
|
61
|
+
require 'rubygems'
|
58
62
|
require 'libcraigscrape'
|
59
63
|
|
60
64
|
listing = CraigScrape.scrape_listing 'http://miami.craigslist.org/search/sss?query=laptop'
|
data/Rakefile
CHANGED
@@ -4,16 +4,19 @@ require 'rake/gempackagetask'
|
|
4
4
|
require 'rake/rdoctask'
|
5
5
|
require 'rake/testtask'
|
6
6
|
require 'fileutils'
|
7
|
+
require 'tempfile'
|
8
|
+
|
7
9
|
include FileUtils
|
8
10
|
|
9
11
|
RbConfig = Config unless defined? RbConfig
|
10
12
|
|
11
13
|
NAME = "libcraigscrape"
|
12
|
-
VERS = ENV['VERSION'] || "0.
|
14
|
+
VERS = ENV['VERSION'] || "0.6"
|
13
15
|
PKG = "#{NAME}-#{VERS}"
|
14
16
|
|
15
17
|
RDOC_OPTS = ['--quiet', '--title', 'The libcraigscrape Reference', '--main', 'README', '--inline-source']
|
16
|
-
|
18
|
+
RDOC_FILES = ['README', "CHANGELOG", "COPYING","COPYING.LESSER", 'bin/craigwatch']
|
19
|
+
PKG_FILES = (%w(Rakefile) + RDOC_FILES + Dir.glob("{bin,test,lib}/**/*")).uniq
|
17
20
|
|
18
21
|
SPEC =
|
19
22
|
Gem::Specification.new do |s|
|
@@ -24,7 +27,7 @@ SPEC =
|
|
24
27
|
s.bindir = 'bin'
|
25
28
|
s.executables = 'craigwatch'
|
26
29
|
s.rdoc_options += RDOC_OPTS
|
27
|
-
s.extra_rdoc_files =
|
30
|
+
s.extra_rdoc_files = RDOC_FILES
|
28
31
|
s.summary = "quick, easy, craigslist parsing library that takes the monotony out of working with craigslist posts and listings"
|
29
32
|
s.description = s.summary
|
30
33
|
s.author = "Chris DeRose, DeRose Technologies, Inc."
|
@@ -50,7 +53,7 @@ Rake::RDocTask.new do |rdoc|
|
|
50
53
|
rdoc.rdoc_dir = 'doc/rdoc'
|
51
54
|
rdoc.options += RDOC_OPTS
|
52
55
|
rdoc.main = "README"
|
53
|
-
rdoc.rdoc_files.add ['
|
56
|
+
rdoc.rdoc_files.add RDOC_FILES+['lib/**/*.rb']
|
54
57
|
end
|
55
58
|
|
56
59
|
Rake::GemPackageTask.new(SPEC) do |p|
|
@@ -70,3 +73,36 @@ end
|
|
70
73
|
task :uninstall => [:clean] do
|
71
74
|
sh %{sudo gem uninstall #{NAME}}
|
72
75
|
end
|
76
|
+
|
77
|
+
task :pkg_archives do
|
78
|
+
base_dir = File.dirname __FILE__
|
79
|
+
package_name = '%s-%s' % [NAME,VERS]
|
80
|
+
packages_base = "#{base_dir}/pkg"
|
81
|
+
packaging_dir = '%s/%s' % [ packages_base,package_name ]
|
82
|
+
|
83
|
+
begin
|
84
|
+
# First we create a proper package-X.X directory:
|
85
|
+
PKG_FILES.each do |p_f|
|
86
|
+
base_file = '%s/%s' % [base_dir, p_f]
|
87
|
+
packaged_file = '%s/%s' % [packaging_dir, p_f]
|
88
|
+
packaged_file_dirname = File.dirname packaged_file
|
89
|
+
|
90
|
+
# We really don't care to do anything about these - we'll recreate it when/if its needed
|
91
|
+
next if File.directory? base_file
|
92
|
+
|
93
|
+
FileUtils.mkdir_p packaged_file_dirname unless File.directory? packaged_file_dirname
|
94
|
+
|
95
|
+
FileUtils.cp base_file, packaged_file unless File.exists? packaged_file
|
96
|
+
end
|
97
|
+
|
98
|
+
# Remove any old archives we'd be replacing:
|
99
|
+
%w(zip tar.bz2).each{ |ext| FileUtils.rm "#{packaging_dir}.#{ext}" if File.exist? "#{packaging_dir}.#{ext}" }
|
100
|
+
|
101
|
+
# Now let's create some archives:
|
102
|
+
sh %{cd #{packages_base} && tar -cjvf #{package_name}.tar.bz2 #{package_name}}
|
103
|
+
sh %{cd #{packages_base} && zip -r #{package_name}.zip #{package_name}}
|
104
|
+
ensure
|
105
|
+
# Delete that temp directory we created at the start here
|
106
|
+
FileUtils.rmtree packaging_dir
|
107
|
+
end
|
108
|
+
end
|
data/bin/craigwatch
CHANGED
@@ -320,9 +320,11 @@ ActiveRecord::Schema.define do
|
|
320
320
|
end
|
321
321
|
end
|
322
322
|
|
323
|
-
#
|
323
|
+
# We'll need these outside this next loop:
|
324
324
|
report_summaries = []
|
325
|
+
newly_tracked_posts = []
|
325
326
|
|
327
|
+
# Now let's run a report:
|
326
328
|
craig_report.each_search do |search|
|
327
329
|
|
328
330
|
# Load our tracking info
|
@@ -333,35 +335,43 @@ craig_report.each_search do |search|
|
|
333
335
|
|
334
336
|
last_tracked_at = (search_track.last_tracked_at) ? search_track.last_tracked_at : search.starting_at
|
335
337
|
|
338
|
+
already_tracked_urls = search_track.tracked_posts.collect{|tp| tp.url}
|
339
|
+
|
336
340
|
# Let's collect all the summaries that could apply:
|
337
341
|
new_summaries = {}
|
338
342
|
search.listing.each do |listing|
|
339
|
-
CraigScrape.
|
340
|
-
new_summaries[p_s.full_url] = p_s unless new_summaries.has_key? p_s.full_url
|
343
|
+
CraigScrape.scrape_until(listing){|p| p.date <= last_tracked_at or already_tracked_urls.include? p.full_url }.each do |p_s|
|
344
|
+
new_summaries[p_s.full_url] = p_s unless new_summaries.has_key? p_s.full_url
|
341
345
|
end
|
342
346
|
end
|
343
|
-
|
347
|
+
|
344
348
|
# Let's flatten the unique'd hash into a more useable array:
|
345
349
|
new_summaries = new_summaries.values.sort{|a,b| a.date <=> b.date} # oldest goes to bottom
|
346
350
|
|
347
|
-
#
|
351
|
+
# Let's tag all the newest tracked posts that should go into the database:
|
352
|
+
# NOTE: Since all the dates are at_begining_of_day, we'll effectively have a chunk of dates tied for latest
|
353
|
+
new_summaries.reject{|p| p.date < new_summaries.last.date}.each do |p_s|
|
354
|
+
newly_tracked_posts << search_track.tracked_posts.build( :url => p_s.full_url, :created_at => p_s.date)
|
355
|
+
end
|
356
|
+
|
357
|
+
# Reject anything from this report which doesn't match the has/has_no :
|
348
358
|
new_summaries.reject!{|s| !search.passes_filter? s }
|
349
359
|
|
350
360
|
# Now Let's manage the tracking database:
|
351
361
|
if new_summaries.length > 0
|
352
|
-
|
353
|
-
#
|
354
|
-
|
355
|
-
search_track.tracked_posts.create! :url => p_s.full_url, :created_at => p_s.date
|
356
|
-
end
|
357
|
-
|
358
|
-
# Remove all tracked posts older then we could need:
|
359
|
-
TrackedPost.delete_all ['tracked_search_id = ? AND created_at < ?', search_track.id, new_summaries.last.date ]
|
362
|
+
|
363
|
+
# We'll use this in the cleanup at the bottom:
|
364
|
+
latest_post_date = new_summaries.last.date
|
360
365
|
|
361
366
|
new_summaries.reverse! if search.newest_first?
|
362
367
|
|
363
368
|
# We'll want to email these...
|
364
|
-
report_summaries << {
|
369
|
+
report_summaries << {
|
370
|
+
:postings => new_summaries,
|
371
|
+
:search => search,
|
372
|
+
:search_track => search_track,
|
373
|
+
:latest_post_date => latest_post_date
|
374
|
+
}
|
365
375
|
end
|
366
376
|
end
|
367
377
|
|
@@ -372,3 +382,12 @@ ReportMailer.deliver_report(
|
|
372
382
|
craig_report.report_name,
|
373
383
|
{:summaries => report_summaries, :definition => craig_report}
|
374
384
|
) if report_summaries.length > 0
|
385
|
+
|
386
|
+
# Save the newly created posts:
|
387
|
+
newly_tracked_posts.each{|tp| tp.save!}
|
388
|
+
|
389
|
+
# Now that we know the user has been informed, Let's commit all our database changes and end this scrape 'transaction':
|
390
|
+
report_summaries.each do |s|
|
391
|
+
# Let's do some light cleanup to keep the database size down, by removing all the old posts we're no longer tracking:
|
392
|
+
TrackedPost.delete_all [ 'tracked_search_id = ? AND created_at < ?', s[:search_track].id, s[:latest_post_date] ]
|
393
|
+
end
|
data/lib/libcraigscrape.rb
CHANGED
@@ -13,6 +13,12 @@ require 'activesupport'
|
|
13
13
|
class CraigScrape
|
14
14
|
cattr_accessor :logger
|
15
15
|
cattr_accessor :time_now
|
16
|
+
cattr_accessor :retries_on_fetch_fail
|
17
|
+
cattr_accessor :sleep_between_fetch_retries
|
18
|
+
|
19
|
+
# Set some defaults:
|
20
|
+
self.retries_on_fetch_fail = 4
|
21
|
+
self.sleep_between_fetch_retries = 4
|
16
22
|
|
17
23
|
def self.most_recently_expired_time(month, day) #:nodoc:
|
18
24
|
now = (time_now) ? time_now : Time.now
|
@@ -30,6 +36,12 @@ class CraigScrape
|
|
30
36
|
end
|
31
37
|
end
|
32
38
|
|
39
|
+
class ParseError < StandardError #:nodoc:
|
40
|
+
end
|
41
|
+
|
42
|
+
class FetchError < StandardError #:nodoc:
|
43
|
+
end
|
44
|
+
|
33
45
|
# PostFull represents a fully downloaded, and parsed, Craigslist post.
|
34
46
|
# This class is generally returned by the listing scrape methods, and
|
35
47
|
# contains the post summaries for a specific search url, or a general listing category
|
@@ -68,14 +80,18 @@ class CraigScrape
|
|
68
80
|
POSTING_ID = /PostingID\:[ ]+([\d]+)/
|
69
81
|
REPLY_TO = /(.+)/
|
70
82
|
PRICE = /\$([\d]+(?:\.[\d]{2})?)/
|
83
|
+
HTML_TAG = /<\/?[^>]*>/
|
71
84
|
|
72
85
|
def initialize(page) #:nodoc:
|
73
86
|
# We proceed from easy to difficult:
|
74
87
|
|
75
88
|
@images = []
|
76
89
|
|
77
|
-
|
78
|
-
@
|
90
|
+
h2 = page.at('h2')
|
91
|
+
@header = he_decode h2.inner_html if h2
|
92
|
+
|
93
|
+
title = page.at('title')
|
94
|
+
@title = he_decode title.inner_html if title
|
79
95
|
@title = nil if @title.length ==0
|
80
96
|
|
81
97
|
@full_section = []
|
@@ -99,7 +115,7 @@ class CraigScrape
|
|
99
115
|
@posting_id = $1.to_i if $1
|
100
116
|
|
101
117
|
# OK - so the biggest problem parsing the contents of a craigslist post is that users post invalid html all over the place
|
102
|
-
#
|
118
|
+
# This bad html trips up hpricot, and I've resorted to splitting the page up using string parsing like so:
|
103
119
|
userbody_as_s,craigbody_as_s = $1, $2 if /\<div id\=\"userbody\">(.+)\<br[ ]*[\/]?\>\<br[ ]*[\/]?\>(.+)\<\/div\>/m.match page.to_s
|
104
120
|
|
105
121
|
# Contents:
|
@@ -108,17 +124,23 @@ class CraigScrape
|
|
108
124
|
# I made this a separate method since we're not actually parsing everything in here as-is.
|
109
125
|
# This will make it easier for the next guy to work with if wants to parse out the information we're disgarding...
|
110
126
|
parse_craig_body Hpricot.parse(craigbody_as_s) if craigbody_as_s
|
127
|
+
|
128
|
+
# Validate that required fields are present:
|
129
|
+
raise ParseError, "Unable to parse PostFull: %s" % page.to_html if !flagged_for_removal? and [
|
130
|
+
@contents,@posting_id,@post_time,@header,@title,@full_section
|
131
|
+
].any?{|f| f.nil? or (f.respond_to? :length and f.length == 0)}
|
111
132
|
end
|
112
133
|
|
134
|
+
# I left this here as a stub, since someone may want to parse more then what I'm currently scraping from this part of the page
|
113
135
|
def parse_craig_body(craigbody_els) #:nodoc:
|
114
136
|
# Location (when explicitly defined):
|
115
|
-
cursor = craigbody_els.at
|
116
|
-
cursor = cursor.at
|
117
|
-
@location = he_decode
|
137
|
+
cursor = craigbody_els.at 'ul'
|
138
|
+
cursor = cursor.at 'li' if cursor
|
139
|
+
@location = he_decode $1 if cursor and LOCATION.match cursor.inner_html
|
118
140
|
|
119
141
|
# Real estate listings can work a little different for location:
|
120
142
|
unless @location
|
121
|
-
cursor = craigbody_els.at
|
143
|
+
cursor = craigbody_els.at 'small'
|
122
144
|
cursor = cursor.previous_node until cursor.nil? or cursor.text?
|
123
145
|
|
124
146
|
@location = he_decode(cursor.to_s.strip) if cursor
|
@@ -130,6 +152,14 @@ class CraigScrape
|
|
130
152
|
@images = (img_table / 'img').collect{|i| i[:src]} if img_table
|
131
153
|
end
|
132
154
|
|
155
|
+
# Returns true if this Post was parsed, and merely a 'Flagged for Removal' page
|
156
|
+
def flagged_for_removal?
|
157
|
+
(
|
158
|
+
[@contents,@posting_id,@post_time,@title].all?{|f| f.nil?} and
|
159
|
+
@header.gsub(HTML_TAG, "") == "This posting has been flagged for removal"
|
160
|
+
)
|
161
|
+
end
|
162
|
+
|
133
163
|
# Returns the price (as float) of the item, as best ascertained by the post header
|
134
164
|
def price
|
135
165
|
$1.to_f if @title and @header and PRICE.match(@header.gsub(/#{@title}/, ''))
|
@@ -137,7 +167,7 @@ class CraigScrape
|
|
137
167
|
|
138
168
|
# Returns the post contents with all html tags removed
|
139
169
|
def contents_as_plain
|
140
|
-
@contents.gsub
|
170
|
+
@contents.gsub HTML_TAG, "" if @contents
|
141
171
|
end
|
142
172
|
end
|
143
173
|
|
@@ -175,6 +205,9 @@ class CraigScrape
|
|
175
205
|
|
176
206
|
# This will find the link on 'search listing' pages (if there is one):
|
177
207
|
@next_page_href = next_link[:href] if next_link
|
208
|
+
|
209
|
+
# Validate that required fields are present:
|
210
|
+
raise ParseError, "Unable to parse Listings: %s" % page.to_html unless @posts.length > 0
|
178
211
|
end
|
179
212
|
|
180
213
|
end
|
@@ -213,8 +246,8 @@ class CraigScrape
|
|
213
246
|
location_tag = p_element.at 'font'
|
214
247
|
has_pic_tag = p_element.at 'span'
|
215
248
|
|
216
|
-
|
217
|
-
@location = $1 if LOCATION.match
|
249
|
+
location = he_decode p_element.at('font').inner_html if location_tag
|
250
|
+
@location = $1 if location and LOCATION.match location
|
218
251
|
|
219
252
|
@img_types = []
|
220
253
|
if has_pic_tag
|
@@ -231,11 +264,17 @@ class CraigScrape
|
|
231
264
|
@date = CraigScrape.most_recently_expired_time $1, $2.to_i
|
232
265
|
end
|
233
266
|
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
267
|
+
if title_anchor
|
268
|
+
label = he_decode title_anchor.inner_html
|
269
|
+
@label = $1 if LABEL.match label
|
270
|
+
|
271
|
+
@href = title_anchor[:href]
|
272
|
+
end
|
273
|
+
|
238
274
|
@base_url = base_url
|
275
|
+
|
276
|
+
# Validate that required fields are present:
|
277
|
+
raise ParseError, "Unable to parse PostSummary: %s" % p_element.to_html if [@label,@href].any?{|f| f.nil? or f.length == 0}
|
239
278
|
end
|
240
279
|
|
241
280
|
# Returns the full uri including host and scheme, not just the href
|
@@ -275,7 +314,13 @@ class CraigScrape
|
|
275
314
|
def self.scrape_listing(listing_url)
|
276
315
|
current_uri = ( listing_url.class == String ) ? URI.parse(listing_url) : listing_url
|
277
316
|
|
278
|
-
|
317
|
+
uri_contents = self.fetch_url(current_uri)
|
318
|
+
|
319
|
+
CraigScrape::Listings.new Hpricot.parse(uri_contents), '%s://%s' % [current_uri.scheme, current_uri.host]
|
320
|
+
|
321
|
+
rescue ParseError
|
322
|
+
puts "Encountered error here! : #{uri_contents.inspect}"
|
323
|
+
exit
|
279
324
|
end
|
280
325
|
|
281
326
|
# Continually scrapes listings, using the supplied url as a starting point, until the supplied block returns true or
|
@@ -323,17 +368,40 @@ class CraigScrape
|
|
323
368
|
end
|
324
369
|
|
325
370
|
def self.fetch_url(uri) #:nodoc:
|
326
|
-
|
327
|
-
uri_dest = ( uri.class == String ) ? URI.parse(uri) : uri
|
328
|
-
|
329
|
-
logger.info "Requesting: %s" % uri_dest.to_s unless logger.nil?
|
371
|
+
fetch_attempts = 0
|
330
372
|
|
331
|
-
|
373
|
+
begin
|
374
|
+
# This handles the redirects for us
|
375
|
+
uri_dest = ( uri.class == String ) ? URI.parse(uri) : uri
|
376
|
+
|
377
|
+
logger.info "Requesting: %s" % uri_dest.to_s if logger
|
378
|
+
|
379
|
+
resp, data = Net::HTTP.new( uri_dest.host, uri_dest.port).get uri_dest.request_uri, nil
|
380
|
+
|
381
|
+
if resp.response.code == "200"
|
382
|
+
data
|
383
|
+
elsif resp.response['Location']
|
384
|
+
redirect_to = resp.response['Location']
|
385
|
+
self.fetch_url(redirect_to)
|
386
|
+
else
|
387
|
+
# Sometimes Craigslist seems to return 404's for no good reason, and a subsequent fetch will give you what you want
|
388
|
+
error_description = 'Unable to fetch "%s" (%s)' % [ uri_dest.to_s, resp.response.code ]
|
332
389
|
|
333
|
-
|
334
|
-
|
390
|
+
logger.info error_description if logger
|
391
|
+
|
392
|
+
raise FetchError, error_description
|
393
|
+
end
|
394
|
+
rescue FetchError => err
|
395
|
+
fetch_attempts += 1
|
396
|
+
|
397
|
+
if retries_on_fetch_fail <= CraigScrape.retries_on_fetch_fail
|
398
|
+
sleep CraigScrape.sleep_between_fetch_retries if CraigScrape.sleep_between_fetch_retries
|
399
|
+
retry
|
400
|
+
else
|
401
|
+
raise err
|
402
|
+
end
|
403
|
+
end
|
335
404
|
|
336
|
-
(redirect_to) ? self.fetch_url(redirect_to) : data
|
337
405
|
end
|
338
406
|
|
339
407
|
def self.uri_from_href(base_uri, href) #:nodoc:
|
@@ -0,0 +1,226 @@
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
2
|
+
<html><head>
|
3
|
+
<title>south florida furniture - all classifieds - craigslist</title>
|
4
|
+
|
5
|
+
<meta name="description" content="craigslist furniture - all classifieds for south florida ">
|
6
|
+
<meta name="keywords" content="south florida furniture - all craigslist, classifieds, want ads ">
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
<link rel=alternate type="application/rss+xml" href="index.rss" title="RSS feed for craigslist | furniture - all in south florida ">
|
11
|
+
<link rel="stylesheet" title="craigslist" href="http://www.craigslist.org/styles/craigslist.css" type="text/css" media="all">
|
12
|
+
</head>
|
13
|
+
|
14
|
+
<body class="toc">
|
15
|
+
|
16
|
+
<a name="top"></a>
|
17
|
+
|
18
|
+
<div class="bchead"><span id="ef">
|
19
|
+
|
20
|
+
[ <a href="http://www.craigslist.org/about/help/">help</a> ]
|
21
|
+
[ <a href="https://post.craigslist.org/mia/S">post</a> ]</span>
|
22
|
+
|
23
|
+
<a href="/"> south florida craigslist</a> > <a href="/fua/">furniture - all</a><div id="satabs"> <b>all south florida</b> <a href="/mdc/fua/">miami / dade</a> <a href="/brw/fua/">broward county</a> <a href="/pbc/fua/">palm beach co</a> </div>
|
24
|
+
</div>
|
25
|
+
|
26
|
+
<blockquote>
|
27
|
+
<form action="/search/fua" method="get" onsubmit="ckCAbb();">
|
28
|
+
|
29
|
+
<script type="text/javascript"><!--
|
30
|
+
function ckCAbb() {
|
31
|
+
t = document.getElementById("cAbb");
|
32
|
+
if (t.value == "fua") { t.disabled = true; }
|
33
|
+
}
|
34
|
+
-->
|
35
|
+
</script>
|
36
|
+
|
37
|
+
<table width="95%" cellpadding="2" style="white-space: nowrap; background:#eee; border:1px solid gray;" summary="">
|
38
|
+
<tr>
|
39
|
+
<td align="right" width="1">search for:</td>
|
40
|
+
<td width="30%"><input id="query" name="query" size="30" value=""> in:
|
41
|
+
<select id="cAbb" name="catAbbreviation">
|
42
|
+
<option value="ccc">all community<option value="eee">all event<option value="sss">all for sale / wanted<option disabled value="">--<option value="art"> art & crafts
|
43
|
+
<option value="pts"> auto parts
|
44
|
+
<option value="bab"> baby & kid stuff
|
45
|
+
<option value="bar"> barter
|
46
|
+
<option value="bik"> bicycles
|
47
|
+
<option value="boa"> boats
|
48
|
+
<option value="bks"> books
|
49
|
+
<option value="bfs"> business
|
50
|
+
<option value="cta"> cars & trucks - all
|
51
|
+
<option value="ctd"> cars & trucks - by dealer
|
52
|
+
<option value="cto"> cars & trucks - by owner
|
53
|
+
<option value="emd"> cds / dvds / vhs
|
54
|
+
<option value="clo"> clothing
|
55
|
+
<option value="clt"> collectibles
|
56
|
+
<option value="sys"> computers & tech
|
57
|
+
<option value="ele"> electronics
|
58
|
+
<option value="grd"> farm & garden
|
59
|
+
<option value="zip"> free stuff
|
60
|
+
<option value="fua" selected> furniture - all
|
61
|
+
<option value="fud"> furniture - by dealer
|
62
|
+
<option value="fuo"> furniture - by owner
|
63
|
+
<option value="tag"> games & toys
|
64
|
+
<option value="gms"> garage sales
|
65
|
+
<option value="for"> general
|
66
|
+
<option value="hsh"> household
|
67
|
+
<option value="wan"> items wanted
|
68
|
+
<option value="jwl"> jewelry
|
69
|
+
<option value="mat"> materials
|
70
|
+
<option value="mcy"> motorcycles/scooters
|
71
|
+
<option value="msg"> musical instruments
|
72
|
+
<option value="pho"> photo/video
|
73
|
+
<option value="rvs"> recreational vehicles
|
74
|
+
<option value="spo"> sporting goods
|
75
|
+
<option value="tix"> tickets
|
76
|
+
<option value="tls"> tools
|
77
|
+
<option disabled value="">--<option value="ggg">all gigs<option value="hhh">all housing<option value="jjj">all jobs<option value="ppp">all personals<option value="res">all resume<option value="bbb">all services offered</select>
|
78
|
+
<input type="submit" value="Search">
|
79
|
+
</td><td>
|
80
|
+
<label><input type="checkbox" name="srchType" value="T"
|
81
|
+
title="check this box to search only posting titles"> only search titles</label>
|
82
|
+
</td>
|
83
|
+
</tr>
|
84
|
+
|
85
|
+
<tr>
|
86
|
+
<td align="right" width="1">price:</td>
|
87
|
+
<td><input name="minAsk" size="6" value="min" onfocus="value=''"> <input name="maxAsk" size="6" value="max" onfocus="value=''"> </td>
|
88
|
+
<td align="left"><label><input type="checkbox" name="hasPic" value="1"> has image</label></td>
|
89
|
+
</tr></table></form></blockquote><span id="showPics"></span><span id="hidePics"></span>
|
90
|
+
|
91
|
+
<blockquote>
|
92
|
+
<table width="95%" summary="">
|
93
|
+
<tr>
|
94
|
+
<td valign="top">[ Thu, 21 May 19:27:50 ]</td>
|
95
|
+
<td valign="top" id="messages"><span class="hl"> [ <a href="/about/prohibited.items">partial list of prohibited items</a> ] </span> <span class="hl"> [ <a href="http://www.recalls.gov/">avoid recalled items</a> ] </span> <span class="hl"> [ <b><a href="/about/safety">PERSONAL SAFETY TIPS</a></b> ] </span> <span class="hl"> [ <b><a href="/about/scams">AVOIDING SCAMS & FRAUD</a></b> ] </span> <span class="hl"> [<a href="/cgi-bin/success.stories.cgi">success story?</a>]</span> </td>
|
96
|
+
</tr>
|
97
|
+
</table>
|
98
|
+
|
99
|
+
<h4>Fri May 15</h4>
|
100
|
+
<p><a href="/brw/fuo/1171713452.html">Wood Office Shelf - $250 -</a><font size="-1"> (Coconut Creek)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
101
|
+
<p><a href="/mdc/fuo/1171708187.html">_+_+_+_ $ 35 _+_+_+_ -</a><font size="-1"> (***** Miami Beach *****)</font> <span class="p"> img</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
102
|
+
<p><a href="/brw/fuo/1171707696.html">Leather sofa - damage on one arm - $100 -</a><font size="-1"> (Margate, FL)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
103
|
+
<p><a href="/brw/fuo/1171705893.html">Keelan 2PC Sofa Set -</a><font size="-1"> (Davie)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
104
|
+
<p><a href="/brw/fuo/1171703787.html">Wood TV stand and end table - $70 -</a><font size="-1"> (Margate, FL)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
105
|
+
<p><a href="/brw/fuo/1171703282.html">Sofabed(queen), love seat, 2 tables - $500 -</a><font size="-1"> (Broward)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
106
|
+
<p><a href="/brw/fuo/1171697270.html">Glass top coffee table and end table - $60 -</a><font size="-1"> (Margate, FL)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
107
|
+
<h4></h4>
|
108
|
+
<p><a href="/brw/fuo/1171694683.html">Bassett Sofa and Chair and a half - $350 -</a><font size="-1"> (Margate, FL)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
109
|
+
<h4>Fri May 15</h4>
|
110
|
+
<p><a href="/brw/fuo/1171689641.html">KING SIZE WATER BED -</a><font size="-1"> (Oakland Park)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
111
|
+
<p><a href="/mdc/fuo/1171689432.html">Big Red Bed Couch with Cover -</a><font size="-1"> (Coral Gables)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
112
|
+
<p><a href="/brw/fuo/1171679181.html">Printer Stand - $25 -</a><font size="-1"> (Parkland)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
113
|
+
<p><a href="/brw/fuo/1171673408.html">Bedroom Furniture Set - $100 -</a><font size="-1"> (Parkland)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
114
|
+
<p><a href="/brw/fuo/1171683390.html">LIGHT RATTAN TABLE CHAIRS (4) - $40 -</a><font size="-1"> (HOLLYWOOD)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
115
|
+
<p><a href="/brw/fuo/1171680733.html">amazing furniture -</a><font size="-1"> (hollywood)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
116
|
+
<h4>Thu May 14</h4>
|
117
|
+
<p><a href="/mdc/fud/1171659425.html">BLACK AND WHITE COFFEE TABLE - $179 -</a><font size="-1"> (MIAMI)</font> <span class="p"> pic</span> <<<i><a href="/fud/">furniture by dealer</a></i></p>
|
118
|
+
<p><a href="/mdc/fuo/1171655834.html">ESTATE SALE -</a><font size="-1"> (SUNNY ISLES BEACH)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
119
|
+
<p><a href="/brw/fuo/1171654085.html">Patio Set - round w/ 4 chairs, wrought iron, quality, scroll design - $100 -</a><font size="-1"> (East Deerfield beach)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
120
|
+
<p><a href="/mdc/fuo/1171645673.html">White Floor Lamp - $35 -</a><font size="-1"> (NMB)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
121
|
+
<p><a href="/mdc/fuo/1171640310.html">3 piece wall unit - $165 -</a><font size="-1"> (NMB)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
122
|
+
<p><a href="/pbc/fuo/1171636316.html">Black Lacquer Dining Room Set - $1750 -</a><font size="-1"> (Lake Worth)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
123
|
+
<p><a href="/brw/fuo/1171634083.html">Piano- Baby Grand - $4800 -</a><font size="-1"> (Hollywood, Florida)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
124
|
+
<p><a href="/brw/fuo/1171045933.html">Beautiful Elephant Glass Table - $190 -</a><font size="-1"> (Lighthouse Point, FL)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
125
|
+
<p><a href="/brw/fuo/1171620976.html">$$$$$$ *** DINING ROOM HUTCH *** dark brown / lots of room - $75 -</a><font size="-1"> (Coral Springs)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
126
|
+
<p><a href="/pbc/fuo/1171618625.html">BEAUTIFUL SOUTHWESTERN HUTCH - $1100 -</a><font size="-1"> (Boca Raton, Florida)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
127
|
+
<p><a href="/brw/fuo/1171605305.html">Extraordinary Murals & Faux Finishings by Jorde!!bca -</a> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
128
|
+
<p><a href="/brw/fuo/1171609292.html">armoire - $290 -</a><font size="-1"> (Fort Lauderdale)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
129
|
+
<p><a href="/mdc/fuo/1171608196.html">Queen Sleigh Bed - Natural Finish - $300 -</a><font size="-1"> (Kendall)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
130
|
+
<p><a href="/brw/fuo/1171592461.html">Safari Home Decor - $1 -</a> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
131
|
+
<p><a href="/brw/fuo/1171598534.html">Antique french cabinet - $890 -</a><font size="-1"> (Fort Lauderdale)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
132
|
+
<p><a href="/mdc/fuo/1171047868.html">bunk bed desk drawer set - $450 -</a><font size="-1"> (miami beach)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
133
|
+
<p><a href="/pbc/fuo/1171597616.html">RED microfiber sectional couch - $300 -</a><font size="-1"> (Lake Worth/Greenacres)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
134
|
+
<p><a href="/mdc/fuo/1171595497.html">Wood Futon - $50 -</a><font size="-1"> (Coral Gables)</font> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
135
|
+
<p><a href="/brw/fuo/1171595817.html">furniture for sale - $1200 -</a><font size="-1"> (ft lauderdale)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
136
|
+
<p><a href="/brw/fuo/1171595527.html">New King Koil King Size Bed Matress/Boxspring - $800 -</a><font size="-1"> (Plantation)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
137
|
+
<p><a href="/brw/fuo/1171592934.html">DINIG BUFFET AND WINERY wood beauty stylish - $590 -</a><font size="-1"> (Fort Lauderdale)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
138
|
+
<p><a href="/brw/fuo/1171591182.html">HUGE MOVING SALE EVERYTHING MUST GO!!!!!! -</a> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
139
|
+
<p><a href="/mdc/fuo/1171587077.html">Wooden/Metal Computer Desk - $30 -</a><font size="-1"> (Coral Gables)</font> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
140
|
+
<p><a href="/brw/fuo/1171581992.html">Safari Animals Home Decor - $1 -</a> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
141
|
+
<p><a href="/mdc/fud/1171582327.html">NEW AG MANAGEMENT OFFICE CHAIRS - $219 -</a> <span class="p"> pic</span> <<<i><a href="/fud/">furniture by dealer</a></i></p>
|
142
|
+
<p><a href="/pbc/fuo/1171581302.html">Contempoary Style Leather Sofa -</a><font size="-1"> (West Palm Beach)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
143
|
+
<p><a href="/brw/fuo/1171577772.html">BREAK FAST DINING TABLE MARBLE WITH 6 CHAIRS - $140 -</a><font size="-1"> (PARKLAND/CORAL SPRING)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
144
|
+
<p><a href="/brw/fuo/1171577687.html">PATIO FURNITURE CAST ALUMINUM - $350 -</a><font size="-1"> (POMPANO BEACH)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
145
|
+
<p><a href="/mdc/fud/1164329587.html"> pool table - $250 -</a> <<<i><a href="/fud/">furniture by dealer</a></i></p>
|
146
|
+
<p><a href="/pbc/fuo/1171576098.html">Corner table - $5 -</a><font size="-1"> (Royal Palm Beach)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
147
|
+
<p><a href="/mdc/fud/1171574897.html">PK22 Easy Leather Chair - $599 -</a> <span class="p"> pic</span> <<<i><a href="/fud/">furniture by dealer</a></i></p>
|
148
|
+
<p><a href="/mdc/fuo/1171076966.html">new table and chairs - $500 -</a> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
149
|
+
<p><a href="/pbc/fuo/1171572816.html">Elegant Floor Lamp -</a><font size="-1"> (West Palm Beach)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
150
|
+
<p><a href="/brw/fuo/1171570670.html">45" Glass top dinette - $190 -</a><font size="-1"> (Coconut Creek)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
151
|
+
<p><a href="/brw/fuo/1171570228.html">Couch w/ Pull out Bed - $150 -</a><font size="-1"> (Pompano Beach)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
152
|
+
<p><a href="/mdc/fud/1171570038.html">Eileen Gray Adjustable Tables - New -</a> <span class="p"> pic</span> <<<i><a href="/fud/">furniture by dealer</a></i></p>
|
153
|
+
<p><a href="/mdc/fuo/1171568132.html">CHEAP GLASS TOP DESK - $400 -</a><font size="-1"> (kendall/163pl. 88st.)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
154
|
+
<p><a href="/pbc/fuo/1171567577.html">$10 couch - $10 -</a><font size="-1"> (boca raton)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
155
|
+
<p><a href="/brw/fuo/1171564018.html">Massage chair - $170 -</a><font size="-1"> (Pompano Beach)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
156
|
+
<p><a href="/mdc/fuo/1171564859.html">Loveseat - $350 -</a><font size="-1"> (West Kendall)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
157
|
+
<p><a href="/pbc/fuo/1171565497.html">Ironman Weight Lifting Set - $300 -</a><font size="-1"> (wellinton)</font> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
158
|
+
<p><a href="/mdc/fud/1171564511.html">Eiffel Tower Base Dining Side Chairs - New - $99 -</a> <span class="p"> pic</span> <<<i><a href="/fud/">furniture by dealer</a></i></p>
|
159
|
+
<p><a href="/pbc/fuo/1171564283.html">Stereo Receiver w/Graphic Analyzer & Speakers - $100 -</a><font size="-1"> (Boynton Beach)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
160
|
+
<p><a href="/pbc/fuo/1171563499.html">>>>> BEAUTIFUL SOFA FOR SALE <<<< - $200 -</a><font size="-1"> (Palm Beach Gardens)</font> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
161
|
+
<p><a href="/brw/fuo/1171562707.html">ENTERTAINMENT CENTER CUSTOM DESIGN - $250 -</a><font size="-1"> (PARKLAND/CORAL SPRING)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
162
|
+
<p><a href="/mdc/fud/1171561987.html">NEW CELLULA STYLE 48" CHANDELIER - $349 -</a> <span class="p"> pic</span> <<<i><a href="/fud/">furniture by dealer</a></i></p>
|
163
|
+
<p><a href="/mdc/fuo/1171561507.html">Beautiful glass top coffee table - $50 -</a><font size="-1"> (Bay Harbor Islands)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
164
|
+
<p><a href="/pbc/fuo/1171561451.html">9 Drawer Solid Wood Dresser and Mirror - $200 -</a><font size="-1"> (Boynton Beach)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
165
|
+
<p><a href="/mdc/fuo/1171559897.html">Bunkbed - $60 -</a><font size="-1"> (Dadeland)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
166
|
+
<p><a href="/pbc/fuo/1171559299.html">Crate & Barrel Side Table - $65 -</a><font size="-1"> (Abacoa/Jupiter)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
167
|
+
<p><a href="/pbc/fuo/1171558286.html">Sectional Sofa - $400 -</a><font size="-1"> (Palm Beach Gardens)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
168
|
+
<p><a href="/brw/fuo/1171463677.html">GEORGEOUS CHEETAH PRINT SEALY SOFA - MUST SELL - $299 -</a><font size="-1"> (Hollywood Lakes/North)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
169
|
+
<p><a href="/brw/fuo/1171558038.html">DINING ROOM TABLE SET - $290 -</a><font size="-1"> (Pembroke Pines)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
170
|
+
<p><a href="/pbc/fuo/1171556722.html">Sterns and Foster King Size Mattress/ Box Spring - $350 -</a><font size="-1"> (Palm Beach)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
171
|
+
<p><a href="/pbc/fuo/1171556629.html">dining set high end must see - $6500 -</a><font size="-1"> (boca raton)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
172
|
+
<p><a href="/mdc/fud/1171556148.html">New Victoria Ghost Style Transparent Side Chairs and Armchair - $185 -</a> <span class="p"> pic img</span> <<<i><a href="/fud/">furniture by dealer</a></i></p>
|
173
|
+
<p><a href="/mdc/fuo/1171554780.html">Modern wood/black patio table w/chairs - $75 -</a><font size="-1"> (Miami)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
174
|
+
<p><a href="/mdc/fud/1171553514.html">Leather Matteo Adjustable Barstools By Nuevo - $367 -</a> <span class="p"> pic</span> <<<i><a href="/fud/">furniture by dealer</a></i></p>
|
175
|
+
<p><a href="/pbc/fuo/1171550178.html">Modern Glass TV/Audio/Video Stand Entertainment Center Only6months old - $350 -</a><font size="-1"> (WPB/Wellington/Boynton Beach)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
176
|
+
<p><a href="/mdc/fuo/1171549884.html">Patio Wood square table+4 director chairs+umbrela - $179 -</a><font size="-1"> (Aventura)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
177
|
+
<p><a href="/mdc/fud/1171548703.html">New Wagner Wishbone "Y" Dining Chairs - $249 -</a> <span class="p"> pic</span> <<<i><a href="/fud/">furniture by dealer</a></i></p>
|
178
|
+
<p><a href="/mdc/fuo/1171545409.html">Super sale!! Patio Light fiji bamboo set - $155 -</a><font size="-1"> (N.Dade)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
179
|
+
<p><a href="/mdc/fud/1171545312.html">Leather Springing Lounge Chair By Poul Kjaerhol - $499 -</a> <span class="p"> pic</span> <<<i><a href="/fud/">furniture by dealer</a></i></p>
|
180
|
+
<p><a href="/mdc/fud/1171543887.html">New Amici Stainless Steel Benches in Brused or Polished finish - $630 -</a> <span class="p"> pic</span> <<<i><a href="/fud/">furniture by dealer</a></i></p>
|
181
|
+
<p><a href="/mdc/fuo/1171543491.html">High wood table & 2 chairs patio/outdoor/Indoor - $80 -</a><font size="-1"> (Miami)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
182
|
+
<p><a href="/brw/fuo/1171543172.html">Adjustable Metal Bed Frame - $40 -</a><font size="-1"> (Deerfield Beach)</font> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
183
|
+
<p><a href="/mdc/fud/1171542823.html">Aluminum Group Padded Management Chairs - 4 colors - $245 -</a> <span class="p"> pic img</span> <<<i><a href="/fud/">furniture by dealer</a></i></p>
|
184
|
+
<p><a href="/brw/fuo/1171542223.html">Leather Couch, Seat, & Ottoman - $50 -</a><font size="-1"> (Pembroke Pines)</font> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
185
|
+
<p><a href="/brw/fuo/1171539653.html">great designer chair - $40 -</a><font size="-1"> (deerfield beach)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
186
|
+
<p><a href="/mdc/fuo/1171541074.html">Dark bamboo set for the patio - $270 -</a><font size="-1"> (Miami)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
187
|
+
<p><a href="/mdc/fud/1171539959.html">Eames Style Lounge Chair and Ottoman - Black,Vanilla - $895 -</a> <span class="p"> pic</span> <<<i><a href="/fud/">furniture by dealer</a></i></p>
|
188
|
+
<p><a href="/brw/fuo/1171534920.html">***** ULTRA MODERN OTTOMAN - DARK CHOCOLATE ***** - $129 -</a><font size="-1"> (Miami / Kendall)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
189
|
+
<p><a href="/mdc/fud/1171538677.html">NEW JAPANESE STYLE PLATFORM BED - King or Queen Sizes - $1375 -</a> <span class="p"> pic</span> <<<i><a href="/fud/">furniture by dealer</a></i></p>
|
190
|
+
<p><a href="/mdc/fuo/1171519822.html">***** MODERN DARK BROWN OTTOMAN ***** - $125 -</a><font size="-1"> (Miami / Kendall area)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
191
|
+
<p><a href="/mdc/fud/1171536546.html">New Alexander Barstools - Lem Style - 5colors - $249 -</a> <span class="p"> pic</span> <<<i><a href="/fud/">furniture by dealer</a></i></p>
|
192
|
+
<p><a href="/mdc/fuo/1171536378.html">Super patio/Outdoor sectional 6 piece - $475 -</a><font size="-1"> (North Dade)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
193
|
+
<p><a href="/pbc/fuo/1171536353.html">> 0 < Pittsburgh Steelers Beer Pong Table For Sale!Super Bowl Champs!! - $120 -</a><font size="-1"> (Tequesta/Jupiter)</font> <span class="p"> pic img</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
194
|
+
<p><a href="/mdc/fuo/1171535233.html">American Signature Loveseat - $250 -</a><font size="-1"> (Bay Harbor Islands)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
195
|
+
<p><a href="/mdc/fud/1171535495.html">New Le Corbusier Pony Lounge Chair - $899 -</a> <span class="p"> pic</span> <<<i><a href="/fud/">furniture by dealer</a></i></p>
|
196
|
+
<p><a href="/pbc/fuo/1171458403.html">Broyhill Wood Coffee Table with Drawers - $50 -</a><font size="-1"> (West Lake Worth)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
197
|
+
<p><a href="/pbc/fuo/1171534833.html">Queen Anne Traditional End Tables Stiffel Brass Lamps - $70 -</a><font size="-1"> (Deerfield Beach)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
198
|
+
<p><a href="/mdc/fud/1171533476.html">Eames Style Molded plywood Dining Chairs w/Megtal Legs - $199 -</a> <span class="p"> pic img</span> <<<i><a href="/fud/">furniture by dealer</a></i></p>
|
199
|
+
<p><a href="/mdc/fuo/1171526415.html">Armoire/Antique finished - $1900 -</a><font size="-1"> (Coral Gables, FL)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
200
|
+
<p><a href="/mdc/fud/1171532234.html">NEW MEGAN LEATHER ITALIAN STYLE DINING CHAIRS - 2 colors - $150 -</a> <span class="p"> pic</span> <<<i><a href="/fud/">furniture by dealer</a></i></p>
|
201
|
+
<p><a href="/pbc/fuo/1171531145.html">(SOLD) Miami Hurricanes Beer Pong Table!! Buy yours custom!! - $175 -</a><font size="-1"> (Jupiter/ Tequesta)</font> <span class="p"> pic img</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
202
|
+
<p><a href="/brw/fuo/1171530985.html">China Cabinet, Table and chairs REDUCED - $100 -</a><font size="-1"> (Deerfield Beach)</font> <span class="p"> pic</span> <<<i><a href="/fuo/">furniture by owner</a></i></p>
|
203
|
+
|
204
|
+
|
205
|
+
<p align="center"><font size="4"><a href="index9000.html">next 100 postings</a></font>
|
206
|
+
|
207
|
+
<div id="footer">
|
208
|
+
<hr>
|
209
|
+
<span id="copy">
|
210
|
+
Copyright © 2009 craigslist, inc.<br>
|
211
|
+
<a href="#top">Back to top of page</a>
|
212
|
+
</span>
|
213
|
+
<span class="rss">
|
214
|
+
<a class="l" href="http://miami.craigslist.org/fua/index.rss">RSS</a>
|
215
|
+
<a href="http://www.craigslist.org/about/rss">(?)</a><br>
|
216
|
+
<a class="y" href="http://add.my.yahoo.com/rss?url=http://miami.craigslist.org/fua/index.rss">add to My Yahoo!</a>
|
217
|
+
</span>
|
218
|
+
</div>
|
219
|
+
<br><br>
|
220
|
+
|
221
|
+
<div id="floater"> </div>
|
222
|
+
|
223
|
+
</blockquote>
|
224
|
+
<script type="text/javascript" src="http://www.craigslist.org/js/jquery.js"></script>
|
225
|
+
</body>
|
226
|
+
</html>
|
@@ -5,14 +5,12 @@ require 'test/unit'
|
|
5
5
|
|
6
6
|
class CraigslistListingTest < Test::Unit::TestCase
|
7
7
|
|
8
|
-
def
|
8
|
+
def test_pukes
|
9
9
|
google = read_as_hpricot('google.html')
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
assert_nothing_raised{ CraigScrape::PostFull.new google }
|
10
|
+
|
11
|
+
assert_raise(CraigScrape::ParseError){ CraigScrape::PostSummary.new google }
|
12
|
+
assert_raise(CraigScrape::ParseError){ CraigScrape::Listings.new google }
|
13
|
+
assert_raise(CraigScrape::ParseError){ CraigScrape::PostFull.new google }
|
16
14
|
end
|
17
15
|
|
18
16
|
def test_listing_parse
|
@@ -141,6 +139,18 @@ EOD
|
|
141
139
|
short_search = CraigScrape::Listings.new read_as_hpricot('listing_samples/short_search_output.html')
|
142
140
|
assert_equal nil, short_search.next_page_href
|
143
141
|
assert_equal 93, short_search.posts.length
|
142
|
+
|
143
|
+
mia_fua_index8900_052109 = CraigScrape::Listings.new read_as_hpricot('listing_samples/mia_fua_index8900.5.21.09.html')
|
144
|
+
assert_equal 'index9000.html', mia_fua_index8900_052109.next_page_href
|
145
|
+
assert_equal 100, mia_fua_index8900_052109.posts.length
|
146
|
+
mia_fua_index8900_052109.posts[0..13].each do |l|
|
147
|
+
assert_equal 5, l.date.month
|
148
|
+
assert_equal 15, l.date.day
|
149
|
+
end
|
150
|
+
mia_fua_index8900_052109.posts[14..99].each do |l|
|
151
|
+
assert_equal 5, l.date.month
|
152
|
+
assert_equal 14, l.date.day
|
153
|
+
end
|
144
154
|
end
|
145
155
|
|
146
156
|
def test_posting_parse
|
@@ -211,6 +221,7 @@ EOD
|
|
211
221
|
assert_equal 225000.0, posting4.price
|
212
222
|
|
213
223
|
posting5 = CraigScrape::PostFull.new read_as_hpricot('post_samples/posting5.html')
|
224
|
+
assert_equal true, posting5.flagged_for_removal?
|
214
225
|
assert_equal nil, posting5.contents
|
215
226
|
assert_equal ["south florida craigslist", "palm beach co", "apts/housing for rent"], posting5.full_section
|
216
227
|
assert_equal "This posting has been <a href=\"http://www.craigslist.org/about/help/flags_and_community_moderation\">flagged</a> for removal", posting5.header
|
@@ -221,7 +232,7 @@ EOD
|
|
221
232
|
assert_equal nil, posting5.post_time
|
222
233
|
assert_equal [], posting5.images
|
223
234
|
assert_equal nil, posting5.contents_as_plain
|
224
|
-
assert_equal nil, posting5.price
|
235
|
+
assert_equal nil, posting5.price
|
225
236
|
end
|
226
237
|
|
227
238
|
private
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: libcraigscrape
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: "0.
|
4
|
+
version: "0.6"
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris DeRose, DeRose Technologies, Inc.
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-05-
|
12
|
+
date: 2009-05-21 00:00:00 -04:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -55,18 +55,20 @@ extra_rdoc_files:
|
|
55
55
|
- COPYING.LESSER
|
56
56
|
- bin/craigwatch
|
57
57
|
files:
|
58
|
+
- Rakefile
|
59
|
+
- README
|
58
60
|
- CHANGELOG
|
59
61
|
- COPYING
|
60
62
|
- COPYING.LESSER
|
61
|
-
-
|
63
|
+
- bin/craigwatch
|
62
64
|
- bin/craig_report_schema.yml
|
63
65
|
- bin/report_mailer
|
64
66
|
- bin/report_mailer/craigslist_report.html.erb
|
65
67
|
- bin/report_mailer/craigslist_report.plain.erb
|
66
|
-
- bin/craigwatch
|
67
68
|
- test/listing_samples
|
68
69
|
- test/listing_samples/category_output.html
|
69
70
|
- test/listing_samples/short_search_output.html
|
71
|
+
- test/listing_samples/mia_fua_index8900.5.21.09.html
|
70
72
|
- test/listing_samples/category_output_2.html
|
71
73
|
- test/listing_samples/long_search_output.html
|
72
74
|
- test/test_craigslist_listing.rb
|
@@ -79,7 +81,6 @@ files:
|
|
79
81
|
- test/post_samples/posting2.html
|
80
82
|
- test/google.html
|
81
83
|
- lib/libcraigscrape.rb
|
82
|
-
- README
|
83
84
|
has_rdoc: true
|
84
85
|
homepage: http://www.derosetechnologies.com/community/libcraigscrape
|
85
86
|
post_install_message:
|