Ruby Mechanize 使用小结

1. Mechanize 简介

The Mechanize library is used for automating interaction with websites. Mechanize automatically stores and sends cookies, follows redirects, and can follow links and submit forms. Form fields can be populated and submitted. Mechanize also keeps track of the sites that you have visited as a history.

简单来说:

Mechanize 是一个用来自动化和网站交互的类库。Mechanize 有着自动存储和发送 cookies、跟踪重定向和链接以及提交表单的功能。Mechanize 可以产生和提交表单的域。Mechanize 还能够记录你访问的历史记录。

2. Mechanize 简单使用

使用 Mechanize 需要 require 一下:

require 'mechanize'

2.1 Mechanize 获取页面

我们首先获取一个浏览器的代理:

@agent = Mechanize.new

我们可以对这个代理进行设置,伪装成各种主流的浏览器(此处不表)。然后通过 URL 获取指定页面:

@page = @agent.get('www.github.com')

2.2 表单操作

2.2.1 搜索框

@agent = Mechanize.new
@page = @agent.get('xxx.xxx.com')
form = @page.forms.first
form["q"] = "xxxxx"
result = form.submit

上述代码中使用 @page.forms.first 获取了第一个表单,在页面中包含多个表单时,可以使用 @page.form_with(action: "search") 这样的方法获取特定的表单。

2.2.2 登录表单

@agent = Mechanize.new
@page = @agent.get('xxx.xxx.com')
form = @page.form_with(action: "login")
form["username"] = "username"
form["password"] = "password"
result = form.submit

form 使用 hash 的形式进行参数的赋值,表单中的每个元素用 name 属性来获取。

2.3 获取页面中的元素

从页面中获取元素常见的方法是 @page.links 或者 @page.forms 这样的内建方法。但是要从页面中获取某个特定标签时,可以使用 XPath 来实现:

@page.parser.xpath("//div[name='content']/p[id='id']")

上述语句获取的是页面中一个 name 属性值为 contentdiv 标签下的 id 属性为 idp 标签。XPath 的具体使用方法请看参考文献。

但是偶尔也会碰上你想获取的元素既没有 id 也没有 name 属性的情况,这个时候只能靠类似下文的方法暴力匹配了:

link.children[0].children[2].children[1].text

2.4 POST 数据到指定 URI

Mechanize 不支持 Javascript,对于某些需要 Javascript 支持的表单,Mechanize 无法帮你获取到数据。但是我们可以直接发出 POST 请求。
一般来说,我们可以先使用 Firefox 或者 Chrome 浏览器查看执行 POST 请求时发送的数据中参数的名称、格式以及地址。然后将其作为模板,用我们实际使用的参数替换模板中的参数。以下就是一个例子:

post_url = "http://address/to/your/target/action"

date = Time.now.strftime('%Y-%m-%d')
release_params ={
  "issue[tracker_id]" => "9",
  "issue[subject]" => "[xx上线任务] #{date}",
  "issue[description]" => "#{description}",
  "issue[project_id]" => "46",
  "issue[assigned_to_id]" => "642",
  "issue[status_id]" => "1",
  "issue[priority_id]" => "13",
  "issue[custom_field_values][30]" => "642",
  "issue[custom_field_values][37]" => "xxxx"
}
@agent.post(post_url, release_params)

3. 参考文献