Отправить POST запрос на сайт используя ruby

[Е] Егор, 3 августа 2016, 21:39 , 2 подписчика

Добрый день.

Есть задача, над которой я завис. Есть сайт, в котором есть форма, после ввода данных происходит POST запрос и тут же идет возврат ответа. Вот задача как раз стоит распарсить данный ответ. Вопросов с парсингом нет. Вопрос как передать в скрипте ruby запрос к этому сайту. Варианты: 1) Используем Capybara

require 'rubygems'
require 'capybara'
require 'capybara/dsl'

Capybara.run_server = false
Capybara.current_driver = :selenium
Capybara.app_host = 'https://ya.ru/'

module MyCapybaraTest
  class Test
    include Capybara::DSL
      def get_title
        visit('/')
      fill_in 'text', with: "ruby"
      click_button 'Найти'
      end
  end
end

t = MyCapybaraTest::Test.new
puts t.get_title

Понятно, что вместо яндекса будет другой сайт, с другим запросом. Но данная имитация работает так как нужно. но тогда задача вот в чем: Как отключить драйвер cucumber? Я так понял, что Capybara идет вместе с cucumber либо webkit'ом. Можно ли вместо них использовать те же Nokogiri либо Mechanize, просто не хочу, чтобы вылазила данная страница броузера пока идет выполнения. (capybar'у использовал до этого только для теста локального приложения для rails)

2) Возможно второй вариант: использовать curl ? Но как сделать в linux консоле post запрос на данном сайте и вернуть ответ я так и не понял. Но думаю можно (тем более даже гемчик есть для ruby 'curl'

3) Возможно есть третий вариант, о котором я не подозреваю? Произошла эмуляция действий на сайте с отправкой Post запроса => возврат данных который вернул данный запрос.

Обсуждение (8)


[Е]

Как я понял, это можно сделать и просто через гем Mechanize, но засада в том, что он не работает, если есть input, но при этом нет тэга <form>. А у меня как раз такая ситуация: код:

require 'rubygems'
require 'mechanize'

agent = Mechanize.new

page = agent.get('https://lookup-id.com/')
pp page

вывод:

#<Mechanize::Page
 {url #<URI::HTTPS https://lookup-id.com/>}
 {meta_refresh}
 {title "Find my Facebook ID | Find Facebook Group ID | Find Facebook Page ID"}
 {iframes}
 {frames}
 {links
  #<Mechanize::Page::Link "    " nil>
  #<Mechanize::Page::Link "Lookup-ID.com" "https://lookup-id.com/">
  #<Mechanize::Page::Link "Facebook ID" "https://lookup-id.com/">
  #<Mechanize::Page::Link
   "Facebook Card"
   "https://lookup-id.com/facebookcard.html">
  #<Mechanize::Page::Link
   "FB Search"
   "https://lookup-id.com/facebooksearch.html">
  #<Mechanize::Page::Link
   "Extract Members"
   "https://lookup-id.com/get_facebookid.php">
  #<Mechanize::Page::Link " Directory" "https://lookup-id.com/dir/">
  #<Mechanize::Page::Link "Resources" "https://lookup-id.com/resource/">
  #<Mechanize::Page::Link "click here" "https://www.facebook.com/profile.php">
  #<Mechanize::Page::Link
   "Facebook Groups Autoposter"
   "http://groupsforyou.com/autopost/">
  #<Mechanize::Page::Link "Career" "https://lookup-id.com/career">
  #<Mechanize::Page::Link "Privacy" "https://lookup-id.com/privacy-policy">
  #<Mechanize::Page::Link "About Us" "https://lookup-id.com/about-us">
  #<Mechanize::Page::Link "" "https://twitter.com/lookupiddotcom">
  #<Mechanize::Page::Link "" "https://plus.google.com/116867839880707442258/">
  #<Mechanize::Page::Link "" "https://www.facebook.com/lookupid">}
 {forms
  #<Mechanize::Form
   {name nil}
   {method "POST"}
   {action ""}
   {fields [text:0x4743d9a type: text name: fburl value: ]}
   {radiobuttons}
   {checkboxes}
   {file_uploads}
   {buttons [submit:0x4743c82 type: submit name: check value: Lookup]}>}>

[Е]

Так, стэковерфлоу мне наврал (касательно того, что mechanize не будет работать если нет тэга <form>), можно в предыдущий ответ не смотреть. Вот код, который все прекрасно заполняет, даже если на форме нет тэга <form>:

require 'rubygems'
require 'mechanize'

agent = Mechanize.new
page = agent.get('https://lookup-id.com/')

form = page.forms.first # => Mechanize::Form
#form.fields.each { |f| puts f.name } #можем просто посмотреть все названия полей формы

form['fburl'] = 'https://www.facebook.com/groups/clubneec/'

pp page #вывод DOM структуры для mechanize

Как видим value у нас заполнился

   {fields
    [text:0x4f8986a type: text name: fburl value: https://www.facebook.com/groups/clubneec/]}

Осталось понять как все это сабмиттить, чтобы получить результат..


[Е]

В общем разобрался как сабмитить, но как выяснил mechanize не дружит с ajax запросами и не понимает JS.

Остановился на этом:

require 'rubygems'
require 'mechanize'

require 'capybara'
require 'capybara/dsl'

Capybara.run_server = false
Capybara.current_driver = :selenium
Capybara.app_host = 'https://lookup-id.com/'

module MyCapybaraTest
  class Test
    include Capybara::DSL
      def get_title
        visit('/')
        fill_in 'input_url', with: "https://www.facebook.com/groups/clubneec/"
        click_button 'facebook_lookup_botton'
        page.body
      end
  end
end

t = MyCapybaraTest::Test.new
html_doc = Nokogiri::HTML(t.get_title)
puts html_doc.xpath("//span[@id='code']/text()")

На данный момент оно работает так как нужно, вот только окно браузера бесит, а как сделать в фоне не понимаю. Не понимаю, как подключить дравер mechanize к capybara, данный код не работает:

Capybara.register_driver :mechanize do |app|
    Capybara::Mechanize::Driver.new(app)
end

Помогите советом, пожалуйста..


Вадим Венедиктов Учитель

[В]

как выяснил mechanize не дружит с ajax запросами и не понимает JS.

А полтергейст не пробовали?

https://github.com/teampoltergeist/poltergeist

Очень советую.


[Е]

Вадим, спасибо за наводку. Я нашел решение своей задачи, другим, тривиальными способом. А, почитав по данный гем, понял, что он мне очень понадобиться для TDD\BDD, я сейчас как раз изучаю работу рельс с ajax, и как раз задавался вопросом как это тестировать.

Если интересно решение (вдруг кому-то понадобиться нечто подобное). Стояла задача в следующем: вводим ссылку на группу\страницу в фейсбуке, после ввода получаем ее title. Вроде бы кажется все просто, но как всегда есть подводные камни: 1) Если вы не зарегестрированы на фейсбуке, то при вводе ссылку на группу вас попросят залогиниться. 2) Если у вас есть токен разработчика, то тоже не получиться. В апи можно вывести название группы только зная id данной группы. А его (id группы) через api не получить по ссылке на группу. Это сделано специально фейсбуком для борьбы со скрапингом (также выснил в ходе решения задачи ))))

Как решал Придумал два способа: 1) Есть сервис https://lookup-id.com/, который по ссылке на группу выводит данный id, по которому я бы уже смог получить id. Все проблемы можно почитать выше, с чем столкнулся

2) Просто залогиниться на сайт, затем пройти по ссылке группы и получить ее title. Вот тут я столкнулся с проблемой, при которой с помощью mechanize я логинился, но при вводе следующей ссылке фейсбук считал меня незалогенным пользователем.

Решение. Бился именно над решением первого способа, но в итоге решил отвлечься и во втором способе просто сохранил куки через mechandize и сразу получил результат, который мне нужен (тривиального решение, не правда ли)). Вот полный код:

require 'rubygems'
require 'mechanize'

# Укажем в данном блоке параметры подключения
root_url = 'https://facebook.com/'
username = 'your_email'
userpass = 'your_password'


agent = Mechanize.new

page = agent.get(root_url)
puts 'Добро пожаловать на', page.title()

# На фейсбуке форма ввода логина\пароля стоит первой
# Ее и выбераем
form = page.forms.first

puts "Пробуем залогиниться"
form['email'] = username #заполняем поле email
form['pass'] = userpass #заполняем пароль
result_page = form.submit() # Нажимаем на кнопку
agent.cookie_jar.save_as 'cookies'
#Сохраняем куки и выводим результат
puts agent.get("https://www.facebook.com/groups/clubneec/").title

Собственно все, задача решена, и очень просто. Данный способ возможно кому-то приходится не только логиниться на фейсбук.

Ради интереса попробую решить задачу первым способом используя вышеуказаннй гем

Всем спасибо.


Вадим Венедиктов Учитель

[В]

А глобально какая задача, чем занимаетесь сейчас, какой-то сервис делаете или просто в рамках обучения?


[Е]

Вадим, вы можете обращаться ко мне на ты (если вы не против)).

сейчас в виде стажировки меня взяли на проект https://mindpowergame.com/ Он написан на рельсах, сейчас на нем идет переписка кода, вот на нем и получаю разные задачки, в качестве опыта очень нравиться. Данная задача была как раз одна из них, нужно было в админке реализовать форму, в которую админ вводит ссылку, ajax'ом выводится информация по данной ссылке (включая отпарсенный title) в виде формы в модальном окне на дальной странице, инфу можно редактировать и по кнопке сохранить все в базу записывается. Задачу сделал, вот только был вопрос по фейсбуку.

Плюс параллельно с этим для себя делаю проект, где пробую всякие фишки с рельсами, гемы, а также изучаю TDD\BDD на нем

Вот пока как-то так :)))


Вадим Венедиктов Учитель

[В]

Супер! Держите в курсе!

На Вы мне проще! :)