0

今天早上,我决定做一个小项目,将 maverik 加油站的所有汽油价格解析成一个数组。我的大部分工作相当容易,我觉得我的代码中唯一“脏”的部分是将 html 实际解析为变量。我正在使用 indexOf 和子字符串来获取我想要的数据,我觉得必须有一种更清洁的方法来做到这一点?无论如何,这是我的代码,它可以编译并且工作得很好,只是不像我想要的那样干净。

maverik.java包含项目的主要方法和大部分代码。 maverikObj.java包含 getter 和 setter、构造函数和 toString 方法。

要更改从您获取控制台数据的加油站,只需更改 maverik.java 的第 90 行上的数组 println 中的数字。未来的修订版将具有根据用户请求控制显示哪些数据的方法。

这是一个带有价格的示例 HTML:

html4 = "<b>Maverik Store 4</b><br/>5200 Chinden Blvd<br>Boise, ID<br>208-376-0532<br><center><b></b></center><br /><font color=red>Fuel Prices -- Updated every 30 minutes</font><br /><div><div style=\"float: left; width: 70%; text-align:right;\">Adventure Club Card</div><div style=\"float: right; width: 30%; text-align:center;\">Retail</div><br /><div style=\"float: left;width: 30%;\">Unleaded:</div><div style=\"float: left; width: 30%; text-align:center;\"> 3.379</div><div style=\"float: right; width: 30%; text-align:center;\"> 3.399</div><br /><div style=\"float: left;width: 30%;\">Blend 89:</div><div style=\"float: left; width: 30%; text-align:center;\"> 3.469</div><div style=\"float: right; width: 30%; text-align:center;\"> 3.499</div><br /><div style=\"float: left;width: 30%;\">Blend 90:</div><div style=\"float: left; width: 30%; text-align:center;\"> 3.549</div><div style=\"float: right; width: 30%; text-align:center;\"> 3.579</div><br /><div style=\"float: left;width: 30%;\">Premium:</div><div style=\"float: left; width: 30%; text-align:center;\"> 3.599</div><div style=\"float: right; width: 30%; text-align:center;\"> 3.639</div><br /><div style=\"float: left;width: 30%;\">Diesel:</div><div style=\"float: left; width: 30%; text-align:center;\"> 4.039</div><div style=\"float: right; width: 30%; text-align:center;\"> 4.059</div>";

目前我正在解析地址、城市、州、电话号码以及每个站点可能的所有 8 种气体类型。(无铅、混合 87、88、89、99、优质、柴油)。但它变得有点棘手,因为一些 html 条目没有列出所有 8 个,大多数只有 8 种可能的燃料类型中的 4 或 5 种。因此,为了解析这些数据,我使用了两种方法。

地址、城市、州、电话号码使用以下方式解析:

if(line.contains(" = \"<b>Maverik Store")&&!line.contains("Coming Soon!")){ address=splitLine[3].substring(0,splitLine[3].length()-3).replace(" ", " "); city=splitLine[4].substring(0,splitLine[4].length()-7); state=splitLine[4].substring(splitLine[4].length()-5,splitLine[4].length()-3); phone=splitLine[5].substring(0,splitLine[5].length()-3);

使用 if else 语句解析燃料类型,使用 if 语句记录数据(如果存在),使用 else 语句记录 0.0 双精度值,因为我的构造函数要求所有燃料类型都有一些值。

if(line.indexOf("Unleaded:")>0){
    unleaded=Double.parseDouble(line.substring(line.indexOf("Unleaded:")+147, line.indexOf("Unleaded:")+152));
}
else{
    unleaded=0.0;
}

如您所见,我使用了很多子字符串和 indexOf 字符串方法来获取我想要的数据。我担心这是获取我想要的数据的一种极其静态的方法,因此我觉得这是一种非常肮脏的做事方式。任何关于如何清理我的代码的提示都非常感谢!=)

4

3 回答 3

4

好吧,起初,我使用了一种完全不同的编码风格,它更漂亮(根据我的看法)。但我会建议你寻找一些不同的编码风格并决定你最喜欢什么。

我在使用 XML 文件时也遇到过类似的问题,但结果却是一团糟。您可以做的最好的事情是编写自己的 XMLParser,并且由于 HTML 与 XML 结构没有区别,您也可以使用它来解析 HTML 文件。

由于这是一项非常艰巨的工作,我可以给你我的实现(如果你想要的话,告诉我,它当然是开源的)。它旨在让开发人员快速实现他想要的。使用示例:

XMLDocument document = new XMLDocument("yourXMLSourceCode");
XMLNode node = document.getNode("html.body.div");
String attribute = document.get("html.body.div?id");
String content = document.get("html.body.div.input");
XMLNode[] mynodes = document.getNode("html.body").getSubNodes("input");

您可以通过像这样搜索“SAX 解析器”或“XML 解析器”来找到其他解决方案。

我认为你可以使用它,用该代码做一些小技巧,你就可以完美地将它用于 HTML。

否则,我在处理 HTML 时所做的,您可以使用 HTMLParser。我对Jsoup有很好的经验。

于 2013-03-17T07:18:04.747 回答
1

不说太细,但是用正则表达式解析html(甚至xml)才是当今世界万恶之源。(好吧,有点夸张,但只是一点点。)

有许多实用程序试图尽最大努力处理我们现代 html 固有的混乱混乱。Java 的一个是“ jsoup ”。例如:

package foo;
import org.jsoup.*;
import org.jsoup.nodes.*;
import org.jsoup.select.*;

public class Bar {
  public static void main(String[] args) {
    //Document doc = Jsoup.connect(url).get();
    String html = "<html>...</html>";
    Document doc = Jsoup.parse(html);
    Elements divs = doc.select("div");
    for (Element e : divs) {
       System.out.println(e.text());
    }
  }
}

然后,即使给出了您的示例 html 片段(留给读者做很多练习):

$ java -cp jsoup-1.7.2.jar:.  foo.Bar

Adventure Club Card Retail Unleaded: 3.379 3.399 Blend 89: 3.469 3.499 Blend 90: 3.549 3.579 Premium: 3.599 3.639 Diesel: 4.039 4.059
Adventure Club Card
Retail
Unleaded:
3.379
3.399
Blend 89:
3.469
3.499
Blend 90:
3.549
3.579
Premium:
3.599
3.639
Diesel:
4.039
4.059
于 2013-03-17T09:41:58.527 回答
-1

您可以像这样使用正则表达式:

BufferedReader reader = new BufferedReader (
    new InputStreamReader (
        new URL ("https://www.maverik.com/locations/").
            openStream ()));

Pattern linePattern = Pattern.compile ("<b>Maverik Store ([^<]*)</b><br/>([^<]*)<br>([^<]*)<br>([^<]*)<br><center><b></b></center><br /><font color=red>Fuel Prices -- Updated every 30 minutes</font>");
Pattern pricePattern = Pattern.compile ("<div style=\\\\\"float: left;width: 30%;\\\\\">([^<]*)</div><div style=\\\\\"float: left; width: 30%; text-align:center;\\\\\">([^<]*)</div><div style=\\\\\"float: right; width: 30%; text-align:center;\\\\\">([^<]*)</div><br />");

String line;
while ((line = reader.readLine ()) != null)
{
    Matcher lineMatcher = linePattern.matcher (line);
    if (lineMatcher.find ())
    {
        System.out.println ("Store #: " + lineMatcher.group (1));
        System.out.println ("Store Address 1: " + lineMatcher.group (2));
        System.out.println ("Store Address 2: " + lineMatcher.group (3));
        System.out.println ("Store Phone: " + lineMatcher.group (4));

        Matcher priceMatcher = pricePattern.matcher (line);
        while (priceMatcher.find ())
        {
            System.out.println (priceMatcher.group (1) + priceMatcher.group (2) + priceMatcher.group (3));
        }
        System.out.println ();
    }
}

对我来说,它输出:

Store #: 4
Store Address 1: 5200 Chinden Blvd
Store Address 2: Boise, ID
Store Phone: 208-376-0532
Unleaded: 3.379 3.399
Blend 89: 3.469 3.499
Blend 90: 3.549 3.579
Premium: 3.599 3.639

Store #: 6
Store Address 1: 8561 West State
Store Address 2: Boise, ID
Store Phone: 208-853-1226
Unleaded: 3.379 3.399
Blend 88: 3.849 3.879
Blend 89: 3.469 3.499
Blend 90: 3.549 3.579

Store #: 7
Store Address 1: Highway   310  North
Store Address 2: Bridger, MT
Store Phone: 406-662-3356
Unleaded: 3.249 3.269
Blend 87: 3.499 3.529
Blend 89: 3.499 3.529
Premium: 3.489 3.529

Store #: 130
Store Address 1: 105  South  200  West
Store Address 2: Bountiful, UT
Store Phone: 801-292-6792
Unleaded: 3.269 3.289
Blend 87: 3.359 3.389
Blend 89: 3.439 3.469

Store #: 134
Store Address 1: 105  East Winnemucca
Store Address 2: Winnemucca, NV
Store Phone: 775-623-5948
Unleaded: 3.559 3.579
Blend 87: 3.649 3.679
Blend 89: 3.729 3.759

Store #: 135
Store Address 1: 1571  North  Main
Store Address 2: Sheridan, WY
Store Phone: 307-672-7010
Unleaded: 3.159 3.179

Store #: 136
Store Address 1: 222  South  Main
Store Address 2: Lyman, WY
Store Phone: 307-786-2705
Unleaded: 3.269 3.289
Blend 87: 3.359 3.389
Blend 89: 3.439 3.469
Premium: 3.489 3.529

Store #: 137
Store Address 1: 7th  & Main
Store Address 2: Snowflake, AZ
Store Phone: 928-536-7511
Unleaded: 3.539 3.559
Blend 89: 3.629 3.659
Blend 90: 3.709 3.739

...
于 2013-03-17T07:26:51.240 回答