【问题标题】:XPath Expression with Jsoup使用 Jsoup 的 XPath 表达式
【发布时间】:2014-09-05 03:38:47
【问题描述】:

在这个表达上需要帮助

"//tr[td[normalize-space(font) = '"+params[1]+"']]/td/font/text()"

我正在尝试从这个 HTML 文档中获取信息

<table width="575" border="0" cellspacing="1" cellpadding="0">
    <tr> 
      <td width="39" class="back1"><b class="texto4">CRN</b></td>
      <td width="60" class="back1"><b class="texto4">Materia</b></td>
      <td width="53" class="back1"><b class="texto4">Secci&oacute;n</b></td>
      <td width="55" class="back1"><b class="texto4">Cr&eacute;ditos</b></td>
      <td width="156" class="back1"><b class="texto4">T&iacute;tulo</b></td>
      <td width="69" class="back1"><b class="texto4">Cupo</b></td>
      <td width="57" class="back1"><b class="texto4">Inscritos</b></td>
      <td width="77" class="back1"><b class="texto4">Disponible</b></td>
    </tr>
    <tr> 
      <td width="39"><font class="texto4"> 
        10110                        </font></td>
      <td width="60"><font class="texto4"> 
        IIND1000                        </font></td>
      <td width="53"><font class="texto4"> 
      <div align="center">
        1                        </div></font></td>
      <td width="55"><font class="texto4"> 
        <div align="center">
        3                       </div>
        </font></td>
      <td width="156"><font class="texto4"> 
        INTROD. INGEN. INDUSTRIAL                        </font></td>
      <td width="69"><font class="texto4"> 
        100                        </font></td>
      <td width="57"><font class="texto4"> 
        100                        </font></td>
      <td width="77"><font class="texto4"> 
        0                        </font></td>
    </tr>
</table>

如果我查找 params1=10110,我想获取该 tr 标签中的每个 td 元素 (10110,IIND1000, 1, 3, INTROD.INGEN. INDUSTRIAL, 100, 100, 0)。

Jtidy 并没有真正做好这项工作 (it was having trouble with the spaces between font and div),所以我决定改用 Jsoup。有人会碰巧知道如何在一开始就转换那个 Xpath 表达式以便在 Jsoup 中使用它吗?

到目前为止,我已经设法得到这个表达式:font.texto4:contains(10110),它只得到“10110”。但是,我还没有找到一种方法来从同一级别的每个子节点获取文本。

EDTI:我是 Jsoup 的菜鸟,但我正在尝试更多的表达方式并检查结果。我发现如果我尝试这个表达式tr&gt;td:contains(10110) font.texto4,我会得到表中每个元素的文本。我只是想把它缩小到同一级别的 tr 节点集。

【问题讨论】:

    标签: java xpath html-parsing jsoup


    【解决方案1】:

    可以通过 xpath 和 jsoup 方式完成。考虑这个例子。

    import java.io.ByteArrayInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    
    import javax.xml.parsers.DocumentBuilder;
    import javax.xml.parsers.DocumentBuilderFactory;
    import javax.xml.parsers.ParserConfigurationException;
    import javax.xml.xpath.XPath;
    import javax.xml.xpath.XPathConstants;
    import javax.xml.xpath.XPathExpressionException;
    import javax.xml.xpath.XPathFactory;
    
    import org.jsoup.Jsoup;
    import org.jsoup.nodes.Element;
    import org.w3c.dom.Document;
    import org.w3c.dom.NodeList;
    import org.xml.sax.SAXException;
    
    
    public class SibilingParse {
    
        public static void main(String[] args) {
            try {
                    String html = "<table width='575' border='0' cellspacing='1' cellpadding='0'>"
                                    + "<tr>"
                                        + "<td width='39'><font class='texto4'>10110</font></td>"
                                        + "<td width='60'><font class='texto4'>IIND1000</font></td>"
                                        + "<td width='53'><font class='texto4'><div align='center'>1</div></font></td>"
                                        + "<td width='55'><font class='texto4'><div align='center'>3</div></font></td>"
                                        + "<td width='156'><font class='texto4'>INTROD. INGEN. INDUSTRIAL</font></td>"
                                        + "<td width='69'><font class='texto4'>100</font></td>"
                                        + "<td width='57'><font class='texto4'>100</font></td>"
                                        + "<td width='77'><font class='texto4'>0</font></td>"
                                    + "</tr>"
                                + "</table>";
    
                    //Xpath way
                    System.out.println("XPATH");
                    InputStream xmlStream = new ByteArrayInputStream(html.getBytes());
                    DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
                    DocumentBuilder builder = builderFactory.newDocumentBuilder();
                    Document xmlDocument = builder.parse(xmlStream);
                    XPath xPath =  XPathFactory.newInstance().newXPath();
    
                    String expression = "/table/tr/td//*[text()='10110']//../following-sibling::td";
                    NodeList nodeList = (NodeList) xPath.compile(expression).evaluate(xmlDocument, XPathConstants.NODESET);
                    for (int i = 0; i < nodeList.getLength(); i++) {
                        System.out.println(nodeList.item(i).getFirstChild().getTextContent()); 
                    }
                    System.out.println();
    
                    // Jsoup way
                    org.jsoup.nodes.Document doc = Jsoup.parse(html);
                    Elements tds = doc.select("td:contains(10110)");
                    if(tds != null && tds.size() > 0){
                        for(Element td : tds.first().siblingElements()){
                            System.out.println(td.text());
                        }
                    }
                } catch (ParserConfigurationException e) {
                    e.printStackTrace();
                } catch (SAXException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (XPathExpressionException e) {
                    e.printStackTrace();
                }
            }
    
    }
    

    基于网址

    import java.io.IOException;
    
    import org.jsoup.Jsoup;
    import org.jsoup.nodes.Document;
    import org.jsoup.nodes.Element;
    import org.jsoup.select.Elements;
    
    public class SiblingJsoup {
    
        public static void main(String[] args) {
            try {
                Document doc = Jsoup
                        .connect("http://registroapps.uniandes.edu.co/scripts/adm_con_horario1_joomla.php?depto=IIND")
                        .timeout(20000)
                        .get();
    
                Elements tds = doc.select("font:containsOwn(10110)");
                if (tds != null && tds.size() > 0) {
                    for (Element td : tds.parents().first().siblingElements()) {
                        System.out.println(td.text());
                    }
                }
                System.out.println("Done");
            } catch (IOException e) {
                e.printStackTrace();
            }
    
        }
    
    }
    

    【讨论】:

    • 好主意!但是,我在这一行得到了一个 NPE:doc.select("td:contains(10110)").first().siblingElements(),更具体地说是在 .siblingElements() 上。这次我直接从 URL 解析文档,而不是像您那样从 HTML 代码解析文档。这可能是问题吗? (URL 在我的浏览器中加载没有问题)
    • 那是因为没有 10110 的任何 td。所以first() 将是空的,我在空上调用兄弟元素。我应该做一些空值或长度检查。我只是把它作为一个例子.. :)
    • 更新了我的答案。现在应该没问题了.. :)
    • 完成。那是因为父母 td.当我们说td:contains 时,它也会搜索子 td。 containsOwn 有一种方法可以检查自己的文本。由于 td 没有那个 id 并且字体字段有我们需要在字体字段上执行 containscontainsOwn 。更新了我的答案。
    • 是的。即使在浏览器中,服务器也很慢。这就是我设置超时的原因
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多