Java JSOUP解析表单字段和标签的表

Java JSOUP解析表单字段和标签的表,java,jsoup,Java,Jsoup,我试图使用JSOUP解析表中包含字段的表单,以获取字段及其标签。我遇到的问题是找不到标签的任何模式或公共属性。下面是一个HTML页面示例,标签标记为标签1、标签2等,字段标记为字段_1、字段_2等 <form id="some_form" method="post" action="some_page.do"> <div class="main_div"> <table id="main_table" class="table_class"&

我试图使用JSOUP解析表中包含字段的表单,以获取字段及其标签。我遇到的问题是找不到标签的任何模式或公共属性。下面是一个HTML页面示例,标签标记为标签1、标签2等,字段标记为字段_1、字段_2等

<form id="some_form" method="post" action="some_page.do">
    <div class="main_div">
        <table id="main_table" class="table_class">
            <tr>
                <td colspan="10" align="center" class="pad_bottom pad_top">
                    Label 1: 
                    <input type="text" name="field_1" value="Field 1 value" id="field_1"/>
                </td>
            </tr>
            <tr>
                <td colspan="10" align="center">
                    Label 2:
                    <span class="radio_class"><input type="radio" name="field_2" value="No" checked="checked" class="radio_field" id="field_2"/> No</span>
                    <span class="radio_class"><input type="radio" name="field_2" value="Yes" class="radio_field" id="field_2"/> Yes</span><br/>
                    <span class="extra">Some text to ignore</span>
                    More text to ignore
                 </td>
            </tr>
            <tr>
                <td colspan="10" align="center">
                    <table width="90%">
                        <tr>
                            <td class="td_class">
                                Some text to ignore
                            </td>
                            <td class="td_class">
                                Some text to ignore
                            </td>
                        </tr>
                        <tr>
                            <td align=3"left" class="another_td_class">                    
                                Label 3<br/>
                                More text for label 3
                            </td>                     
                            <td align="left" class="another_td_class">      
                                <input type="hidden" name="field_3_hidden" value="1" id="field_3"/>
                                <span class="radio_class"><input type="radio" name="field_3" value="1" id="field_3"/>1</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1<br/>
                                <span class="radio_class"><input type="radio" name="field_3" value="2" checked="checked" onfocus="" id="field_3"/> 2</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2<br/>
                               <br/>                          
                            </td>                      
                        <tr>
                        <tr>
                    </table>
                </td>
            </tr>
            <tr>
                <td class="heading" colspan="2" width="50%">Label 4</td>
                <td class="heading" width="50%">Label 5</td>
            </tr>
            <tr>
                <td align="center" class="td_class nowrap">
                    <input type="integer" name="field_4a" maxlength="2" size="2" value="42" class="integer_class" id="field_4"/>
                    Additional text for label 4
                    <br/>
                    <span class="span_class">Text to ignore</span>
                </td>
                <td class="td_class nowrap">
                    <input type="radio" name="field_4b" value="A" class="radio_class" id="field_4b"/>A<br/>
                    <input type="radio" name="field_4b" value="B" checked="checked" class="radio_class" id="field_4b"/>B
                    <br/>
                </td>
                <td align="center" class="td_class nowrap">
                    <input type="radio" name="field_5" value="C" checked="checked" class="radio_class" id="field_5"/>C
                    <input type="radio" name="field_5" value="D" class="radio_class" id="field_5"/>D
                    <br/>
                </td>
            </tr>
        </table>
    </div>
</form>

标签1:
标签2:
不
是
要忽略的一些文本 更多要忽略的文本 要忽略的一些文本 要忽略的一些文本 标签3
标签3的更多文本 11
2

标签4 标签5 标签4的附加文本
要忽略的文本 A
B
C D
最接近我的是下面的代码,但是标签经常在不同的地方,有时还有额外的文本,我仍然有问题

Set<MyElement> myElements = new HashSet<MyElement>();
Element mainDiv = page.select("div.main_div").first();
if (mainDiv != null) {
    Elements children = mainDiv.children();
    Elements tds = children.select("td");
    for (Element td : tds) {
        Elements inputs = td.select("input");
        for (Element input : inputs) {
            String field = input.id();
            if (field != null && !field.isEmpty()) {
                String label = td.text();
                MyElement myElement = new MyElement(field, label);
                myElements.add(myElement);
            }
        }
    }
}
Set myElements=new HashSet();
Element mainDiv=page.select(“div.main_div”).first();
如果(mainDiv!=null){
Elements children=mainDiv.children();
元素tds=子元素。选择(“td”);
用于(元件td:tds){
元素输入=td。选择(“输入”);
用于(元素输入:输入){
字符串字段=input.id();
if(field!=null&&!field.isEmpty()){
字符串标签=td.text();
MyElement MyElement=新的MyElement(字段、标签);
添加(myElement);
}
}
}
}

如果标签没有任何模式或公共属性,我想我想做的是不可能的,但这是我第一次使用JSOUP,所以我希望有一些我不知道的东西可以让我这样做。

我在这里看到一些模式。您说您想要获取字段及其标签。让我们换一种方式来思考这个问题。这是我看到的

  • 您关心的所有元素都是输入元素
  • 所有输入元素都有一个关联的标签
  • 标签名称是输入元素need属性的值
  • 某些输入元素具有相同的名称,这意味着它们与相同的标签相关联
  • 根据这些观察结果,您可以简单地解析所有输入字段和组,然后是我的名字(相同的名字,相同的组)。因为您知道所有输入元素的name属性的值都对应于它各自的标签,所以您甚至不需要查找标签


    你的问题是关于模式,而不是它背后的代码。如果你认为这个答案有效,试着编码它。如果您需要帮助编码,请告诉我。我有一个使用JSOUP的项目,我希望我们愿意编写一个PoC,只要您提供要解析的示例HTML(最好比您已经发布的更多)

    可能有一种方法。。。这看起来是理解这些标签的一个良好开端

    到目前为止,与字段中的标签匹配的粗略系统是:

  • 单元格前面的文本
  • 行上上一个
    单元格中的文本
  • 上面列中
    单元格中的文本
  • 要做到这一点,需要在
    中四处走动,找出每个单元格中的文本,并按(行、单元格)存储这些文本,然后从字段返回。其中有一个
    colspan
    值,该值显然计为多个单元格

    import java.io.IOException;
    import java.util.LinkedHashMap;
    import java.util.Map;
    
    import org.apache.commons.lang3.StringUtils;
    import org.jsoup.Jsoup;
    import org.jsoup.nodes.Document;
    import org.jsoup.nodes.Element;
    
    public class TableParser {
        private Map<Integer, Map<Integer, String>> cells = new LinkedHashMap<>();
    
        private void parseTable(Element table) {
            int rowNum = 0;
            for (Element row : table.select("> tbody > tr")) {
                parseRow(rowNum++, row);
            }
        }
    
        private void parseRow(int rowNum, Element row) {
            int columnNum = 0;
            for (Element cell : row.select("> td")) {
                String colspanText = cell.attr("colspan");
                int colspan = 1;
                if (StringUtils.isNotBlank(colspanText))
                    colspan = Integer.parseInt(colspanText);
    
                addCell(rowNum, columnNum, colspan, cell);
                parseCell(rowNum, columnNum, cell);
    
                columnNum += colspan;
            }
        }
    
        private void addCell(int rowNum, int columnNum, int colspan, Element cell) {
            Map<Integer, String> rowCells = cells.computeIfAbsent(rowNum,
                    r -> new LinkedHashMap<>());
            for (int i = 0; i < colspan; i++)
                rowCells.put(columnNum + i, labelIn(cell));
        }
    
        private String labelIn(Element cell) {
            return cell.textNodes().get(0).text().trim();
        }
    
        private String cellAt(int rowNum, int columnNum) {
            Map<Integer, String> rowCells = cells.get(rowNum);
            if (rowCells == null)
                return null;
            return rowCells.get(columnNum);
        }
    
        private void parseCell(int rowNum, int columnNum, Element cell) {
            // Don't drill down into the nested table yet
            if (!cell.select("table").isEmpty())
                return;
            for (Element input : cell.select("input")) {
                String label = labelIn(cell);
                if (StringUtils.isBlank(label))
                    label = cellAt(rowNum, columnNum - 1);
                if (StringUtils.isBlank(label))
                    label = cellAt(rowNum - 1, columnNum);
                System.out.println(String.format("%s->%s at (%d,%d)", label,
                        input.attr("name"), rowNum, columnNum));
            }
        }
    
        public static void main(String[] args) throws IOException {
            Document doc = Jsoup.parse(new java.io.File("/temp/labels.html"),
                    java.nio.charset.StandardCharsets.UTF_8.name());
            for (Element table : doc.select("table")) {
                new TableParser().parseTable(table);
            }
        }
    }
    

    1.是的,我关心的是输入2。正确的3。我试图采取这种方法,但遇到了问题。例如,输入ID可能是“status”,而相关标签可能是“What is the status?”因此它们不完全匹配。4.是的,这是正确的,我希望我可以给你从页面上的实际值,但html页面上的信息都是保密的,因此我无法发布实际的html页面或使用的实际值。如果你想用相同格式的lorem ipsum替换保密的htnl,我愿意提供帮助,但是你不能期望任何人在没有精确样本的情况下找到一个模式,事实上,我已经发布的是一个HTML的精确副本,只是更改了机密信息。因此,如果您用lorem lipsum替换标签1和字段_1,这将是唯一的区别。您可以发布基于示例HTML的预期输出吗?仅凭示例很难判断需要选择哪些内容。我更新了上面代码的Java部分,希望能有所帮助。我试图将字段和标签匹配在一起,并将它们放在自定义类中。我想以:[“field_1”、“Label 1”]、[“field_2”、“Label 2”]、[“field_3”、“Label 3”]、[“fie”结尾
    Label 1:->field_1 at (0,0)
    Label 2:->field_2 at (1,0)
    Label 2:->field_2 at (1,0)
    Label 4->field_4a at (4,0)
    Label 4->field_4b at (4,1)
    Label 4->field_4b at (4,1)
    Label 5->field_5 at (4,2)
    Label 5->field_5 at (4,2)
    Label 3->field_3_hidden at (1,1)
    Label 3->field_3 at (1,1)
    Label 3->field_3 at (1,1)