-
Notifications
You must be signed in to change notification settings - Fork 3
解析 HTTP 响应包
本文档讨论了如何以最简洁的方式解析 HTTP 响应正文.
获得响应包, 你可以使用 Rex::Proto::Http::Client 或 HttpClient mixin 来发出 HTTP 请求. 如果你正在编写一个模块, 你应该使用 mixin.
以下是使用 HttpClient#send_request_cgi
方法的示例:
res = send_request_cgi({'uri'=>'/index.php'})
res
的返回值是 Rex::Proto::Http::Response 对象, 但也有可能由于连接/响应超时而获得 NilClass
使用 Rex::Proto::Http::Response 对象, 你可以通过以下方式获取 HTTP body:
data = res.body
如果你想获取原始 HTTP 响应 (包括 code、headers、body 等) , 那么你可以简单地执行以下操作:
raw_res = res.to_s
但在本文档中, 我们只关注 res.body
格式 | 解析器 |
---|---|
HTML | Nokogiri |
XML | Nokogiri |
JSON | JSON |
如果你需要解析的格式不在列表中, 则回退到 res.body
.
当你有一个带有 HTML 的 Rex::Proto::Http::Response 时, 调用的方法是:
html = res.get_html_document
这将为你返回一个 Nokogiri::HTML::Document, 它允许你使用 Nokogiri API.
Nokogiri 中有两种常用的查找元素的方法: #at
和 #search
. 主要区别在于 #at
方法将只返回第一个结果, 而 #search
将返回所有找到的结果 (在一个数组中) .
以下示例作为你的 HTML 响应:
<html>
<head>
<title>Hello, World!</title>
</head>
<body>
<div class="greetings">
<div id="english">Hello</div>
<div id="spanish">Hola</div>
<div id="french">Bonjour</div>
</div>
</body>
<html>
简单使用 #at
如果 #at
方法用于查找 DIV 元素:
html = res.get_html_document
greeting = html.at('div')
那么 greeting
变量应该是一个 Nokogiri::XML::Element 对象, 它为我们提供了这个 HTML 块 (同样, 因为 #at
方法只返回第一个结果) :
<div class="greetings">
<div id="english">Hello</div>
<div id="spanish">Hola</div>
<div id="french">Bonjour</div>
</div>
从特定元素树中获取元素
html = res.get_html_document
greeting = html.at('div//div')
那么 greeting
变量应该给我们这个 HTML 块:
<div id="english">Hello</div>
抓取具有特定属性的元素
假设我不想要英文, 我想要西班牙文. 然后我们可以这样做:
html = res.get_html_document
greeting = html.at('div[@id="spanish"]')
抓取具有特定文本的元素
假设我只知道有一个 DIV 元素文本包含 "Bonjour", 我想获取它, 那么我可以这样做:
html = res.get_html_document
greeting = html.at('//div[contains(text(), "Bonjour")]')
或者假设我不知道 "Bonjour" 这个词在哪个元素中, 那么我可以对此有点模糊:
html = res.get_html_document
greeting = html.at('[text()*="Bonjour"]')
#search 基本使用
#search
方法返回一个元素数组. 假设我们要查找所有 DIV 元素, 那么方法如下:
html = res.get_html_document
divs = html.search('div')
提取 text
当你有一个元素时, 你总是可以调用 #text
方法来抓取文本. 例如:
html = res.get_html_document
greeting = html.at('[text()*="Bonjour"]')
print_status(greeting.text)
#text
方法也可以用作去除所有 HTML 标记的技巧
html = res.get_html_document
print_line(html.text)
以上将打印:
"\n\nHello, World!\n\n\n\nHello\nHola\nBonjour\n\n\n"
如果你确实想保留 HTML 标记, 则不要调用 #text
, 而是调用 #inner_html
.
访问属性值
获取元素, 只需调用 #attributes
.
遍历 DOM 树
使用 #next
方法移动到下一个元素.
使用 #previous
方法回滚到前一个元素.
使用 #parent
方法查找父元素.
使用 #children
方法获取所有子元素.
使用 #traverse
方法进行复杂的解析.
To get the XML body from Rex::Proto::Http::Response, do:
xml = res.get_xml_document
这与解析 HTML 非常相似.
在 Rex::Proto::Http::Response 获取 JSON 解析, 请执行以下操作:
json = res.get_json_document