【问题标题】:Issue parsing html using powershell and xpath使用 powershell 和 xpath 解析 html 的问题
【发布时间】:2013-12-18 13:15:41
【问题描述】:

这是我上周提出的posted here 的后续问题。我已经解决了最初的问题,但现在我遇到了一个稍微不同的问题。

如果没有使用 GetAttributeValue 方法嵌套 html 标签,我现在可以获取我感兴趣的项目的属性,这里是 data-pid 但我现在在获取嵌套标签中的项目属性时遇到问题,在我的代码 sn-p 中它是日期。我在这里使用 xpath 和 HtmlAgility 包来解析 html,但在下面的示例中,相同的日期被一遍又一遍地返回。

$item 对象如下所示:

Attributes           : {class, data-pid}
ChildNodes           : {#text, a, #text, span...}
Closed               : True
ClosingAttributes    : {}
FirstChild           : HtmlAgilityPack.HtmlTextNode
HasAttributes        : True
HasChildNodes        : True
HasClosingAttributes : False
Id                   : 
InnerHtml            :  <a href="/mod/4175126893.html" class="i"><span class="price">$20</span></a> <span class="star"></span> <span class="pl"> <span class="date">Nov 
                       30</span>  <a href="/mod/4175126893.html">Unlock Any GSM Cell Phone Today!</a> </span> <span class="l2"> <span class="price">$20</span>  <span 
                       class="pnr"> <small> (Des Moines)</small> <span class="px"> <span class="p"> </span></span> </span>  <a class="gc" href="/mod/" 
                       data-cat="mod">cell phones - by dealer</a> </span> 
InnerText            :  $20   Nov 30  Unlock Any GSM Cell Phone Today!   $20    (Des Moines)      cell phones - by dealer  
LastChild            : HtmlAgilityPack.HtmlTextNode
Line                 : 305
LinePosition         : 5408
Name                 : p
NextSibling          : HtmlAgilityPack.HtmlTextNode
NodeType             : Element
OriginalName         : p
OuterHtml            : <p class="row" data-pid="4175126893"> <a href="/mod/4175126893.html" class="i"><span class="price">$20</span></a> <span class="star"></span> 
                       <span class="pl"> <span class="date">Nov 30</span>  <a href="/mod/4175126893.html">Unlock Any GSM Cell Phone Today!</a> </span> <span class="l2"> 
                       <span class="price">$20</span>  <span class="pnr"> <small> (Des Moines)</small> <span class="px"> <span class="p"> </span></span> </span>  <a 
                       class="gc" href="/mod/" data-cat="mod">cell phones - by dealer</a> </span> </p>
OwnerDocument        : HtmlAgilityPack.HtmlDocument
ParentNode           : HtmlAgilityPack.HtmlNode
PreviousSibling      : HtmlAgilityPack.HtmlTextNode
StreamPosition       : 18733
XPath                : /html[1]/body[1]/article[1]/section[1]/div[1]/div[2]/p[11]

Attributes           : {class, data-pid}
ChildNodes           : {#text, a, #text, span...}
Closed               : True
ClosingAttributes    : {}

我想从 outerhtml 值中提取数据。

OuterHtml            : <p class="row" data-latitude="41.5937565437255" data-longitude="-93.6437636649079" data-pid="4184719674"> <a href="/mod/4184719674.html" class="i"></a> 
               <span class="star"></span> <span class="pl"> <span class="date">Nov 27</span>  <a href="/mod/4184719674.html">iPhone and other Cell Phone Unlocks</a> 
               </span> <span class="l2">   <span class="pnr"> <small> (Des Moines)</small> <span class="px"> <span class="p"> <a href="#" class="maptag" 
               data-pid="4184719674">map</a></span></span> </span>  <a class="gc" href="/mod/" data-cat="mod">cell phones - by dealer</a> </span> </p>

我可以抓取 data-pid 没问题。这是当前代码的样子:

ForEach ($item in $results) {

    # This is working
    $ID = $item.GetAttributeValue("data-pid", "")

    # This is looping over the same item
    $Date = $item.SelectSingleNode("//span[@class='date']").InnerText
}

我想要做的是能够使用我的 xpath 语句从包含在 externalhtml 对象中的不同标签中获取属性,但我不知道该怎么做。这是解决问题的最佳方法还是我应该使用一些正则表达式来获得我想要的值?

让我知道我需要发布的其他详细信息。

【问题讨论】:

  • > 对 craigslist 或发布在 craigslist 上的任何内容的任何复制、聚合、展示、分发、执行或衍生使用,无论是直接完成还是通过中介(包括但不限于通过蜘蛛、机器人、爬虫) 、刮板、框架、iframe 或 RSS 提要)是被禁止的。 (Source)

标签: html powershell xpath html-parsing html-agility-pack


【解决方案1】:

我没有使用 HTML Agility Pack,但 AFAICS 内置工具应该足够了:

$url = 'http://www.example.com/path/to/some.html'

$html = (Invoke-Webrequest $url).ParsedHTML

$html.getElementsByTagName('p') | ? { $_.className -eq 'row' } | % {
  $ID   = $_.getAttributeNode('data-pid').value
  $Date = $_.getElementsByTagName('span') | ? { $_.className -eq 'date' } |
          % { $_.innerText }

  # do stuff with $ID and $Date
  "{0}: {1}" -f $ID, $Date
}

请注意,Invoke-Webrequest 需要 PowerShell v3。如果您仅限于 PowerShell v2,请使用 Internet Explorer COM 对象:

$ie = New-Object -COM InternetExplorer.Application
$ie.Navigate($url)
while ($ie.ReadyState -ne 4) { sleep 100 }
$html = $ie.Document

如果您的 HTML 文件是本地文件,请将 Invoke-Webrequest 行替换为以下内容:

$htmlfile = 'C:\path\to\some.html'

$html = New-Object -COM HTMLFile
$html.write((Get-Content $htmlfile | Out-String))

【讨论】:

  • 到目前为止,这对我有用,但它需要很长时间才能运行。你知道什么会导致它需要这么长时间吗?
  • 在不知道实际输入数据的情况下运行它?几乎没有。
【解决方案2】:

我来得太晚了,但这是你的错误。您一直在使用绝对路径。

ForEach ($item in $results) {

    # This is working
    $ID = $item.GetAttributeValue("data-pid", "")

    # This is looping over the same item
    $Date = $item.SelectSingleNode("//span[@class='date']").InnerText

    # This is looping over the different items (i.e. this is what what you want)
    $Date = $item.SelectSingleNode(".//span[@class='date']").InnerText
}

【讨论】:

    猜你喜欢
    • 2012-07-19
    • 2012-08-23
    • 2011-06-03
    • 1970-01-01
    • 2014-07-13
    • 1970-01-01
    • 1970-01-01
    • 2014-07-06
    • 1970-01-01
    相关资源
    最近更新 更多