XQuery/頁面抓取和雅虎天氣
外觀
< XQuery
雅虎透過 REST API 提供全球天氣預報服務,提供 RSS。它在 API 文件 中進行了描述。
但是,每個英國城鎮供稿的關鍵是雅虎位置 ID,例如 UKXX0953,並且沒有可用的服務將位置名稱轉換為雅虎程式碼。雅虎確實提供了包含指向供稿本身連結的位置的字母索引頁面。
此任務可以透過 Paul Daniel 編寫的 雅虎管道 完成。(直至提取位置 ID)但是,HTML 標記的固有穩定性導致當前管道失敗。
此指令碼接收一個位置引數,提取位置的第一個字母,構建該字母的雅虎天氣索引頁面的 URL,字母 B 的索引頁面,並透過 eXist 中的 httpclient 模組獲取頁面。該頁面不是有效的 XHTML,但 httpclient:get 函式清理了 XML,使其格式良好。
可以在 樹形檢視 中看到頁面結構。
接下來,導航此 XML 以定位包含位置的 li 元素,並剝離該位置的程式碼。最後,將此程式碼附加到該位置 RSS 頁面 URL 的根,建立一個指向該位置 RSS 供稿的 URL。 RSS 供稿,然後指令碼重定向到該 URL。
declare variable $yahooIndex := "http://weather.yahoo.com/regional/UKXX";
declare variable $yahooWeather := "http://weather.yahooapis.com/forecastrss?u=c&p=";
let $location := request:get-parameter("location","Bristol")
let $letter := upper-case(substring($location,1,1))
let $suffix := if($letter eq 'A') then '' else concat('_',$letter)
let $index := xs:anyURI(concat ($yahooIndex,$suffix,".html"))
let $page := httpclient:get($index,true(),())
let $href := $page//div[@id="yw-regionalloc"]//li/a[.= $location]/@href
let $code := substring-after(substring-before($href,'.'),'forecast/')
let $rss := xs:anyURI(concat($yahooWeather,$code) )
return
response:redirect-to ($rss)
- 儘管索引頁面不是有效的 XHTML(為什麼?),並且需要整理,但雅虎透過在各節中使用 ID 對抓取程式提供了幫助。這允許 XPath 表示式透過 ID 選擇相關的部分,然後選擇包含位置的 li。但是,此類標記並不穩定,實際上最近從 browse 的 ID 更改為當前的 yw-regionalloc。還要注意,由於字母 A 的頁面與其他字母的頁面 URL 不同,因此需要額外的操作 - 這是一項不容易看到或測試的功能。
- eXist 不太適合此任務,因為頁面必須首先儲存在資料庫中,以便使用結構索引執行 XPath 表示式。像 Saxon 這樣的記憶體中 XQuery 引擎預計在此任務中會執行得更好。目前,效能有點慢,但新的 1.3 版本改進了這種情況。
- 使用正則表示式從字串中提取程式碼會更清晰,但是 XQuery 不提供簡單的匹配函式來提取匹配的模式。在 analyse-string 中描述了包裝一些 XSLT 來執行此操作的 XQuery 函式。
- 該指令碼使用 eXist 函式 response:redirect-to 將瀏覽器重定向到為 RSS 供稿構建的 URL。
為了比較,這是使用 analyse-string 的等效 XSLT 指令碼。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:param name="location"/>
<xsl:variable name="html2xml">
<xsl:text>http://www.html2xml.nl/Services/html2xml/version1/Html2Xml.asmx/Url2XmlNode?urlAddress=</xsl:text>
</xsl:variable>
<xsl:variable name="yahooIndex">
<xsl:text>http://weather.yahoo.com/regional/UKXX_</xsl:text>
</xsl:variable>
<xsl:variable name="yahooWeather">
<xsl:text>http://weather.yahooapis.com/forecastrss?u=c&p=</xsl:text>
</xsl:variable>
<xsl:template match="/">
<xsl:variable name="letter" select="upper-case(substring($location,1,1))"/>
<xsl:variable name="suffix" select="if($letter eq 'A') then '' else concat('_',$letter)"></xsl:variable>
<xsl:variable name="page" select="doc(concat ($html2xml,$yahooIndex,$suffix,'.html'))"/>
<xsl:variable name="href" select="$page//div[@id='yw-regionalloc']//li/a[.= $location]/@href"/>
<xsl:variable name="code" >
<xsl:analyze-string select="$href" regex="forecast(.*)\.html">
<xsl:matching-substring>
<xsl:value-of select="regex-group(1)"/>
</xsl:matching-substring>
</xsl:analyze-string>
</xsl:variable>
<xsl:variable name="rssurl" select="concat($yahooWeather,$code)"/>
<xsl:copy-of select="doc($rssurl)"/>
</xsl:template>
</xsl:stylesheet>
布里斯托爾天氣 - 但目前已損壞。
另一種方法是使用 Erik Bruchez 和 Alessandro Vernet 在 Orbeon 開發的 XPL 來描述一系列轉換作為管道。這裡,管道擴充套件為從 RSS 供稿建立自定義 HTML 頁面。
<?xml version="1.0" encoding="UTF-8"?>
<p:pipeline xmlns:p="http://www.cems.uwe.ac.uk/xpl" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<p:output id="weatherPage"/>
<p:processor name="xslt">
<p:annotation>construct the index page url from the parameter</p:annotation>
<p:input name="parameter" id="location"/>
<p:input name="xml">
<dummy/>
</p:input>
<p:input name="xslt">
<xsl:template match="/">
<xsl:text>http://weather.yahoo.com/regional/UKXX_</xsl:text>
<xsl:value-of select="upper-case(substring($location,1,1))"/>
<xsl:text>.html</xsl:text>
</xsl:template>
</p:input>
<p:output name="result" id="indexUrl"/>
</p:processor>
<p:processor name="tidy">
<p:annotation>tidy the index page</p:annotation>
<p:input name="url" id="indexUrl"/>
<p:output name="xhtml" id="indexXhtml"/>
</p:processor>
<p:processor name="xslt">
<p:annotation>parse the index page and construct the URL for the RSS feed</p:annotation>
<p:input name="xml" id="indexXhtml"/>
<p:input name="parameter" id="location"/>
<p:input name="xslt">
<xsl:template match="/">
<xsl:variable name="href" select="//div[@id='yw-regionalloc']//li/a[.= $location]/@href"/>
<xsl:text>http://weather.yahooapis.com/forecastrss?u=c%26p=</xsl:text>
<xsl:value-of select="substring-before(substring-after($href,'forecast/'),'.html')"
/>
</xsl:template>
</p:input>
<p:output name="result" id="rssUrl"/>
</p:processor>
<p:processor name="fetch">
<p:annotation>fetch the RSS feed</p:annotation>
<p:input name="url" id="rssUrl"/>
<p:output name="result" id="RSSFeed"/>
</p:processor>
<p:processor name="xslt">
<p:annotation>Convert RSS to an HTML page</p:annotation>
<p:input name="xml" id="RSSFeed"/>
<p:input name="xslt" href="http://www.cems.uwe.ac.uk/xmlwiki/weather/yahooRSS2HTML.xsl"/>
<p:output name="result" id="weatherPage"/>
</p:processor>
</p:pipeline>
給定每個命名處理器型別的實現,這可以 執行(儘管在此原型 XQuery 處理器中速度相當慢)。
- 這正在進行中 - 目前,此 XPL 引擎只是一個非常簡單的部分原型,即使這個簡單的順序示例也不符合 XPL 模式(因此是本地名稱空間)。
可以使用 GraphViz 視覺化 管道。
- 目的是生成一個額外的影像地圖,以支援連結到基礎程序,以及支援完整的 XPL 語言。