2

我正在尝试自动解析网站(例如http://www.delhaizedirect.be/nl/Search/Duvel并获取 VBA 列表中第一项的价格。因此,我得到了 HTML,效果很好 但是当我将 HTML 解析为 DOMDocument 并应用 XPath 查询时,我没有得到任何结果。

这是我正在使用的代码:

Public Function zoekDelhaizePrijs(Artikel As String)

Dim URL As String
URL = "http://www.delhaizedirect.be/nl/Search/" + Artikel

Dim website As Object
Set website = CreateObject("MSXML2.ServerXMLHTTP.6.0")

Call website.Open("GET", URL, False)
Call website.Send("")

Dim XPathQuery As String
XPathQuery = "/html/body/div[1]/div[3]/div[1]/div[1]/div[3]/ul/div[1]/div/div[2]/p[1]"

Dim dom As DOMDocument60
Set dom = New DOMDocument60
dom.async = False

dom.validateOnParse = False

'Debug.Print website.responseText

dom.LoadXML website.responseText
dom.setProperty "SelectionLanguage", "XPath"

Dim node As IXMLDOMNodeList
Set node = dom.SelectNodes(XPathQuery)

Dim title As IXMLDOMNode

For Each title In node
    Debug.Print title.Text
Next

End Function

有谁有想法吗?

在此先感谢,汤姆

4

2 回答 2

1

尽管页面顶部的 DOCTYPE 将其声明为“XHTML 1.0 Transitional”,但为“Duvel”查询返回的页面甚至不是格式良好的 XML。因此,它无法解析为 DOMDocument60 对象,因此不返回任何节点。即使您已设置validateOnParse=False,这也不会消除文档是格式良好的 XML 的要求。

您可以将来自网站的响应加载到字符串中,然后手动将其更正为格式正确的 XML,然后再将其加载到 DOMDocument60。这可能需要一些时间,因为您需要解决问题、运行您的函数,然后检查 的属性dom.parseError以找到下一个问题。

XHTML 文档的问题包括:

  • &未被&实体替换的字符 - 例如value="/nl/Search/Duvel?NB_REPLY=20&brand=Delhaize&page=1",而不是value="/nl/Search/Duvel?NB_REPLY=20&brand=Delhaize&page=1"
  • 没有值的属性 - 例如<option selected value="/nl/Search/Duvel?NB_REPLY=20&page=1">,而不是<option selected="selected" value="/nl/Search/Duvel?NB_REPLY=20&page=1">
  • 标签未关闭 - 例如<div><p></p><p></p><p><span><span></span></span></div>(缺少</p>

还有一些特定的 MSXML2 问题。在 DOMDocument60 中默认禁止 DTD,因此dom.setProperty "ProhibitDTD", False在尝试加载 XML 之前需要。

您的 XPath 查询也可能与 MSXML2 的默认命名空间问题发生冲突 - 请参见此处(该链接指的是 MXSML 4.0,但问题仍然存在于 MSXML 6.0 中)。由于页面具有默认命名空间xmlns="http://www.w3.org/1999/xhtml",您需要:

  • 声明与该命名空间对应的命名空间前缀dom.setProperty "SelectionNamespaces", "xmlns:r='http://www.w3.org/1999/xhtml'"
  • 在 XPath 查询中使用它XPathQuery = "/r:html/r:body/r:div[1]/r:div[3]/r:div[1]/r:div[1]/r:div[3]/r:ul/r:div[1]/r:div/r:div[2]/r:p[1]"

或者,您可以尝试将来自网站的响应加载到 HTMLDocument 中,并使用诸如getElementsByClassName定位所需数据之类的方法。在这种情况下,不需要文档是格式良好的 XML

这些是我需要进行的替换,以使 Duvel 页面正常工作。该站点上的其他页面可能需要一组不同的替换。我不会声称这类似于最佳实践,但它适用于这一特定页面。标准实体(加号&nbsp;)被临时重命名以允许&替换文档中的不正确字符。&nbsp;替换为等效的数字:

Dim webResponse As String
webResponse = website.responseText
webResponse = Replace(webResponse, "&nbsp;", "^nbsp;")
webResponse = Replace(webResponse, "&amp;", "^amp;")
webResponse = Replace(webResponse, "&lt;", "^lt;")
webResponse = Replace(webResponse, "&gt;", "^gt;")
webResponse = Replace(webResponse, "&quot;", "^quot;")
webResponse = Replace(webResponse, "&apos;", "^apos;")

webResponse = Replace(webResponse, "&", "&amp;")

webResponse = Replace(webResponse, "^nbsp;", "&#160;")
webResponse = Replace(webResponse, "^amp;", "&amp;")
webResponse = Replace(webResponse, "^lt;", "&lt;")
webResponse = Replace(webResponse, "^gt;", "&gt;")
webResponse = Replace(webResponse, "^quot;", "&quot;")
webResponse = Replace(webResponse, "^apos;", "&apos;")

webResponse = Replace(webResponse, "<option selected ", "<option selected=" & Chr$(34) & "selected" & Chr$(34) & " ")
webResponse = Replace(webResponse, " style=>", " style=" & Chr$(34) & Chr$(34) & ">")
webResponse = Replace(webResponse, "]]&gt;", "]]>")
webResponse = Replace(webResponse, "<span>prijs</span></span>", "<span>prijs</span></span></p>")
于 2013-04-02T01:57:54.153 回答
-1

这对我有用:

//div[@class="displayProdList"][1]//p[@class="prodListPrice"]
于 2013-04-01T15:34:16.247 回答