Skip to content

Instantly share code, notes, and snippets.

@hac
Created January 4, 2011 02:00
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hac/764284 to your computer and use it in GitHub Desktop.
Save hac/764284 to your computer and use it in GitHub Desktop.
A class for automating basic user tasks on FaceBook.
#!/usr/bin/ruby
require 'rubygems'
require 'mechanize'
# We will probably want to start using JSON instead of regular expressions sometime.
#require 'json'
class Mechanize::Page
# This is a workaround for a problem with Mechanize. It lets you search for forms by id when scraping a page.
def form_id(formId)
formContents = (self/:form).find { |elem| elem['id'] == formId }
if formContents then return Mechanize::Form.new(formContents) end
end
end
class FacebookBot
def initialize(email, pass)
@fbUrl = "http://www.facebook.com/"
@mobileUrl = "http://m.facebook.com/"
@email, @pass = email, pass
@agent = Mechanize.new
@agent.user_agent_alias = 'Mac Safari'
@cookies = File.dirname(__FILE__) + "/cookies-" + @email + ".yml"
if (File.file?(@cookies))
@agent.cookie_jar.load(@cookies)
puts "Saved cookies:", @agent.cookies
else
puts "No saved cookies."
end
self.login
end
def login
page = @agent.get(@fbUrl)
# Read stored cookies.
if (loginf = page.form_id("login_form"))
puts "Logging in..."
loginf.set_fields(:email => @email, :pass => @pass)
page = @agent.submit(loginf, loginf.buttons.first)
puts page.form_id("logout_form")? "Login Successful" : "Login Failed"
else
puts "Not logging in. Already Logged In!"
end
# Write login cookies. Once these are written your password is not used again until your session expires.
@agent.cookie_jar.save_as(@cookies)
body = page.root.to_html
# @uid = %r{\\"user\\":(\d+),\\"hide\\"}.match(body)[1] # This is a UID given to each Facebook user.
@uid = %r{user:(\d+),}.match(body)[1] # This is a UID given to each Facebook user.
# @post_form_id = %r{<input type="hidden" id="post_form_id" name="post_form_id" value="([^"]+)}.match(body)[1] # This is a token we need to submit forms.
@post_form_id = %r{name=\\"post_form_id\\" value=\\"([^"]+)\\"}.match(body)[1] # This is a token we need to submit forms.
end
def postStatus(status)
puts "Sharing text..."
page = @agent.get(@mobileUrl)
composerForm = page.form_id("composer_form")
composerForm.set_fields(:fb_dtsg => "A6vyP", :post_form_id => @post_form_id, :charset_test => "€,´,€,´,水,Д,Є", :status => status)
@agent.submit(composerForm, composerForm.buttons.first)
puts "Done."
end
def suggestedFriends
page = @agent.get(@fbUrl + "find-friends")
friends = []
page.search(".friend_browser_page_name_box/a").each do
|my_tag| friends.push(%r{\?id=(\d+)"}.match(my_tag.to_html)[1]) # Add the person's id to an array.
# The person's display name would be (my_tag.to_html.gsub(/<\/?[^>]*>/, "")
end
friends
end
def requestFriend(friendId)
r = @agent.post('http://www.facebook.com/ajax/profile/connect.php?profile_id=' + friendId.to_s + '&rel_dialog=1&src=fbx_top_bar&ref=none&__a=1',
'profile_id' => friendId,
'rel_dialog' => 1,
'src' => 'fbx_top_bar',
'ref' => 'none',
'__d' => 1,
'post_form_id' => @post_form_id,
'fb_dtsg' => 'A6vyP',
'lsd' => '',
'post_form_id_source' => 'AsyncRequest').body
submit_token = %r{\\"submit_token\\":\\"([0-9a-z]+)\\"}.match(r)[1]
r = @agent.post('http://www.facebook.com/ajax/profile/connect.php?__a=1',
'user' => @uid,
'profile_id' => friendId,
'submit_token' => submit_token,
'source' => 'profile_button',
'src' => 'fbx_top_bar',
'submit' => 1,
'post_form_id' => @post_form_id,
'fb_dtsg' => 'A6vyP',
'lsd' => '',
'post_form_id_source' => 'AsyncRequest').body
end
def acceptRequests
puts "Accepting all requests..."
page = @agent.get(@mobileUrl + "friends.php")
page.forms.each { |form| if (form.buttons.first.value=="Confirm" || form.buttons.first.value=="Add Friend") then @agent.submit(form, form.buttons.first) end }
puts "Done."
end
# Get recent status changes or text posts on other people's walls.
def recentPosts
page = @agent.get(@mobileUrl + "stories.php")
posts = []
page.search(".c div").each do |my_tag|
if (authorLink = my_tag.search("a").first) then
author = authorLink.inner_text
authorLink.remove
end
if (my_tag.to_html.scan("\342\226\266").count) then # It's a conversation.
if (recieverLink = my_tag.search("a").first) then recieverLink.remove end
end
post = {"text" => my_tag.inner_text.gsub("\342\226\266", "").strip, "authorName" => author}
if (recieverLink) then post["recieverName"] = recieverLink.inner_text end;
posts.push(post)
end
posts
end
def personalMessages(showRead = false)
page = @agent.get(@mobileUrl + (showRead ? "inbox#!/inbox/" : "inbox#!/inbox/?unread"))
messages = []
page.search("table.results/*/td").each do |my_tag|
senderTag = my_tag.search("a[@href^='/profile']").first
subjectTag = my_tag.search("a[@href^='/inbox']").first
replyTag = my_tag.search("a[@href^='/inbox/readmessage.php']").first
messageId = %r{\?t=(\d+)}.match(replyTag.attributes["href"])[1]
message = {"subject" => subjectTag.inner_text.gsub("\342\200\242", ''), "senderName" => senderTag.inner_text, "messageId" => messageId}
# Remove all divs except the one with the message.
my_tag.search("div.note").remove
my_tag.search("div.mfss").remove
message["body"] = my_tag.inner_text
messages.push(message)
end
messages
end
# This method is unfinished.
def replyToMessageWithText(messageId, messageText)
page = @agent.get(@mobileUrl + "inbox/readmessage.php?t=" + messageId)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment