Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Css Nokogiri返回空数组_Css_Ruby_Xpath_Nokogiri_Open Uri - Fatal编程技术网

Css Nokogiri返回空数组

Css Nokogiri返回空数组,css,ruby,xpath,nokogiri,open-uri,Css,Ruby,Xpath,Nokogiri,Open Uri,我在擦屏幕 我尝试使用CSS和XPath来获取网站中表格的降水预测部分 它们都不在我的程序中工作,因为它们返回空数组,但是,它们都在Chrome开发工具中工作(Inspect element->console->$$用于CSS,x用于Xpath) 为什么会这样?它与名称空间有关吗 require 'open-uri' require 'nokogiri' foo = Nokogiri::HTML(open("http://www.weather.com/weather/hourbyhour/l/

我在擦屏幕

我尝试使用CSS和XPath来获取网站中表格的降水预测部分

它们都不在我的程序中工作,因为它们返回空数组,但是,它们都在Chrome开发工具中工作(Inspect element->console->$$用于CSS,x用于Xpath)

为什么会这样?它与名称空间有关吗

require 'open-uri'
require 'nokogiri'
foo = Nokogiri::HTML(open("http://www.weather.com/weather/hourbyhour/l/INXX0202:1:IN"))
foo.remove_namespaces!
p foo.xpath("//section[@data-ng-class]/p[@class='precip weather-cell ng-isolate-scope']/span[@data-ng-if]") # returns []
p foo.css("section[data-ng-class] p[class='precip weather-cell ng-isolate-scope'] span[data-ng-if]")  # returns []
这里是我试图从中获取数据的地方。我想要的是标题“Precip”下的数字(如图中的85100100,95,80,70,45,40)

我将页面的HTML复制到一个本地HTML文件中,并让我的程序访问该文件。然后程序给了我所需的输出,但当我让同一程序使用OpenUri访问网站时,它返回一个空数组:

require 'open-uri'
require 'nokogiri'
foo = open("http://www.weather.com/weather/hourbyhour/l/INXX0202:1:IN")
nokogirifoo = Nokogiri::HTML(foo)
p nokogirifoo.xpath("//section[@data-ng-class]/p[@class='precip weather-cell ng-isolate-scope']/span[@data-ng-if]") # => empty array

bar = File.open('weather.html') # weather.html is just the html code of the page copied into a local file
nokogiribar = Nokogiri::HTML(bar)
p nokogiribar.xpath("//section[@data-ng-class]/p[@class='precip weather-cell ng-isolate-scope']/span[@data-ng-if]").text # => "85%100%100%95%80%70%45%40%" (this is what I need)
以下是HTML的一个片段(显示的部分嵌套在网站的多个标记中):


上午9:30
11月20日,星期五

28°C

Feels34°

雷暴

85%

85%

ESE 9公里/小时


问题在于,您正在使用浏览器查看页面,该页面除了实现HTML解析器外,还具有嵌入式JavaScript解释器。浏览器在为用户呈现页面之前查找并处理任何JavaScript
标记,加载和调整元素。这就是你想要的页面中发生的事情。像Nokogiri这样的解析器不是浏览器,也不关心嵌入的脚本,因为在HTML中,脚本只是特定标记中的文本,因此,您想要的第二个HTML永远不会被检索到

你说你把HTML保存到了一个文件中,但是你没有说你是如何保存的。我猜,因为保存的HTML包含您想要的信息,所以它是使用浏览器保存的

在处理web页面时,第一步是确定页面是使用动态HTML和/或JavaScript还是静态HTML。关闭浏览器中的JavaScript,然后加载URL。或者,您可以从命令行中使用
wget
curl
检索页面并使用编辑器查看。在这两种情况下,您是否看到了所需的内容?如果是这样的话,那么很有可能在检索到Nokogiri这样的解析器后就可以使用它了。如果没有,那么您必须使用能够解释JavaScript、处理加载的信息,然后将其传递给解析器的东西

PhantomJS和Watir等工具可以帮助您,或者相反,可以找到一个天气服务,它允许您使用API检索数据,而无需进行刮取,因为刮取总是非常脆弱的

还可以找出JavaScript用于检索数据的URL,然后请求辅助资源并对其进行解析。它可能是HTML,也可能是JSON,其中包含JavaScript处理的数据,然后动态构建整个表

关于堆栈溢出,有许多问题和答案正在讨论如何实现上述所有功能

总之,一旦你得到了你想要的HTML,你可以很容易地减少那些值所需的CSS选择器。每个值都包装在一个具有类的
标记中,因此使用该类查找值

require 'nokogiri'
doc = Nokogiri::HTML(<<EOT)

    <section class="wxcard-hourly summary-view ng-isolate-scope last" data-ng-class="{'last': $last}" data-wxcard-hourly="hour" data-wxcard-hourly-methods="hourlyScope" data-hours-index="hoursDataIndex" data-show-wx-labels="false" data-details-view="false">
        <div class="heading weather-cell" data-ng-switch="dataMethods.checkTime(data.getForecastLocalDate())">
            <h2>

          <span class="wx-dsxdate ng-binding ng-scope" ng-bind-template=" 9:30 am" data-dsxdate="" data-ng-switch-when="min" data-datetime="data.getForecastLocalDate()" data-timezone="locTz" data-format="'h:mm a'"> 9:30 am</span>
            </h2>
        <span class="sub-heading wx-hourly-date wx-dsxdate ng-binding ng-scope" ng-bind-template=" Fri, Nov 20" data-dsxdate="" data-datetime="data.getForecastLocalDate()" data-timezone="locTz" data-format="'EEE, MMM d'"> Fri, Nov 20</span>
        </div>
        <p class="hi-temp temp-1 weather-cell ng-isolate-scope" data-wx-temperature="data.getTemp()" data-show-temp-unit="hoursIndex === 0"> <span data-ng-if="hasValue()" data-ng-bind="temp" class="ng-binding ng-scope">28</span><sup data-ng-if="hasValue()" class="deg ng-scope">°</sup><sup class="temp-unit ng-binding ng-scope" data-ng-if="showTempUnit" data-ng-bind="tempUnit()">C</sup>
    </p>
        <p class="feels-like temp-2 weather-cell ng-isolate-scope" data-wx-temperature="data.getFeelsLike()" data-temp-prefix="Feels"><span ng-if="tempPrefix" class="temp-prefix ng-binding ng-scope" data-ng-bind="tempPrefix">Feels</span><span data-ng-if="hasValue()" data-ng-bind="temp" class="ng-binding ng-scope">34</span><sup data-ng-if="hasValue()" class="deg ng-scope">°</sup>
    </p>
        <div class="weather-cell">
            <h3 class="weather-phrase">
                <div class="weather-icon ng-isolate-scope wx-weather-icon" data-wxicon="" data-sky-code="data.getSkyCode()"><div class="svg-icon"><img src="/sites/all/modules/custom/angularmods/app/shared/wxicon/svgz/thunderstorm.svgz?1" aria-hidden="true" alt="thunderstorm"></div></div>

                <span class="phrase ng-binding" data-ng-bind-template="Thunderstorms">Thunderstorms</span>
            </h3>
        </div>
        <!-- The Next Line Is What I Need-->
        <p class="precip weather-cell ng-isolate-scope" data-wx-precip="dataMethods.roundedValue(data.getChanceOfPrecipDay())" data-wx-precip-type="data.getPrecipType()" data-wx-precip-sky-code="data.getSkyCode()"><span aria-hidden="true" class="wx-iconfont-global wx-icon-precip-rain-1"></span><span data-ng-if="!wxPrecipIconOnly" class="precip-val ng-binding ng-scope" data-ng-bind="chanceOfPrecip() | safeDisplay">85%</span></p>

        <p class="humidity-wrapper weather-cell">
          <span data-ng-bind-template="85%" class="humidity ng-binding ng-isolate-scope" data-wx-percentage="data.getHumidity()">85%</span>
        </p>

        <p class="wind-conditions weather-cell">
            <span class="wx-wind ng-binding ng-isolate-scope" data-ng-bind-template="ESE 9 km/h" data-wx-wind-direction="data.getWindDirectionText()" data-wx-wind-speed="data.getWindSpeed()">ESE 9 km/h</span>
        </p>
    </section>
EOT
at
查找第一个匹配节点并返回它<代码>文本检索其文本节点

您希望该类具有多个节点,因此类似这样的内容应该会有所帮助:

doc.search('.precip-val').map(&:text) # => ["85%"]
search
查找所有匹配的节点并返回节点集,该节点集类似于数组,可以使用
map
进行迭代

他们不太可能将
.precip val
用于非沉淀标记包装值,但如果他们使用了,请尝试:

doc.search('span.precip-val').map(&:text)

然后看看你能得到什么。

欢迎来到Stack Overflow。请不要要求我们去一个网站,通过HTML挖掘;您需要提取演示您正在使用的内容所需的最小HTML,并将其放入您的问题中。请为我们提供一个您希望收集的数据示例。请读“。使用短选择器比使用长选择器更容易定位数据。把它分成小块,看看你是否能用这种方法获取数据。@theTinMan感谢你的输入。请看我编辑的帖子。为了精确起见,我的选择器有点长,只提取我需要的数据。然而,话虽如此,我将寻找更短、更好的方法来获得相同的数据。我试着分解选择器,但也没用。
doc.search('.precip-val').map(&:text) # => ["85%"]
doc.search('span.precip-val').map(&:text)