-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfoodspot_friend.rb
170 lines (135 loc) · 4.05 KB
/
foodspot_friend.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#!/usr/bin/env ruby
# This script uses Selenium WebDriver and Firefox to scrape the friends and
# followers lists of a Foodspotting user.
# Then it groups the contacts into 3 sets: mutual friends, only followers, and
# only following.
require 'selenium-webdriver'
require 'set'
require 'optparse'
# Get the user name.
def get_user_name web
puts 'Getting user name...'
url = 'http://foodspotting.com/me'
web.get url
m = web.current_url.match(%r{foodspotting\.com/([^/]+)$})
raise 'Unable to retrieve user name.' unless m
m[1]
end
# Find the highest-numbered page by parsing the pages links.
def get_last_page web
web.find_elements(:css, 'div.pagination a[href*="?page="]').map { |elem|
elem.attribute('href').match(/\?page=(\d+)/)[1].to_i
}.max
end
# Parse user IDs and names from the contact list.
def get_names web
web.find_elements(:css, 'div.title a').map { |elem|
id = elem.attribute('href').sub(%r{^/}, '')
name = elem.text.strip
{ id: id, name: name }
}
end
# Process the contact list, returning a list of users from all the pages in
# the list.
def process_list what, username, web
puts "Fetching #{what} page 1..."
url = "http://www.foodspotting.com/#{username}/#{what}"
web.get url
last_page = get_last_page web
names = get_names web
(2..last_page).each { |page|
puts "Fetching #{what} page #{page}..."
web.get "#{url}?page=#{page}"
names += get_names web
}
names
end
def show_list flist
flist.each_with_index { |name, i|
puts "#{i + 1}: #{name[:id]} - #{name[:name]}"
}
end
# Wait for user to log in to Foodspotting, if necessary.
def check_login web
url = 'https://www.foodspotting.com'
web.get url
begin
web.find_element(id: 'mini-profile')
rescue Selenium::WebDriver::Error::NoSuchElementError
puts 'Please log in to Foodspotting'
wait = Selenium::WebDriver::Wait.new(timeout: 900)
wait.until { web.find_element(id: 'mini-profile') }
end
end
# Use Spotlight to find the Firefox binary.
def setup_firefox_path
firefox_app = nil
IO.popen('mdfind "kMDItemFSName = Firefox*.app"') { |io|
firefox_app = io.gets
}
raise "Can't find Firefox app bundle" unless firefox_app
firefox_app.chomp!
Selenium::WebDriver::Firefox::Binary.path = File.join(firefox_app, 'Contents/MacOS/firefox')
end
def parse_opts
options = {}
optp = OptionParser.new
optp.banner = <<-EOM
This script uses Selenium WebDriver and Firefox to scrape the friends and
followers lists of a Foodspotting user.
Then it groups the contacts into 3 sets: mutual friends, only followers, and
only following.
Usage: #{File.basename $PROGRAM_NAME} [options]
EOM
optp.on('-h', '-?', '--help', 'Option help') {
puts optp
exit
}
optp.on('-m', '--mutual', 'Show mutual friends') {
options[:mutual_friends] = true
}
optp.on('-r', '--only-friends', 'Show only-friends') {
options[:only_friends] = true
}
optp.on('-o', '--only-followers', 'Show only-followers') {
options[:only_followers] = true
}
optp.separator ' If none of -m/-r/-o are specified, display all 3 categories.'
begin
optp.parse!
rescue OptionParser::ParseError => err
warn "Error parsing command line: #{err}\n\n"
warn optp
exit 1
end
if !options[:mutual_friends] && !options[:only_friends] && !options[:only_followers]
# If none of the 3 options are specified, show everything.
options[:mutual_friends] = options[:only_friends] = options[:only_followers] = true
end
options
end
options = parse_opts
web = nil
begin
setup_firefox_path
web = Selenium::WebDriver.for :firefox
check_login web
username = get_user_name web
followers = Set.new(process_list(:followers, username, web))
following = Set.new(process_list(:following, username, web))
if options[:mutual_friends]
puts 'Mutual followers:'
show_list(following & followers)
end
if options[:only_followers]
puts 'Only followers:'
show_list(followers - following)
end
if options[:only_friends]
puts 'Only following:'
show_list(following - followers)
end
ensure
web.close if web
end
__END__