我正在尝试使用jsoup解析HTML。这是我第一次使用jsoup,并且我也阅读了有关它的一些教程。以下是我要解析的HTML表-
[如果您看到我的下表,那么到目前为止,它具有三个tr
(为了便于理解,我将其缩短为具有三个表行,但总的来说会更多)。现在,我想从下表中提取Cluster Name
及其对应的host name
,例如-我将提取Titan
作为群集名称及其状态为关闭的所有主机名。
您可以在下面看到Titan
群集名称,我有两个主机名machineA.abc.com
和machineB.abc.com
,其中machineA
状态为up
,但machineB
状态为down
。
因此,我将打印Titan
作为群集名称,并打印machineB.abc.com
作为主机名称,因为它已关闭。使用jsoup可以做到吗?
<table border=1>
<tr>
<td> </td>
<td> </td>
<td>Alert</td>
<td>Cluster Name</td>
<td>IP addr</td>
<td>Host Name</td>
<td>Type</td>
<td>Status</td>
<td>Free</td>
<td>Version</td>
<td>Restart Time</td>
<td>UpTime(Days)</td>
<td>Last probed</td>
<td>Last up</td>
</tr>
<tr bgcolor="ffffff">
<td><a href=showlog?ip_addr=127.0.0.1>Hist</a></td>
<td><a href=http://127.0.0.1:8080/test?full=y>VI</a></td>
<td bgcolor="ffffff"> </td>
<td>Titan</td>
<td>10.100.111.77</td>
<td>machineA.abc.com</td>
<td></td>
<td bgcolor="ffffff">up</td>
<td bgcolor="ffffff" align=right>88%</td>
<td bgcolor="ffffff">2.0.5-SNAPSHOT</td>
<td bgcolor="ffffff">2014-07-04 01:49:08,220</td>
<td bgcolor="ffffff" align=right>381</td>
<td>07-14 20:01:59</td>
<td>07-14 20:01:59</td>
</tr>
<tr bgcolor="ffffff">
<td><a href=showlog?ip_addr=127.0.0.1>Hist</a></td>
<td><a href=http://127.0.0.1:8080/test?full=y>VI</a></td>
<td bgcolor="ffffff"> </td>
<td></td>
<td>10.200.192.99</td>
<td>machineB.abc.com</td>
<td></td>
<td bgcolor="ffffff">down</td>
<td bgcolor="ffffff" align=right>85%</td>
<td bgcolor="ffffff">2.0.5-SNAPSHOT</td>
<td bgcolor="ffffff">2014-07-04 01:52:20,613</td>
<td bgcolor="ffffff" align=right>103</td>
<td>07-14 20:01:59</td>
<td>07-14 20:01:59</td>
</tr>
</table>
到目前为止,我能够使用jsoup提取整个HTML表,但不确定如何提取群集名称和已关闭的主机名-
URL url = new URL("url_name");
Document doc = Jsoup.parse(url, 3000);
更新:-
我可能在表中有两个群集名称,如下所示-
<table border=1>
<tr>
<td> </td>
<td> </td>
<td>Alert</td>
<td>Cluster Name</td>
<td>IP addr</td>
<td>Host Name</td>
<td>Type</td>
<td>Status</td>
<td>Free</td>
<td>Version</td>
<td>Restart Time</td>
<td>UpTime(Days)</td>
<td>Last probed</td>
<td>Last up</td>
</tr>
<tr bgcolor="ffffff">
<td><a href=showlog?ip_addr=127.0.0.1>Hist</a></td>
<td><a href=http://127.0.0.1:8080/test?full=y>VI</a></td>
<td bgcolor="ffffff"> </td>
<td>Titan</td>
<td>10.100.111.77</td>
<td>machineA.abc.com</td>
<td></td>
<td bgcolor="ffffff">up</td>
<td bgcolor="ffffff" align=right>88%</td>
<td bgcolor="ffffff">2.0.5-SNAPSHOT</td>
<td bgcolor="ffffff">2014-07-04 01:49:08,220</td>
<td bgcolor="ffffff" align=right>381</td>
<td>07-14 20:01:59</td>
<td>07-14 20:01:59</td>
</tr>
<tr bgcolor="ffffff">
<td><a href=showlog?ip_addr=127.0.0.1>Hist</a></td>
<td><a href=http://127.0.0.1:8080/test?full=y>VI</a></td>
<td bgcolor="ffffff"> </td>
<td></td>
<td>10.200.192.99</td>
<td>machineB.abc.com</td>
<td></td>
<td bgcolor="ffffff">down</td>
<td bgcolor="ffffff" align=right>85%</td>
<td bgcolor="ffffff">2.0.5-SNAPSHOT</td>
<td bgcolor="ffffff">2014-07-04 01:52:20,613</td>
<td bgcolor="ffffff" align=right>103</td>
<td>07-14 20:01:59</td>
<td>07-14 20:01:59</td>
</tr>
<tr bgcolor="ffffff">
<td><a href=showlog?ip_addr=127.0.0.1>Hist</a></td>
<td><a href=http://127.0.0.1:8080/test?full=y>VI</a></td>
<td bgcolor="ffffff"> </td>
<td>Goldy</td>
<td>10.100.111.77</td>
<td>machineH.pqr.com</td>
<td></td>
<td bgcolor="ffffff">up</td>
<td bgcolor="ffffff" align=right>88%</td>
<td bgcolor="ffffff">2.0.5-SNAPSHOT</td>
<td bgcolor="ffffff">2014-07-04 01:49:08,220</td>
<td bgcolor="ffffff" align=right>381</td>
<td>07-14 20:01:59</td>
<td>07-14 20:01:59</td>
</tr>
</table>
现在,如果您在上面看到,我有两个群集名称-一个是Titan
,另一个是Goldy
,所以我想查找所有仅用于Titan
群集名称的计算机。
是的,使用JSoup是可能的。首先,选择表格。然后,为行选择<tr>
标签。您可以从第二个索引开始,因为第一行仅包含列名。然后循环遍历<th>
标签并获取特定的索引。在您的情况下,索引7和5很重要(索引7:状态,索引5:主机名)。检查状态是否等于down
,如果等于,则将主机名添加到列表中。仅此而已。
ArrayList<String> downServers = new ArrayList<>();
Element table = doc.select("table").get(0); //select the first table.
Elements rows = table.select("tr");
for (int i = 1; i < rows.size(); i++) { //first row is the col names so skip it.
Element row = rows.get(i);
Elements cols = row.select("td");
if (cols.get(7).text().equals("down")) {
downServers.add(cols.get(5).text());
}
}
更新:当您找到单词Titan
时,您可以创建另一个循环并查看集群名称是否为空。
编辑:我将while
循环更改为do while
循环。
ArrayList<String> downServers = new ArrayList<>();
Element table = doc.select("table").get(0); //select the first table.
Elements rows = table.select("tr");
for (int i = 1; i < rows.size(); i++) { //first row is the col names so skip it.
Element row = rows.get(i);
Elements cols = row.select("td");
if (cols.get(3).text().equals("Titan")) {
if (cols.get(7).text().equals("down"))
downServers.add(cols.get(5).text());
do {
if(i < rows.size() - 1)
i++;
row = rows.get(i);
cols = row.select("td");
if (cols.get(7).text().equals("down") && cols.get(3).text().equals("")) {
downServers.add(cols.get(5).text());
}
if(i == rows.size() - 1)
break;
}
while (cols.get(3).text().equals(""));
i--; //if there is two Titan names consecutively.
}
}
downServers ArrayList将包含停机服务器主机名的列表。
我要在您的情况下首先创建具有所有适当属性的计算机对象。然后使用Jsoup,我将提取数据并创建一个ArrayList,然后使用逻辑从Arraylist中获取数据。
我正在跳过对象的创建(因为这里不是问题,我将对象命名为Machine
然后使用Jsoup,我将获得像这样的行数据:
ArrayList<Machine> list = new ArrayList();
Document doc = Jsoup.parse(url, 3000);
for (Element table : doc.select("table")) { //this will work if your doc contains only one table element
for (Element row : table.select("tr")) {
Machine tmp = new Machine();
Elements tds = row.select("td");
tmp.setClusterName(tds.get(3).text());
tmp.setIp(tds.get(4).text());
tmp.setStatus(tds.get(7).text());
//.... and so on for the rest of attributes
list.add(tmp);
}
}
然后使用循环从列表中获取所需的值:
for(Machine x:list){
if(x.getStatus().equalsIgnoreCase("up")){
//machine with UP status found
System.out.println("The Machine with up status is:"+x.getHostName());
}
}
就这些。另请注意,此代码未经测试,可能会包含一些语法错误,因为它是直接在此编辑器上而不是在IDE中编写的。
下面是一个干净的泛型函数,用于将html表提取到简单的列表映射结构中。
以表格顺序将文档传递给此函数,以要求html页面中的第n个表格。
如果表使用rowspan或colspan,该函数将不会返回准确的数据。
public static List<Map<String,String>> parseTable(Document doc, int tableOrder) {
Element table = doc.select("table").get(tableOrder);
Elements rows = table.select("tr");
Elements first = rows.get(0).select("th,td");
List<String> headers = new ArrayList<String>();
for(Element header : first)
headers.add(header.text());
List<Map<String,String>> listMap = new ArrayList<Map<String,String>>();
for(int row=1;row<rows.size();row++) {
Elements colVals = rows.get(row).select("th,td");
//check column size here
int colCount = 0;
Map<String,String> tuple = new HashMap<String,String>();
for(Element colVal : colVals)
tuple.put(headers.get(colCount++), colVal.text());
System.out.println(tuple.toString());
listMap.add(tuple);
}
return listMap;
}