【问题标题】:Extract table data with same class names提取具有相同类名的表数据
【发布时间】:2014-06-19 18:11:01
【问题描述】:

我正在尝试从网页中的表格中提取数据,但我一直在提取相同的信息。例如,我将每部电影都放在一个数组列表中,但我想将每部电影与相关的表数据进行匹配。问题是,每个表都有相同的类名。我可以打印每部电影的标题,但我只是在提取 MovieOne 的表格信息。以下是电影一和二的 HTML 示例:

    <TH CLASS="ddtitle">MovieOne</TH>
        <TABLE  CLASS="datadisplaytable" ><CAPTION class="captiontext">Movies</CAPTION>
    <TR>
    <TH CLASS="ddheader" scope="col" >Genre</TH>
    <TH CLASS="ddheader" scope="col" >Time</TH>
    <TH CLASS="ddheader" scope="col" >Days</TH>
    <TH CLASS="ddheader" scope="col" >Where</TH>
    <TH CLASS="ddheader" scope="col" >Date Range</TH>
    <TH CLASS="ddheader" scope="col" >Seating</TH>
    <TH CLASS="ddheader" scope="col" >Actors</TH>
    </TR>
    <TR>
    <TD CLASS="dddefault">Action</TD>
    <TD CLASS="dddefault">10:00 am - 12:00 pm</TD>
    <TD CLASS="dddefault">SMTWTHFSA</TD>
    <TD CLASS="dddefault">AMC Showplace</TD>
    <TD CLASS="dddefault">Aug 20, 2014 - Sept 12, 2014</TD>
    <TD CLASS="dddefault">Reservations</TD>
    <TD CLASS="dddefault">Will Ferrel (<ABBR title= "Primary">P</ABBR>)  target="Will Ferrel" ></TD>
    </TR>
    </TABLE>
<TH CLASS="ddtitle">MovieTwo</TH>
        <TABLE  CLASS="datadisplaytable" ><CAPTION class="captiontext">Movies</CAPTION>
    <TR>
    <TH CLASS="ddheader" scope="col" >Genre</TH>
    <TH CLASS="ddheader" scope="col" >Time</TH>
    <TH CLASS="ddheader" scope="col" >Days</TH>
    <TH CLASS="ddheader" scope="col" >Where</TH>
    <TH CLASS="ddheader" scope="col" >Date Range</TH>
    <TH CLASS="ddheader" scope="col" >Seating</TH>
    <TH CLASS="ddheader" scope="col" >Actors</TH>
    </TR>
    <TR>
    <TD CLASS="dddefault">Action</TD>
    <TD CLASS="dddefault">11:00 am - 12:30 pm</TD>
    <TD CLASS="dddefault">SMTWTHFSA</TD>
    <TD CLASS="dddefault">Showplace Cinemas</TD>
    <TD CLASS="dddefault">Aug 20, 2014 - Sept 12, 2014</TD>
    <TD CLASS="dddefault">TBA</TD>
    <TD CLASS="dddefault">Zach Galifinakis (<ABBR title= "Primary">P</ABBR>)  target="Zach Galifinakis" ></TD>
    </TR>
    </TABLE>

这是我一直在尝试的(由 Praveen 提供,来自我的另一个问题 Extract Text from BR tags):

 WebElement table =driver.findElement(By.xpath("//table[@class='datadisplaytable']"));
   WebElement tbody=table.findElement(By.tagName("tbody"));
   List<WebElement> rows=tbody.findElements(By.tagName("tr"));
   System.out.println("Row  size:"+rows.size());
   ArrayList<String> list=new ArrayList<>();

   for(int i=0;i<rows.size();i++)
   {
     WebElement column = tbody.findElement(By.xpath("//table[@class='datadisplaytable']/tbody/tr[2]/td"));
     if(column.getText().trim().contains("."))
     {
        System.out.println("text : "+column.getText().trim());
        list.add(column.getText().trim());
     }

   }

我还能够以字符串形式获取表格信息,但我需要将每个表格元素分开。我可以使用子字符串,但信息会有所不同,因此字符串长度也会有所不同。我应该使用 xpath 来提取信息,还是有其他方法?

【问题讨论】:

  • 这真的是真正的 HTML 吗?似乎无效。
  • 不,但它是它的一个例子。网页很大,如果我要发布整个内容,它会太长,为了缩短它,我必须以一种无论如何都无效的方式剪切和粘贴它。

标签: java selenium xpath


【解决方案1】:

我假设我正确理解了您的问题。您想从网页中的所有表格中读取电影的名称。

  1. 阅读所有表格
  2. 循环它们并在表格的每一行中,获取第二列(假设有电影名称)

我没有在我的机器上测试过这个。这是你可以尝试的代码。

List<WebElement> tables = driver.findElements(By.className("ddtitle"));

foreach(WebElement table : tables){

   List<WebElement> rows = table.findElements(By.tagName("TR"));

   foreach(WebElement row : rows){
       WebElement movieName = row.findElements(By.tagName("TD")).get(2); // column # in row
       System.out.println(movieName);
   }
}

【讨论】:

  • 嗨 Purus,感谢您抽出宝贵时间提供帮助。我已经尝试过您的代码,但我收到一条错误消息,提示“对于 List 类型,方法 findElements(By) 未定义。这发生在movieName = tables.findElements ...有什么想法吗?跨度>
  • 更新了代码..出现了一些问题..请重试。
  • 新错误:线程“main”中的异常 java.lang.ClassCastException:java.util.ArrayList 无法转换为 org.openqa.selenium.WebElement
  • ArrayList 是指哪个对象?
  • 我不确定我改变了什么,但错误不再发生。现在它继续运行,但没有拉起任何东西。我可以使用以下方法调出第一个表格单元格(操作): WebElement info = driver.findElement(By.xpath("//table[@class='datadisplaytable']//tbody//td//td[1 ]"));如果有某种方法我可以使用 xpath 来获取第二个表格的第一个单元格,我可以通过这种方式解决我的问题。有什么想法吗?
【解决方案2】:

您可以通过使用前面的&lt;TR&gt; 区分每个表来更改限制所选表的上下文的 XPath 表达式)。例如,这个表达式只会选择 second 表:

//table[@class='datadisplaytable'][preceding-sibling::th[1]='MovieTwo']/tbody/tr[2]/td

(假设电影片名不同)

表达式//table/preceding-sibling:th[1] 选择最近的&lt;th&gt; 元素。它的context 由所有具有class 属性datadisplaytable 的表组成。谓词进一步将该集合限制为仅具有前面的&lt;th&gt; 包含字符串值'MovieTwo' 的那些table 元素。

如果您知道几部电影的名称,您可以使用一个变量来代替电影名称,并单独遍历每个表,选择您希望处理的那些。

【讨论】:

  • 感谢您的回复。对我来说,这个解决方案是个问题,因为我要浏览多个电影网页,而且我不知道一个页面中有多少部电影。第一页可能有两部电影,但下一页可能有十部电影,后一页可能有四部电影,以此类推。我有将页面中的每个电影标题放入列表的代码,那么有没有办法让它通过电影列表索引搜索并获取每个标题的相关信息?
  • 这是选择一张表的一种方式。如果您可以找到其他不变的块、文本、id 等,您可以将其用作 anchor 来创建 context,则可以从中编写表达式 上下文到您要选择的节点。
  • 有趣...是否可以使用电影标题作为上下文,然后使用与我的数组中的标题匹配的循环列出表头文本,如果它们匹配则继续提取数据? xpath 会允许我这样做吗?只是想知道你是否知道。我会玩弄它,看看我能不能让它工作。再次感谢您的帮助。
  • 由于电影标题可用于锚定您的上下文(通过preceding-sibling:: 轴),因此您始终可以选择与其相对的表。您几乎可以选择任何您想要的东西。例如:选择表后的表、表号 2(使用位置谓词 [2])或前面的::table[2](上面的 2 个表)等等。
  • 我能够使用此代码:WebElement movieInfo = driver.findElement(By.xpath("//table[@class='datadisplaytable']//tbody//td//td[1 ]"));并检索动作。我将如何从这里选择下一张桌子?我已经尝试过 previous-sibling 和 previous::table[2] 甚至 [@class='datadisplaytable'][2] 还有其他建议吗?
【解决方案3】:

我能够通过使用获取第一个表信息

WebElement movieinfo = driver.findElement(By.xpath("//table[@class='datadisplaytable']/descendant::table["+tcounter+"]//td[1]"));

tcounter 是一个 int 值 = 1。

然后我更改了 td[1] 的值以获取其他单元格并增加 tcounter 的值以访问其他表。它不是很漂亮,但它有效。再次感谢您的帮助。

【讨论】:

    猜你喜欢
    • 2021-04-07
    • 1970-01-01
    • 2020-06-26
    • 1970-01-01
    • 2013-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多