【问题标题】:extracting data using XPathSApply conditioning on more than one attribute在多个属性上使用 XPathSApply 条件提取数据
【发布时间】:2015-01-17 15:15:18
【问题描述】:

以下网址包含数字和表格,我喜欢阅读表格的前两列。 xpatahSApply 命令工作正常,但我需要以两个以上的属性为条件,我无法弄清楚。

url ="http://floodobservatory.colorado.edu/SiteDisplays/1544data.htm"

doc=htmlTreeParse(url,useInternal=TRUE)

解析数据样本

<tr height="20" style="height:15.0pt">
<td height="20" class="xl6521398" align="right" style="height:15.0pt">11-Oct-13</td>
  <td class="xl7321398">1853</td>
  <td class="xl7321398"></td>
  <td class="xl8121398">0.80</td>
  <td class="xl7221398" align="right">4.87</td>
  <td class="xl1521398"></td>
  <td class="xl1521398"></td>
  <td class="xl1521398"></td>
  <td class="xl1521398"></td>
  <td class="xl1521398"></td>
  <td class="xl1521398"></td>
  <td class="xl7421398"></td>
  <td class="xl7421398"></td>
  <td class="xl7421398"></td>
  <td class="xl7421398"></td>
  <td class="xl9621398"></td>
  <td class="xl7421398"></td>
  <td class="xl8121398"></td>
 </tr>

我需要从两个单元格中读取值,其中一个对应于 date,另一个对应于 streamflow 排放,并具有以下提到的属性

<td height="20" class="xl6521398" ...> and  [<td class="xl7321398"..]

关于上面的示例数据,我需要抓取“11-Oct-13”和“1853”。

我使用以下命令获取“日期”和“流量排放”。

dates=xpathSApply(doc,"//td[@class='xl6521398']",xmlValue)

streamflowdischarge=xpathSApply(doc,"//td[@class='xl7321398']",xmlValue)

他们成功提取信息,但提取的值包含来自其他表/单元格的值,重要的是“日期”和“流量排放”不对应。

日期[1:10] [1] "1-Jan-98" "2-Jan-98" "3-Jan-98" "31-Mar-98" "4-Jan-98" "30-Apr-98" "5-Jan- 98" [8]“98 年 5 月 31 日”“98 年 1 月 6 日”“98 年 6 月 30 日”

“31-Mar-98”介于“3-Jan-98”和“4-Jan-98”之间——有些意外

溪流排放[1:10] [1] “3108” “3076” “3051” “3111” “3064” “3043” “3007” “3066” “378” “”

“3108”不对应于“1-Jan-98” - 可以在 url 上查看

看起来有些表格/单元格具有相同的属性,我不想读取/抓取。在这方面,我认为我需要传递整个属性,即,

<td height="20" class="xl6521398" align="right" style="height:15.0pt">

为了获取“日期”,我应该以某种方式设置条件,以便从同一个表中提取“流量排放”。

非常感谢您的建议,以及是否有其他可用选项。

我尝试了 readHTMLTable,但收到错误“下标越界”

谢谢, 萨蒂什

【问题讨论】:

    标签: r xml-parsing html-parsing


    【解决方案1】:

    我输入数据

    url = "http://floodobservatory.colorado.edu/SiteDisplays/1544data.htm"
    html = htmlParse(url)
    

    然后查询包含您感兴趣的两个单元格类的表格行,获取每个单元格的第一个或第二个单元格

    query = "//tr[./td[@class='xl6521398'] and ./td[@class='xl7321398']]/td[1]"
    dates = xpathSApply(html, query, xmlValue)
    query = "//tr[./td[@class='xl6521398'] and ./td[@class='xl7321398']]/td[2]"
    flows = xpathSApply(html, query, xmlValue)
    

    这些是我认为你想要的

    > df = data.frame(dates=as.Date(dates, "%e-%b-%y"), flows=as.integer(flows))
    > nrow(df)
    [1] 5808
    > head(df, 3)
         dates flows
    1 1-Jan-98  1258
    2 2-Jan-98  1584
    3 3-Jan-98  1272
    > tail(df, 3)
             dates flows
    5806 23-Nov-13  2878
    5807 24-Nov-13  2852
    5808 25-Nov-13  2738
    

    我猜秘诀是使用感兴趣的两列选择行(??但也许这些是用于制作网页的电子表格生成的类,与数据?)对数据进行分组。更“完整”的抓取可能会创建行的节点集,然后查询标有感兴趣类的行(有时是几个)列,例如,

    query = "//tr[./td[@class='xl6521398'] and ./td[@class='xl7321398']]"
    nodes = getNodeSet(html, query)
    date = lapply(nodes, xpathSApply, "./td[@class='xl6521398']", xmlValue)
    flow = lapply(nodes, xpathSApply, "./td[@class='xl7321398']", xmlValue)
    

    日期和流量元素是协调的,但每个日期可以有多个流量测量值。

    > head(flow, 3)
    [[1]]
    [1] "1258" ""     "1799" "2621" "1258"
    
    [[2]]
    [1] "1584" ""     "1550" "2033" "978" 
    
    [[3]]
    [1] "1272" ""     "1104" "3515" "233" 
    
    > table(sapply(flow, length))
    
       2    3    5 
    5577   15  216 
    

    所以我猜这是苏丹的青尼罗河;整洁

    url = "http://floodobservatory.colorado.edu/SiteDisplays/Summary5.htm"
    sites = htmlParse(url)
    
    > sites["//tr[./td[1] = '1544']"]
    [[1]]
    <tr height="17" style="height:12.75pt"><td height="17" class="xl7226158" style="height:12.75pt">1544</td>&#13;
      <td class="xl6926158"/>&#13;
      <td class="xl7026158">13.0940</td>&#13;
      <td class="xl7026158">33.9750</td>&#13;
      <td class="xl6926158">5070</td>&#13;
      <td class="xl6926158">Blue Nile</td>&#13;
      <td class="xl6926158">Sudan</td>&#13;
      <td class="xl6926158">2</td>&#13;
      <td class="xl6926158">2</td>&#13;
      <td class="xl7926158">173%</td>&#13;
      <td class="xl8226158">15.88</td>&#13;
      <td class="xl7126158">19-Nov-14</td>&#13;
      <td class="xl7126158"/>&#13;
     </tr> 
    
    attr(,"class")
    [1] "XMLNodeSet"
    

    【讨论】:

    • 非常详细的解决方案,对我帮助很大。我也猜想该网页可能是使用 excel 表创建的。知道为什么一行的多个表格单元格具有相同的类值吗?另一个问题是:这种数据集生成行和单元格的表格,但内容不会保存为子节点?与Summary5.htm 相关的其他代码也很有用。海量信息
    • @SatishR 我不知道电子表格如何确定类值。我不确定您所说的“内容不会被保存为子节点”是什么意思,抱歉。
    【解决方案2】:

    您可以在 xpath 中使用 and| 运算符:

    path_xp <-  '//td[@class="xl6521398" and  @height="20"]|//td[@class="xl7321398"]'
    
    res <- xpathSApply(doc,path_xp,xmlValue)
    [1] "11-Oct-13" "1853"      "" 
    

    请注意,这里有 3 个元素,因为您有 2 个属性类等于 xl7321398 的元素。也许您应该更精确地提出您的要求,或者您可以移动第三个空元素。

    res[nzchar(res)]
    [1] "11-Oct-13" "1853" 
    

    【讨论】:

    • 解决方案非常有用,但是并没有产生我想要的。上述命令仅在流放电时提取单元格(并且缺少日期)。认为这可能是由于“|”,我尝试用“和”替换它,但它都没有为我提供结果。数据有点没有组织,而是“日期”之后的“2”个元素我经常得到“5”个元素。
    猜你喜欢
    • 2023-02-25
    • 1970-01-01
    • 1970-01-01
    • 2014-10-16
    • 2015-09-22
    • 2022-09-23
    • 2017-04-09
    • 2016-05-08
    • 1970-01-01
    相关资源
    最近更新 更多