craig 0.0.1.pre → 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +165 -28
- data/Rakefile +7 -0
- data/craig.gemspec +2 -2
- data/lib/craig/categories.rb +169 -0
- data/lib/craig/cities.rb +262 -0
- data/lib/craig/craigslist.rb +49 -0
- data/lib/craig/listing.rb +73 -0
- data/lib/craig/node.rb +151 -0
- data/lib/craig/page.rb +50 -0
- data/lib/craig/tasks/update_cities.rb +95 -0
- data/lib/craig/version.rb +1 -1
- data/lib/craig.rb +24 -1
- data/test/community_events_test.rb +56 -0
- data/test/for_sale_cars_trucks_test.rb +38 -0
- data/test/for_sale_photo_video_test.rb +24 -0
- data/test/parsing_test.rb +119 -0
- data/test/personals_casual_encounters_test.rb +36 -0
- data/test/resumes_test.rb +24 -0
- data/test/sample_html/community_event-one-page_files/craigslist.css +1487 -0
- data/test/sample_html/community_event-one-page_files/formats.js +100 -0
- data/test/sample_html/community_event-one-page_files/jquery-1.7.2.js +632 -0
- data/test/sample_html/community_event-one-page_files/jquery.form-defaults.js +2 -0
- data/test/sample_html/community_event-one-page_files/toChecklist.js +47 -0
- data/test/sample_html/community_event-one-page_files/tocs.js +30 -0
- data/test/sample_html/community_events-one-page.html +294 -0
- data/test/sample_html/community_events.html +1077 -0
- data/test/sample_html/community_events_files/craigslist.css +1487 -0
- data/test/sample_html/community_events_files/formats.js +100 -0
- data/test/sample_html/community_events_files/jquery-1.7.2.js +632 -0
- data/test/sample_html/community_events_files/jquery-1.js +632 -0
- data/test/sample_html/community_events_files/jquery.form-defaults.js +2 -0
- data/test/sample_html/community_events_files/jquery.js +2 -0
- data/test/sample_html/community_events_files/toChecklist.js +47 -0
- data/test/sample_html/community_events_files/tocs.js +30 -0
- data/test/sample_html/for_sale.html +1478 -0
- data/test/sample_html/for_sale_cars_trucks.html +1483 -0
- data/test/sample_html/for_sale_cars_trucks_files/craigslist.css +1487 -0
- data/test/sample_html/for_sale_cars_trucks_files/formats.js +100 -0
- data/test/sample_html/for_sale_cars_trucks_files/jquery-1.7.2.js +632 -0
- data/test/sample_html/for_sale_cars_trucks_files/jquery.form-defaults.js +2 -0
- data/test/sample_html/for_sale_cars_trucks_files/toChecklist.js +47 -0
- data/test/sample_html/for_sale_cars_trucks_files/tocs.js +30 -0
- data/test/sample_html/for_sale_files/craigslist.css +1474 -0
- data/test/sample_html/for_sale_files/formats.js +107 -0
- data/test/sample_html/for_sale_files/jquery-1.js +632 -0
- data/test/sample_html/for_sale_files/jquery.js +2 -0
- data/test/sample_html/for_sale_files/toChecklist.js +47 -0
- data/test/sample_html/for_sale_files/tocs.js +30 -0
- data/test/sample_html/for_sale_photo_video.html +674 -0
- data/test/sample_html/for_sale_photo_video_files/craigslist.css +1487 -0
- data/test/sample_html/for_sale_photo_video_files/formats.js +100 -0
- data/test/sample_html/for_sale_photo_video_files/jquery-1.7.2.js +632 -0
- data/test/sample_html/for_sale_photo_video_files/jquery.form-defaults.js +2 -0
- data/test/sample_html/for_sale_photo_video_files/toChecklist.js +47 -0
- data/test/sample_html/for_sale_photo_video_files/tocs.js +30 -0
- data/test/sample_html/gigs.html +1047 -0
- data/test/sample_html/gigs_files/craigslist.css +1474 -0
- data/test/sample_html/gigs_files/formats.js +107 -0
- data/test/sample_html/gigs_files/jquery-1.js +632 -0
- data/test/sample_html/gigs_files/jquery.js +2 -0
- data/test/sample_html/gigs_files/toChecklist.js +47 -0
- data/test/sample_html/gigs_files/tocs.js +30 -0
- data/test/sample_html/housing.html +1406 -0
- data/test/sample_html/housing_vacation_rentals_files/craigslist.css +1474 -0
- data/test/sample_html/housing_vacation_rentals_files/formats.js +107 -0
- data/test/sample_html/housing_vacation_rentals_files/jquery-1.7.2.js +632 -0
- data/test/sample_html/housing_vacation_rentals_files/jquery.form-defaults.js +2 -0
- data/test/sample_html/housing_vacation_rentals_files/toChecklist.js +47 -0
- data/test/sample_html/housing_vacation_rentals_files/tocs.js +30 -0
- data/test/sample_html/jobs.html +1120 -0
- data/test/sample_html/jobs_files/craigslist.css +1474 -0
- data/test/sample_html/jobs_files/formats.js +107 -0
- data/test/sample_html/jobs_files/jquery-1.js +632 -0
- data/test/sample_html/jobs_files/jquery.js +2 -0
- data/test/sample_html/jobs_files/toChecklist.js +47 -0
- data/test/sample_html/jobs_files/tocs.js +30 -0
- data/test/sample_html/personals.html +1096 -0
- data/test/sample_html/personals_casual_encounters.html +1086 -0
- data/test/sample_html/personals_casual_encounters_files/craigslist.css +1487 -0
- data/test/sample_html/personals_casual_encounters_files/formats.js +100 -0
- data/test/sample_html/personals_casual_encounters_files/jquery-1.7.2.js +632 -0
- data/test/sample_html/personals_casual_encounters_files/jquery.form-defaults.js +2 -0
- data/test/sample_html/personals_casual_encounters_files/toChecklist.js +47 -0
- data/test/sample_html/personals_casual_encounters_files/tocs.js +30 -0
- data/test/sample_html/personals_strictly_platonic_files/craigslist.css +1474 -0
- data/test/sample_html/personals_strictly_platonic_files/formats.js +107 -0
- data/test/sample_html/personals_strictly_platonic_files/jquery-1.js +632 -0
- data/test/sample_html/personals_strictly_platonic_files/jquery.js +2 -0
- data/test/sample_html/personals_strictly_platonic_files/toChecklist.js +47 -0
- data/test/sample_html/personals_strictly_platonic_files/tocs.js +30 -0
- data/test/sample_html/resumes.html +811 -0
- data/test/sample_html/resumes_files/craigslist.css +1487 -0
- data/test/sample_html/resumes_files/formats.js +100 -0
- data/test/sample_html/resumes_files/jquery-1.7.2.js +632 -0
- data/test/sample_html/resumes_files/jquery.form-defaults.js +2 -0
- data/test/sample_html/resumes_files/toChecklist.js +47 -0
- data/test/sample_html/resumes_files/tocs.js +30 -0
- data/test/sample_html/services.html +1096 -0
- data/test/sample_html/services_files/craigslist.css +1487 -0
- data/test/sample_html/services_files/formats.js +100 -0
- data/test/sample_html/services_files/jquery-1.7.2.js +632 -0
- data/test/sample_html/services_files/jquery.form-defaults.js +2 -0
- data/test/sample_html/services_files/toChecklist.js +47 -0
- data/test/sample_html/services_files/tocs.js +30 -0
- data/test/sample_html/test.rb +309 -0
- data/test/services_test.rb +25 -0
- data/test/test_helper.rb +26 -0
- metadata +205 -9
data/README.md
CHANGED
@@ -1,51 +1,188 @@
|
|
1
1
|
# Craig
|
2
2
|
|
3
|
-
A
|
3
|
+
A Craigslist listings scraper.
|
4
|
+
|
5
|
+
* Inspired by [gregstallings/craigslist](https://github.com/gregstallings/craigslist).
|
6
|
+
* A just-for-fun self-educational exercise.
|
4
7
|
|
5
8
|
## Installation
|
6
9
|
|
7
|
-
|
10
|
+
$ gem install craig
|
8
11
|
|
9
|
-
|
12
|
+
## Usage
|
10
13
|
|
11
|
-
|
14
|
+
~~~ ruby
|
15
|
+
require "craig"
|
16
|
+
~~~
|
12
17
|
|
13
|
-
|
18
|
+
Pass in the city and category:
|
14
19
|
|
15
|
-
|
20
|
+
~~~ ruby
|
21
|
+
listings = Craig.query(:austin, :for_sale)
|
22
|
+
~~~
|
16
23
|
|
17
|
-
|
24
|
+
Or narrow down your results with a subcategory:
|
25
|
+
|
26
|
+
~~~ ruby
|
27
|
+
listings = Craig.query(:austin, :for_sale => :computers)
|
28
|
+
~~~
|
18
29
|
|
19
|
-
|
30
|
+
Returns up to 100 `Listing`s.
|
20
31
|
|
21
|
-
|
32
|
+
## Examples
|
22
33
|
|
23
|
-
Let's check out some cars within our budget
|
34
|
+
Let's check out some cars within our budget.
|
24
35
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
36
|
+
~~~ ruby
|
37
|
+
vehicles = Craig.query(:austin, :for_sale => :cars_trucks)
|
38
|
+
vehicles.select { |v|
|
39
|
+
v.price.between?(6000, 8000) &&
|
40
|
+
v.image? &&
|
41
|
+
v.seller == :owner
|
42
|
+
}
|
43
|
+
|
44
|
+
#=> [<Listing>, <Listing>, <Listing>]
|
45
|
+
~~~
|
33
46
|
|
34
47
|
I'm about to move to Birmingham. I wonder where the kids my age are living.
|
35
48
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
49
|
+
~~~ ruby
|
50
|
+
listings = Craig.query(:birmingham, :personals => :strictly_platonic)
|
51
|
+
listings.select { |p|
|
52
|
+
p.age < 30
|
53
|
+
}.map(&:location)
|
54
|
+
|
55
|
+
#= ["Highland Ave", "Highland Ave", "Highland Ave"]
|
56
|
+
~~~
|
42
57
|
|
43
58
|
Oh wait, I left my trombone downtown last night. I wonder if anyone found it.
|
44
59
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
60
|
+
~~~ ruby
|
61
|
+
listings = Craig.query(:austin, :community => :lost_found
|
62
|
+
listings.any? { |listing| listing.title =~ /trombone/i }
|
63
|
+
|
64
|
+
#=> true
|
65
|
+
~~~
|
66
|
+
|
67
|
+
Let's get the price of the most expensive Macbook that's sold by an owner
|
68
|
+
(instead of a dealer) on or near UT campus.
|
69
|
+
|
70
|
+
~~~ ruby
|
71
|
+
Craig.query(:austin, :for_sale => :computer)
|
72
|
+
.select { |c|
|
73
|
+
c.seller == :owner &&
|
74
|
+
c.location[/campus/i] &&
|
75
|
+
c.title[/macbook/i]
|
76
|
+
}.sort_by { |c|
|
77
|
+
-c.price
|
78
|
+
}.first
|
79
|
+
|
80
|
+
# Output
|
81
|
+
|
82
|
+
#=> {
|
83
|
+
:url => "http://austin.craigslist.org/sys/3723418912.html"
|
84
|
+
:title => "Late 2011 Macbook Pro"
|
85
|
+
:seller => :owner
|
86
|
+
:price => 1050
|
87
|
+
:posted_at => #<Date: 2013-01-23 ((2456316j,0s,0n),+0s,2299161j)>
|
88
|
+
:location => "West campus"
|
89
|
+
:has_map? => false
|
90
|
+
:has_image? => true
|
91
|
+
:id => 3723418912
|
92
|
+
}
|
93
|
+
~~~
|
94
|
+
|
95
|
+
## Available Listing methods
|
96
|
+
|
97
|
+
The easiest way to see what listings respond to is to just send them `Listing#to_hash`:
|
98
|
+
|
99
|
+
~~~ ruby
|
100
|
+
Craig.query(:new_york_city, :jobs).map(&:to_hash)
|
101
|
+
~~~
|
102
|
+
|
103
|
+
Or just look at console output (`Listing#to_s` outputs the hash in string form):
|
104
|
+
|
105
|
+
~~~ ruby
|
106
|
+
Craig.query(:new_york_city, :jobs)
|
107
|
+
~~~
|
108
|
+
|
109
|
+
Or you can look in `listing.rb` to see the type of nodes that Listings have, then find the method each node defines in `node.rb`.
|
110
|
+
|
111
|
+
Since I rarely use Ruby Modules, this gem started out as an self-educational scraper concept where Nodes are composed of Nodes are composed of Nodes but I didn't get very far. So now the internal API is a little spread out. TODO...
|
112
|
+
|
113
|
+
## Available cities and categories
|
114
|
+
|
115
|
+
The Craigslist website itself serves as documentation for this
|
116
|
+
gem's API.
|
117
|
+
|
118
|
+
* Cities: http://www.craigslist.org/about/sites/
|
119
|
+
* Categories: http://austin.craigslist.org/
|
120
|
+
|
121
|
+
Just downcase Craigslist's name for it and replace spaces and punctuation with underscores.
|
122
|
+
|
123
|
+
Here, let me translate some for you to be clear:
|
124
|
+
|
125
|
+
<table>
|
126
|
+
<tr>
|
127
|
+
<th colspan="2">Cities</th>
|
128
|
+
</tr>
|
129
|
+
<tr>
|
130
|
+
<th>How it appears on Craigslist</th><th>The symbol you pass into Craig</th>
|
131
|
+
</tr>
|
132
|
+
<tr>
|
133
|
+
<td>beaumont / port arthur</td>
|
134
|
+
<td>:beaumont_port_arthur</td>
|
135
|
+
</tr>
|
136
|
+
<tr>
|
137
|
+
<td>cambridge, UK</td>
|
138
|
+
<td>:cambridge_uk</td>
|
139
|
+
</tr>
|
140
|
+
<tr>
|
141
|
+
<td>nice / cote d'azur</td>
|
142
|
+
<td>:nice_cote_d_azur</td>
|
143
|
+
</tr>
|
144
|
+
<tr>
|
145
|
+
<th colspan="2">Categories/Subcategories</th>
|
146
|
+
</tr>
|
147
|
+
<tr>
|
148
|
+
<th>How it appears on Craigslist</th><th>The symbol you pass into Craig</th>
|
149
|
+
</tr>
|
150
|
+
<tr>
|
151
|
+
<td>for sale</td>
|
152
|
+
<td>:for_sale</td>
|
153
|
+
</tr>
|
154
|
+
<tr>
|
155
|
+
<td>cds/dvd/vhs </td>
|
156
|
+
<td>:cds_dvd_vhs</td>
|
157
|
+
</tr>
|
158
|
+
<tr>
|
159
|
+
<td>accounting+finance </td>
|
160
|
+
<td>:accounting_finance</td>
|
161
|
+
</tr>
|
162
|
+
</table>
|
163
|
+
|
164
|
+
~~~ ruby
|
165
|
+
Craig.query(:nice_cote_d_azur, :for_sale => :cds_dvd_vhs)
|
166
|
+
~~~
|
167
|
+
|
168
|
+
If you're still unsure, just check out Craig's internal lookup table.
|
169
|
+
|
170
|
+
## Diverges from Craigslist homepage
|
171
|
+
|
172
|
+
While I've mostly modeled Craig's API after Craigslist's website, I've
|
173
|
+
diverged from the homepage where I felt it made sense.
|
174
|
+
|
175
|
+
For example, I prefer the "Show All" view where possible.
|
176
|
+
|
177
|
+
:community => :events goes to /eee instead of /eve.
|
178
|
+
|
179
|
+
This way you see all events instead of just events with
|
180
|
+
date ranges.
|
181
|
+
|
182
|
+
:for_sale => :cars_trucks goes to the owners+dealers listings
|
183
|
+
|
184
|
+
instead of the splash page that lets you choose
|
185
|
+
TODO: Add search API or expose API to specify this stuff.
|
49
186
|
|
50
187
|
## Contributing
|
51
188
|
|
data/Rakefile
CHANGED
data/craig.gemspec
CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |gem|
|
|
8
8
|
gem.version = Craig::VERSION
|
9
9
|
gem.authors = ["Dan Neumann"]
|
10
10
|
gem.email = ["danrodneu@gmail.com"]
|
11
|
-
gem.description = %q{
|
12
|
-
gem.summary = %q{
|
11
|
+
gem.description = %q{A Craigslist listings scraper.}
|
12
|
+
gem.summary = %q{A Craigslist listings scraper.}
|
13
13
|
gem.homepage = "http://github.com/danneu/craig"
|
14
14
|
|
15
15
|
gem.files = `git ls-files`.split($/)
|
@@ -0,0 +1,169 @@
|
|
1
|
+
module Craig
|
2
|
+
CATEGORIES = {
|
3
|
+
'community' => {
|
4
|
+
'path' => 'ccc',
|
5
|
+
'children' => {
|
6
|
+
'activities' => 'act',
|
7
|
+
'artists' => 'ats',
|
8
|
+
'childcare' => 'kid',
|
9
|
+
'general' => 'com',
|
10
|
+
'groups' => 'grp',
|
11
|
+
'pets' => 'pet',
|
12
|
+
'events' => 'eee', # Diverges. Original: "eve"
|
13
|
+
'lost_found' => 'laf',
|
14
|
+
'musicians' => 'muc',
|
15
|
+
'local news' => 'vnn',
|
16
|
+
'politics' => 'pol',
|
17
|
+
'rideshare' => 'rid',
|
18
|
+
'volunteers' => 'vol',
|
19
|
+
'classes' => 'cls'
|
20
|
+
}
|
21
|
+
},
|
22
|
+
'personals' => {
|
23
|
+
'children' => {
|
24
|
+
'strictly_platonic' => 'stp',
|
25
|
+
'women_seek_women' => 'w4w',
|
26
|
+
'women_seeking_men' => 'w4m',
|
27
|
+
'men_seeking_women' => 'm4w',
|
28
|
+
'men_seeking_men' => 'm4m',
|
29
|
+
'misc_romance' => 'msr',
|
30
|
+
'casual_encounters' => 'cas',
|
31
|
+
'missed_connections' => 'mis',
|
32
|
+
'rants_and_raves' => 'rnr'
|
33
|
+
}
|
34
|
+
},
|
35
|
+
'housing' => {
|
36
|
+
'path' => 'hhh',
|
37
|
+
'children' => {
|
38
|
+
'apts_housing' => 'apa',
|
39
|
+
'rooms_shared' => 'roo',
|
40
|
+
'sublets_temporary' => 'sub',
|
41
|
+
'housing_wanted' => 'hsw',
|
42
|
+
'housing_swap' => 'swp',
|
43
|
+
'vacation_rentals' => 'vac',
|
44
|
+
'parking_storage' => 'prk',
|
45
|
+
'office_commercial' => 'off',
|
46
|
+
'real_estate_for_sale' => 'rea'
|
47
|
+
}
|
48
|
+
},
|
49
|
+
'for_sale' => {
|
50
|
+
'path' => 'sss',
|
51
|
+
'children' => {
|
52
|
+
'appliances' => 'ppa',
|
53
|
+
'antiques' => 'ata',
|
54
|
+
'barter' => 'bar',
|
55
|
+
'bikes' => 'bia',
|
56
|
+
'boats' => 'boo',
|
57
|
+
'books' => 'bka',
|
58
|
+
'business' => 'bfa',
|
59
|
+
'computer' => 'sya',
|
60
|
+
'free' => 'zip',
|
61
|
+
'furniture' => 'fua',
|
62
|
+
'general' => 'foa',
|
63
|
+
'jewelry' => 'jwa',
|
64
|
+
'materials' => 'maa',
|
65
|
+
'rvs' => 'rva',
|
66
|
+
'sporting' => 'sga',
|
67
|
+
'tickets' => 'tia',
|
68
|
+
'tools' => 'tla',
|
69
|
+
'wanted' => 'wan',
|
70
|
+
'arts_crafts' => 'ara',
|
71
|
+
'auto_parts' => 'pta',
|
72
|
+
'baby_kids' => 'baa',
|
73
|
+
'beauty_hlth' => 'haa',
|
74
|
+
'cars_trucks' => 'cta', # Diverges. Original: "/i/autos"
|
75
|
+
'cds_dvd_vhs' => 'ema',
|
76
|
+
'cell_phones' => 'moa',
|
77
|
+
'clothes_acc' => 'cla',
|
78
|
+
'collectibles' => 'cba',
|
79
|
+
'electronics' => 'ela',
|
80
|
+
'farm_garden' => 'gra',
|
81
|
+
'garage_sale' => 'gms',
|
82
|
+
'household' => 'hsa',
|
83
|
+
'motorcycles' => 'mca',
|
84
|
+
'music_instr' => 'msa',
|
85
|
+
'photo_video' => 'pha',
|
86
|
+
'toys_games' => 'taa',
|
87
|
+
'video_gaming' => 'vga'
|
88
|
+
}
|
89
|
+
},
|
90
|
+
'services' => {
|
91
|
+
'path' => 'bbb',
|
92
|
+
'children' => {
|
93
|
+
'beauty' => 'brs',
|
94
|
+
'creative' => 'crs',
|
95
|
+
'computer' => 'cps',
|
96
|
+
'cycle' => 'cys',
|
97
|
+
'event' => 'evs',
|
98
|
+
'financial' => 'fns',
|
99
|
+
'legal' => 'lgs',
|
100
|
+
'lessons' => 'lss',
|
101
|
+
'marine' => 'mas',
|
102
|
+
'pet' => 'pas',
|
103
|
+
'automotive' => 'aos',
|
104
|
+
'farm_garden' => 'fgs',
|
105
|
+
'household' => 'hss',
|
106
|
+
'labor_move' => 'lbs',
|
107
|
+
'skilld_trade' => 'sks',
|
108
|
+
'real_estate' => 'rts',
|
109
|
+
'sm_biz_ads' => 'biz',
|
110
|
+
'therapeutic' => 'thp',
|
111
|
+
'travel_vac' => 'trv',
|
112
|
+
'write_ed_tr8' => 'wet'
|
113
|
+
}
|
114
|
+
},
|
115
|
+
'jobs' => {
|
116
|
+
'path' => 'jjj',
|
117
|
+
'children' => {
|
118
|
+
'accounting_finance' => 'acc',
|
119
|
+
'admin_office' => 'ofc',
|
120
|
+
'arch_engineering' => 'egr',
|
121
|
+
'art_media_design' => 'med',
|
122
|
+
'biotech_science' => 'sci',
|
123
|
+
'business_mgmt' => 'bus',
|
124
|
+
'customer_service' => 'csr',
|
125
|
+
'education' => 'edu',
|
126
|
+
'food_bev_hosp' => 'fbh',
|
127
|
+
'general_labor' => 'lab',
|
128
|
+
'government' => 'gov',
|
129
|
+
'human_resources' => 'hum',
|
130
|
+
'internet_engineers' => 'eng',
|
131
|
+
'legal_paralegal' => 'lgl',
|
132
|
+
'manufacturing' => 'mnu',
|
133
|
+
'marketing_pr_ad' => 'mar',
|
134
|
+
'medical_health' => 'hea',
|
135
|
+
'nonprofit_sector' => 'npo',
|
136
|
+
'real_estate' => 'rej',
|
137
|
+
'retail_wholesale' => 'ret',
|
138
|
+
'sales_biz_dev' => 'sls',
|
139
|
+
'salon_spa_fitness' => 'spa',
|
140
|
+
'security' => 'sec',
|
141
|
+
'skilled_trade_craft' => 'trd',
|
142
|
+
'software_qa_dba' => 'sof',
|
143
|
+
'systems_network' => 'sad',
|
144
|
+
'technical_support' => 'tch',
|
145
|
+
'transport' => 'trp',
|
146
|
+
'tv_film_video' => 'tfr',
|
147
|
+
'web_info_design' => 'web',
|
148
|
+
'writing_editing' => 'wri',
|
149
|
+
'etc' => 'etc'
|
150
|
+
}
|
151
|
+
},
|
152
|
+
'gigs' => {
|
153
|
+
'path' => 'ggg',
|
154
|
+
'children' => {
|
155
|
+
'crew' => 'cwg',
|
156
|
+
'event' => 'evg',
|
157
|
+
'labor' => 'lbg',
|
158
|
+
'talent' => 'tlg',
|
159
|
+
'computer' => 'cpg',
|
160
|
+
'creative' => 'crg',
|
161
|
+
'domestic' => 'dmg',
|
162
|
+
'writing' => 'wrg'
|
163
|
+
}
|
164
|
+
},
|
165
|
+
'resumes' => {
|
166
|
+
'path' => 'res'
|
167
|
+
}
|
168
|
+
}
|
169
|
+
end
|
data/lib/craig/cities.rb
ADDED
@@ -0,0 +1,262 @@
|
|
1
|
+
# Generated by update_cities.rb
|
2
|
+
# Date: 22 Jan 2013
|
3
|
+
#
|
4
|
+
# Total Craigslist cities: 460
|
5
|
+
# Hash size: 252
|
6
|
+
|
7
|
+
module Craig
|
8
|
+
CITIES = {
|
9
|
+
"birmingham" => "bham",
|
10
|
+
"florence_muscle_shoals" => "shoals",
|
11
|
+
"gadsden_anniston" => "gadsden",
|
12
|
+
"huntsville_decatur" => "huntsville",
|
13
|
+
"anchorage_mat_su" => "anchorage",
|
14
|
+
"kenai_peninsula" => "kenai",
|
15
|
+
"southeast_alaska" => "juneau",
|
16
|
+
"flagstaff_sedona" => "flagstaff",
|
17
|
+
"mohave_county" => "mohave",
|
18
|
+
"fayetteville" => "fayar",
|
19
|
+
"fresno_madera" => "fresno",
|
20
|
+
"hanford_corcoran" => "hanford",
|
21
|
+
"humboldt_county" => "humboldt",
|
22
|
+
"imperial_county" => "imperial",
|
23
|
+
"mendocino_county" => "mendocino",
|
24
|
+
"monterey_bay" => "monterey",
|
25
|
+
"san_francisco_bay_area" => "sfbay",
|
26
|
+
"san_luis_obispo" => "slo",
|
27
|
+
"siskiyou_county" => "siskiyou",
|
28
|
+
"ventura_county" => "ventura",
|
29
|
+
"visalia_tulare" => "visalia",
|
30
|
+
"colorado_springs" => "cosprings",
|
31
|
+
"eastern_co" => "eastco",
|
32
|
+
"fort_collins_north_co" => "fortcollins",
|
33
|
+
"high_rockies" => "rockies",
|
34
|
+
"western_slope" => "westslope",
|
35
|
+
"eastern_ct" => "newlondon",
|
36
|
+
"northwest_ct" => "nwct",
|
37
|
+
"washington" => "washingtondc",
|
38
|
+
"daytona_beach" => "daytona",
|
39
|
+
"florida_keys" => "keys",
|
40
|
+
"ft_myers_sw_florida" => "fortmyers",
|
41
|
+
"heartland_florida" => "cfl",
|
42
|
+
"north_central_fl" => "lakecity",
|
43
|
+
"okaloosa_walton" => "okaloosa",
|
44
|
+
"sarasota_bradenton" => "sarasota",
|
45
|
+
"south_florida" => "miami",
|
46
|
+
"tampa_bay_area" => "tampa",
|
47
|
+
"treasure_coast" => "treasure",
|
48
|
+
"albany" => "albanyga",
|
49
|
+
"athens" => "athensga",
|
50
|
+
"columbus" => "columbusga",
|
51
|
+
"macon_warner_robins" => "macon",
|
52
|
+
"northwest_ga" => "nwga",
|
53
|
+
"savannah_hinesville" => "savannah",
|
54
|
+
"hawaii" => "honolulu",
|
55
|
+
"lewiston_clarkston" => "lewiston",
|
56
|
+
"bloomington_normal" => "bn",
|
57
|
+
"champaign_urbana" => "chambana",
|
58
|
+
"la_salle_co" => "lasalle",
|
59
|
+
"mattoon_charleston" => "mattoon",
|
60
|
+
"southern_illinois" => "carbondale",
|
61
|
+
"springfield" => "springfieldil",
|
62
|
+
"western_il" => "quincy",
|
63
|
+
"lafayette_west_lafayette" => "tippecanoe",
|
64
|
+
"muncie_anderson" => "muncie",
|
65
|
+
"richmond" => "richmondin",
|
66
|
+
"south_bend_michiana" => "southbend",
|
67
|
+
"southeast_ia" => "ottumwa",
|
68
|
+
"waterloo_cedar_falls" => "waterloo",
|
69
|
+
"manhattan" => "ksu",
|
70
|
+
"northwest_ks" => "nwks",
|
71
|
+
"southeast_ks" => "seks",
|
72
|
+
"southwest_ks" => "swks",
|
73
|
+
"bowling_green" => "bgky",
|
74
|
+
"eastern_kentucky" => "eastky",
|
75
|
+
"western_ky" => "westky",
|
76
|
+
"central_louisiana" => "cenla",
|
77
|
+
"southern_maryland" => "smd",
|
78
|
+
"western_maryland" => "westmd",
|
79
|
+
"cape_cod_islands" => "capecod",
|
80
|
+
"western_massachusetts" => "westernmass",
|
81
|
+
"worcester_central_ma" => "worcester",
|
82
|
+
"central_michigan" => "centralmich",
|
83
|
+
"detroit_metro" => "detroit",
|
84
|
+
"jackson" => "jxn",
|
85
|
+
"monroe" => "monroemi",
|
86
|
+
"northern_michigan" => "nmi",
|
87
|
+
"saginaw_midland_baycity" => "saginaw",
|
88
|
+
"southwest_michigan" => "swmi",
|
89
|
+
"the_thumb" => "thumb",
|
90
|
+
"upper_peninsula" => "up",
|
91
|
+
"duluth_superior" => "duluth",
|
92
|
+
"minneapolis_st_paul" => "minneapolis",
|
93
|
+
"rochester" => "rmn",
|
94
|
+
"southwest_mn" => "marshall",
|
95
|
+
"gulfport_biloxi" => "gulfport",
|
96
|
+
"north_mississippi" => "northmiss",
|
97
|
+
"southwest_ms" => "natchez",
|
98
|
+
"columbia_jeff_city" => "columbiamo",
|
99
|
+
"lake_of_the_ozarks" => "loz",
|
100
|
+
"southeast_missouri" => "semo",
|
101
|
+
"montana_old" => "montana",
|
102
|
+
"omaha_council_bluffs" => "omaha",
|
103
|
+
"scottsbluff_panhandle" => "scottsbluff",
|
104
|
+
"reno_tahoe" => "reno",
|
105
|
+
"new_hampshire" => "nh",
|
106
|
+
"central_nj" => "cnj",
|
107
|
+
"north_jersey" => "newjersey",
|
108
|
+
"clovis_portales" => "clovis",
|
109
|
+
"roswell_carlsbad" => "roswell",
|
110
|
+
"santa_fe_taos" => "santafe",
|
111
|
+
"elmira_corning" => "elmira",
|
112
|
+
"new_york_city" => "newyork",
|
113
|
+
"plattsburgh_adirondacks" => "plattsburgh",
|
114
|
+
"potsdam_canton_massena" => "potsdam",
|
115
|
+
"twin_tiers_ny_pa" => "twintiers",
|
116
|
+
"utica_rome_oneida" => "utica",
|
117
|
+
"eastern_nc" => "eastnc",
|
118
|
+
"hickory_lenoir" => "hickory",
|
119
|
+
"jacksonville" => "onslow",
|
120
|
+
"raleigh_durham_ch" => "raleigh",
|
121
|
+
"fargo_moorhead" => "fargo",
|
122
|
+
"north_dakota" => "nd",
|
123
|
+
"athens" => "athensohio",
|
124
|
+
"dayton_springfield" => "dayton",
|
125
|
+
"lima_findlay" => "limaohio",
|
126
|
+
"tuscarawas_co" => "tuscarawas",
|
127
|
+
"zanesville_cambridge" => "zanesville",
|
128
|
+
"northwest_ok" => "enid",
|
129
|
+
"corvallis_albany" => "corvallis",
|
130
|
+
"klamath_falls" => "klamath",
|
131
|
+
"medford_ashland" => "medford",
|
132
|
+
"altoona_johnstown" => "altoona",
|
133
|
+
"cumberland_valley" => "chambersburg",
|
134
|
+
"lehigh_valley" => "allentown",
|
135
|
+
"scranton_wilkes_barre" => "scranton",
|
136
|
+
"state_college" => "pennstate",
|
137
|
+
"rhode_island" => "providence",
|
138
|
+
"florence" => "florencesc",
|
139
|
+
"greenville_upstate" => "greenville",
|
140
|
+
"northeast_sd" => "nesd",
|
141
|
+
"pierre_central_sd" => "csd",
|
142
|
+
"rapid_city_west_sd" => "rapidcity",
|
143
|
+
"sioux_falls_se_sd" => "siouxfalls",
|
144
|
+
"south_dakota" => "sd",
|
145
|
+
"jackson" => "jacksontn",
|
146
|
+
"beaumont_port_arthur" => "beaumont",
|
147
|
+
"dallas_fort_worth" => "dallas",
|
148
|
+
"deep_east_texas" => "nacogdoches",
|
149
|
+
"del_rio_eagle_pass" => "delrio",
|
150
|
+
"killeen_temple_ft_hood" => "killeen",
|
151
|
+
"mcallen_edinburg" => "mcallen",
|
152
|
+
"odessa_midland" => "odessa",
|
153
|
+
"southwest_tx" => "bigbend",
|
154
|
+
"tyler_east_tx" => "easttexas",
|
155
|
+
"victoria" => "victoriatx",
|
156
|
+
"ogden_clearfield" => "ogden",
|
157
|
+
"provo_orem" => "provo",
|
158
|
+
"vermont" => "burlington",
|
159
|
+
"hampton_roads" => "norfolk",
|
160
|
+
"new_river_valley" => "blacksburg",
|
161
|
+
"southwest_va" => "swva",
|
162
|
+
"kennewick_pasco_richland" => "kpr",
|
163
|
+
"olympic_peninsula" => "olympic",
|
164
|
+
"pullman_moscow" => "pullman",
|
165
|
+
"seattle_tacoma" => "seattle",
|
166
|
+
"skagit_island_sji" => "skagit",
|
167
|
+
"spokane_coeur_d_alene" => "spokane",
|
168
|
+
"charleston" => "charlestonwv",
|
169
|
+
"eastern_panhandle" => "martinsburg",
|
170
|
+
"huntington_ashland" => "huntington",
|
171
|
+
"northern_panhandle" => "wheeling",
|
172
|
+
"parkersburg_marietta" => "parkersburg",
|
173
|
+
"southern_wv" => "swv",
|
174
|
+
"west_virginia_old" => "wv",
|
175
|
+
"appleton_oshkosh_fdl" => "appleton",
|
176
|
+
"kenosha_racine" => "racine",
|
177
|
+
"guam_micronesia" => "micronesia",
|
178
|
+
"u_s_virgin_islands" => "virgin",
|
179
|
+
"medicine_hat" => "hat",
|
180
|
+
"peace_river_country" => "peace",
|
181
|
+
"fraser_valley" => "abbotsford",
|
182
|
+
"kelowna_okanagan" => "kelowna",
|
183
|
+
"kootenays" => "cranbrook",
|
184
|
+
"skeena_bulkley" => "skeena",
|
185
|
+
"sunshine_coast" => "sunshine",
|
186
|
+
"st_john_s" => "newfoundland",
|
187
|
+
"brantford_woodstock" => "brantford",
|
188
|
+
"chatham_kent" => "chatham",
|
189
|
+
"hamilton_burlington" => "hamilton",
|
190
|
+
"kitchener_waterloo_cambridge" => "kitchener",
|
191
|
+
"london" => "londonon",
|
192
|
+
"niagara_region" => "niagara",
|
193
|
+
"ottawa_hull_gatineau" => "ottawa",
|
194
|
+
"sault_ste_marie" => "soo",
|
195
|
+
"prince_edward_island" => "pei",
|
196
|
+
"quebec_city" => "quebec",
|
197
|
+
"belgium" => "brussels",
|
198
|
+
"croatia" => "zagreb",
|
199
|
+
"finland" => "helsinki",
|
200
|
+
"brittany" => "rennes",
|
201
|
+
"loire_valley" => "loire",
|
202
|
+
"marseille" => "marseilles",
|
203
|
+
"nice_cote_d_azur" => "cotedazur",
|
204
|
+
"normandy" => "rouen",
|
205
|
+
"essen_ruhr" => "essen",
|
206
|
+
"greece" => "athens",
|
207
|
+
"florence_tuscany" => "florence",
|
208
|
+
"napoli_campania" => "naples",
|
209
|
+
"sicilia" => "sicily",
|
210
|
+
"venice_veneto" => "venice",
|
211
|
+
"amsterdam_randstad" => "amsterdam",
|
212
|
+
"norway" => "oslo",
|
213
|
+
"poland" => "warsaw",
|
214
|
+
"faro_algarve" => "faro",
|
215
|
+
"romania" => "bucharest",
|
216
|
+
"sweden" => "stockholm",
|
217
|
+
"turkey" => "istanbul",
|
218
|
+
"birmingham_west_mids" => "birmingham",
|
219
|
+
"cambridge_uk" => "cambridge",
|
220
|
+
"cardiff_wales" => "cardiff",
|
221
|
+
"devon_cornwall" => "devon",
|
222
|
+
"east_anglia" => "norwich",
|
223
|
+
"east_midlands" => "eastmids",
|
224
|
+
"newcastle_ne_england" => "newcastle",
|
225
|
+
"guam_micronesia" => "micronesia",
|
226
|
+
"chennai_madras" => "chennai",
|
227
|
+
"kolkata_calcutta" => "kolkata",
|
228
|
+
"surat_surat" => "surat",
|
229
|
+
"indonesia" => "jakarta",
|
230
|
+
"iran" => "tehran",
|
231
|
+
"iraq" => "baghdad",
|
232
|
+
"west_bank" => "ramallah",
|
233
|
+
"osaka_kobe_kyoto" => "osaka",
|
234
|
+
"beirut_lebanon" => "beirut",
|
235
|
+
"bicol_region" => "naga",
|
236
|
+
"cagayan_de_oro" => "cdo",
|
237
|
+
"taiwan" => "taipei",
|
238
|
+
"thailand" => "bangkok",
|
239
|
+
"united_arab_emirates" => "dubai",
|
240
|
+
"newcastle_nsw" => "ntl",
|
241
|
+
"tasmania" => "hobart",
|
242
|
+
"caribbean_islands" => "caribbean",
|
243
|
+
"bolivia" => "lapaz",
|
244
|
+
"rio_de_janeiro" => "rio",
|
245
|
+
"salvador_bahia" => "salvador",
|
246
|
+
"chile" => "santiago",
|
247
|
+
"dominican_republic" => "santodomingo",
|
248
|
+
"ecuador" => "quito",
|
249
|
+
"baja_california_sur" => "bajasur",
|
250
|
+
"ciudad_juarez" => "juarez",
|
251
|
+
"puerto_vallarta" => "pv",
|
252
|
+
"nicaragua" => "managua",
|
253
|
+
"peru" => "lima",
|
254
|
+
"venezuela" => "caracas",
|
255
|
+
"virgin_islands" => "virgin",
|
256
|
+
"egypt" => "cairo",
|
257
|
+
"ethiopia" => "addisababa",
|
258
|
+
"ghana" => "accra",
|
259
|
+
"morocco" => "casablanca",
|
260
|
+
"tunisia" => "tunis"
|
261
|
+
}
|
262
|
+
end
|