Logging into website using Mechanize to fill in form? - ruby

I am trying to log into a site using Mechanize.
The form I am trying to fill out is the only one for on the page and is called "admin-login". The user name field has a name of "un" and the password field has a name of "pw".
My error output is:
myserver:in `addProduct': undefined local variable or method `form_name' for main:Object (NameError) from login.rb:82:in `<main>'
My code is:
def addProduct
agent = Mechanize.new
page = agent.get( 'correctURL' )
correctURL_form = page.form( 'admin-login' )
form_name.un = 'username'
form_pass.pw = 'password'
page = agent.submit( form_name, form_pass, correctURL_form.buttons.first )
puts page.body
end
Am I missing something here? I was told that this was fairly easy to pick up but I am really struggling with the basics of Mechanize.

I'd use something more like:
admin_login = page.form( 'admin-login' )
form_name = 'username'
form_pass = 'password'
page = agent.submit( form_name, form_pass, admin_login.buttons.first )
You can't name a variable with a '.' in it:
form_name.un = 'username'
form_pass.pw = 'password'
Ruby will assume that you're talking about instances of some class, called form_name or form_pass, which have methods called un and pw respectively. And, since those aren't defined, Ruby complains.
Instead, use a simple variable name and Ruby will be happy.
Also, note that variable names like correctURL_form are not Ruby-like. We use snake_case names for instance variables.

Okay, I have gotten it to work. Here is my corrected code.
def addProduct
agent = Mechanize.new
page = agent.get( 'correctURL' )
correctURL_form = page.form( 'admin-login' )
correctURL_form.un = 'username'
correctURL_form.pw = 'password'
page = agent.submit( correctURL_form, correctURL_form.buttons.first )
puts page.body
end
This got the output of the success page. Thanks all for the help!

Related

Why am I getting an unsupportedSchemeError

I am writing a program that uses Mechanize to scrape a student's grades and classes from edline.net using a student account and return the data I need. However, after logging in, from the homepage I have to access a link (called 'Private Reports') which will then dynamically return a page of links to each of the student's classes and respective grades.
When testing I create a new object my_account that has several instance variables including the homepage. I pointed new variables to the instance variables for this to be more simple to read):
result_page = agent.page.link_with(:text => 'Private Reports').click
I get:
Mechanize::UnsupportedSchemeError
But if I were to replace :click with :text it responds correctly and result_page will equal the link's text "Private Reports"
Why does it respond to :text correctly but give an error for :click? Is there a way to get around this or should I rethink my solution to this problem?
Here's the code:
class AccountFetcher
EDLINE_LOGIN_URL = 'http://edline.net/Index.page'
def self.fetch_form(agent)
# uses #agent of an Account object
page = agent.get(EDLINE_LOGIN_URL)
form = page.form('authenticationEntryForm')
end
# edline's login form has to have several pre-conditions met before submitting the form
def self.initialize_form(agent)
form = AccountFetcher.fetch_form(agent)
submit_event = form.field_with(:name => 'submitEvent')
enter_clicked = form.field_with(:name => 'enterClicked')
ajax_support = form.field_with(:name => 'ajaxSupported')
ajax_support.value = 'yes'
enter_clicked.value = true
submit_event.value = 1
return form
end
# logs the user in and returns the homepage
def self.fetch_homepage(u_username, u_password, agent)
form = AccountFetcher.initialize_form(agent)
username = form.field_with(:name => 'screenName')
password = form.field_with(:name => 'kclq')
username.value = u_username
password.value = u_password
form.submit
end
end
# class Account will be expanded later on but here are the bare bones for a user to log in to their account
class Account
attr_accessor :report, :agent, :username, :password
def initialize(u_username, u_password)
#agent = Mechanize.new
#username = u_username
#password = u_password
end
def login
page = AccountFetcher.fetch_homepage(self.username, self.password, self.agent)
#report = page
end
end
my_account = Account.new('ex_username', 'ex_password')
my_account.login
page = my_account.report
agent = my_account.agent
page = agent.page.link_with(:text => 'Private Reports').click
Where does the link point to? Ie, what's the href?
I ask because "scheme" usually refers to something like http or https or ftp, so maybe the link has a weird scheme that mechanize doesn't know how to handle, hence Mechanize::UnsupportedSchemeError

Using Ruby and Mechanize to fill in a remote login form mystery

I am trying to implement a Ruby script that will take in a username and password, then proceed to fill in the account details on a login form on another website and return the then follow a link and retrieve the account history. To do this I am using the Mechanize gem.
I have been following the examples here
but still I cant seem to get it to work. I have simplified this down greatly to try get it to work in parts but a supposedly simple filling in a form is holding me up.
Here is my code:
# script gets called with a username and password for the site
require 'mechanize'
#create a mechanize instant
agent = Mechanize.new
agent.get('https://mysite/Login.aspx') do |login_page|
#fill in the login form on the login page
loggedin_page = login_page.form_with(:id => 'form1') do |form|
username_field = form.field_with(:id => 'ContentPlaceHolder1_UserName')
username_field.value = ARGV[0]
password_field = form.field_with(:id => 'ContentPlaceHolder1_Password')
password_field.value = ARGV[1]
button = form.button_with(:id => 'ContentPlaceHolder1_btnlogin')
end.submit(form , button)
#click the View my history link
#account_history_page = loggedin_page.click(home_page.link_with(:text => "View My History"))
####TEST to see if i am actually making it past the login page
#### and that the View My History link is now visible amongst the other links on the page
loggedin_page.links.each do |link|
text = link.text.strip
next unless text.length > 0
puts text if text == "View My History"
end
##TEST
end
Terminal error message:
stackqv2.rb:19:in `block in <main>': undefined local variable or method `form' for main:Object (NameError)
from /usr/local/lib/ruby/gems/1.9.1/gems/mechanize-2.5.1/lib/mechanize.rb:409:in `get'
from stackqv2.rb:8:in `<main>'
You don't need to pass form as an argument to submit. The button is also optional. Try using the following:
loggedin_page = login_page.form_with(:id => 'form1') do |form|
username_field = form.field_with(:id => 'ContentPlaceHolder1_UserName')
username_field.value = ARGV[0]
password_field = form.field_with(:id => 'ContentPlaceHolder1_Password')
password_field.value = ARGV[1]
end.submit
If you really do need to specify which button is used to submit the form, try this:
form = login_page.form_with(:id => 'form1')
username_field = form.field_with(:id => 'ContentPlaceHolder1_UserName')
username_field.value = ARGV[0]
password_field = form.field_with(:id => 'ContentPlaceHolder1_Password')
password_field.value = ARGV[1]
button = form.button_with(:id => 'ContentPlaceHolder1_btnlogin')
loggedin_page = form.submit(button)
It's a matter of scope:
page.form do |form|
# this block has its own scope
form['foo'] = 'bar' # <- ok, form is defined inside this block
end
puts form # <- error, form is not defined here
ramblex's suggestion is to not use a block with your form and I agree, it's less confusing that way.

login vk.com net::http.post_form

I want login to vk.com or m.vk.com without Ruby. But my code dosen't work.
require 'net/http'
email = "qweqweqwe#gmail.com"
pass = "qeqqweqwe"
userUri = URI('m.vk.com/index.html')
Net::HTTP.get(userUri)
res = Net::HTTP.post_form(userUri, 'email' => email, 'pass' => pass)
puts res.body
First of all, you need to change userUri to the following:
userUri = URI('https://login.vk.com/?act=login')
Which is where the vk site expects your login parameters.
I'm not very faimilar with vk, but you probably need a way to handle the session cookie. Both receiving it, and providing it for future requests. Can you elaborate on what you're doing after login?
Here is the net/http info for cookie handling:
# Headers
res['Set-Cookie'] # => String
res.get_fields('set-cookie') # => Array
res.to_hash['set-cookie'] # => Array
puts "Headers: #{res.to_hash.inspect}"
This kind of task is exactly what Mechanize is for. Mechanize handles redirects and cookies automatically. You can do something like this:
require 'mechanize'
agent = Mechanize.new
url = "http://m.vk.com/login/"
page = agent.get(url)
form = page.forms[0]
form['email'] = "qweqweqwe#gmail.com"
form['pass'] = "qeqqweqwe"
form.submit
puts agent.page.body

When submitting a login form using mechanize-ruby, Can I use variables to represent field names?

I ran into a problem when using Mechanize to submit a login form. For example, if I need to log into bitbucket:
a = Mechanize.new
a.get('https://bitbucket.org/') do |page|
login_page = a.click(page.link_with(text: 'Log In'))
my_page = login_page.form_with(action: '/account/signin/') do |f|
# The "username" and "password" below are the values of the "name" attribute of the two login form fields
f.username = 'MY_ACCOUNT_NAME'
f.password = 'MY_PASSWORD'
end.click_button
end
That's pretty straight forward, however, not all login forms have the same "name" value on those two fields. WordPress' login form, for example, uses "log" and "pwd" . This would invalidate the above code.
I want to pass some parameters into this method so that it can be used on different login forms.
I attempted to follow "How to convert from a string to object attribute name?" but was unsuccessful:
# auth_info is a hash
def website_login(auth_info)
a = Mechanize.new
a.get(auth_info[:login_page_url]) do |page|
land_page = page.form_with(action: auth_info[:login_form_action]) do |f|
# Now I am stuck with these two lines
????????
????????
# I tried to do it like this. Not working.
f.instance_variable_set('#'+auth_info[:username_field_name], auth_info[:username])
f.instance_variable_set('#'+auth_info[:password_field_name], auth_info[:password])
end.click_button
end
end
Really appreciate if someone can help out.
Resolved. It's like this:
f.send(auth_info[:username_field_name] + '=', auth_info[:username])
f.send(auth_info[:password_field_name] + '=', auth_info[:password])

Need help in debugging a tiny ruby script

I get the following error, when i run my script.
fetch_scores.rb:20:in `<main>': undefined local variable or method `__EVENTTARGET' for main:Object (NameError)
HereÅ› the script:
#fetch_scores.rb
require 'net/http'
require 'open-uri'
#define a constant named URL so if the results URL changes we don't
#need to replace a hardcoded URL everywhere.
URL = "http://www.nitt.edu/prm/nitreg/ShowRes.aspx"
#checking the count of arguments passed to the script.
#it is only taking one, so let's show the user how to use
#the script
if ARGV.length != 1
puts "Usage: fetch_scores.rb student_name"
else
roll_no = ARGV[0] #could drop the ARGV length check and add a default using ||
# or name = ARGV[0] || nikhil
end
params = {
__EVENTTARGET => "Dt1",
__EVENTARGUMENT => "",
__VIEWSTATE => "dDwtMTM3NzI1MDM3O3Q8O2w8aTwxPjs+O2w8dDw7bDxpPDE+O2k8Mj47aTw0Pjs+O2w8dDxwPHA8bDxWaXNpYmxlOz47bDxvPHQ+Oz4+Oz47bDxpPDE+O2k8Mz47PjtsPHQ8O2w8aTwwPjtpPDE+O2k8Mj47aTwzPjtpPDQ+O2k8NT47aTw2Pjs+O2w8dDw7bDxpPDA+Oz47bDx0PDtsPGk8MT47PjtsPHQ8cDxwPGw8VGV4dDs+O2w8VEhJUkQgU0VNRVNURVIgTUFTVEVSIE9GIENPTVBVVEVSIEFQUExJQ0FUSU9OUyBOT1YtMjAxMChSRUdVTEFSKTs+Pjs+Ozs+Oz4+Oz4+O3Q8O2w8aTwxPjs+O2w8dDw7bDxpPDE+Oz47bDx0PHA8cDxsPFRleHQ7PjtsPFNVREVFUCBBR0FSV0FMOz4+Oz47Oz47Pj47Pj47dDw7bDxpPDE+Oz47bDx0PDtsPGk8MT47PjtsPHQ8cDxwPGw8VGV4dDs+O2...xwPGw8VGV4dDs+O2w8MTk7Pj47Pjs7Pjs+Pjs+Pjt0PDtsPGk8MT47PjtsPHQ8O2w8aTwxPjs+O2w8dDxwPHA8bDxUZXh0Oz47bDwwOz4+Oz47Oz47Pj47Pj47Pj47dDxwPHA8bDxWaXNpYmxlOz47bDxvPGY+Oz4+Oz47Oz47Pj47dDw7bDxpPDk+O2k8MTE+Oz47bDx0PHA8cDxsPFRleHQ7VmlzaWJsZTs+O2w8U2VsZWN0IFNlc3Npb24gICA7bzx0Pjs+Pjs+Ozs+O3Q8dDxwPHA8bDxWaXNpYmxlOz47bDxvPHQ+Oz4+Oz47dDxpPDM+O0A8LSBTZWxlY3QgLTtOT1YtMjAxMChSRUdVTEFSKTtNQVktMjAxMVtSRUdVTEFSXTs+O0A8MDs2Mjs2Njs+PjtsPGk8MT47Pj47Oz47Pj47dDxwPHA8bDxUZXh0Oz47bDxcZTs+Pjs+Ozs+Oz4+Oz4+Oz53I0hrrJ9pq04wIekH/y79mq+lYQ==",
TextBox1 => roll_no,
Dt1 => 66
}
results = Net::HTTP.post_form( URL, params )
p results
__EVENTTARGET in the params hash is parsed as a variable and that variable was never defined. Try "__EVENTTARGET" => "Dt1".

Resources