Nokogiri的结果与更广泛的检查不同

时间:2016-11-09 10:48:10

标签: ruby-on-rails ruby web-scraping nokogiri open-uri

我正在尝试抓取一个网站,但仅仅链接返回的结果与我使用浏览器检查时的结果不同。

在我的浏览器中,我获得了正常链接,但所有HREF链接都变为来自Nokogiri的javascript:void(0);

这是网站:

https://www.ctgoodjobs.hk/jobs/part-time

这是我的代码:

url = "https://www.ctgoodjobs.hk/jobs/part-time"
response = open(url) rescue nil
next unless response
doc = Nokogiri::HTML(open(url))
links = doc.search('.job-title > a').text

2 个答案:

答案 0 :(得分:1)

并不那么容易,使用js函数“隐藏”网址,这就是为什么你在要求hrefs时获得javascript: void(0) ...查看html,每个链接都有一些隐藏的输入,并且,有一个预览网址,您可以使用它来构建作业预览网址(如果这是您正在寻找的),所以你有这个:

<div class="result-list-job current-view">
  <input type="hidden" name="job_id" value="04375145">
  <input type="hidden" name="each_job_title_url" value="barista-senior-barista-咖啡調配員">
  <h2 class="job-title"><a href="javascript:void(0);">Barista/ Senior Barista 咖 啡 調 配 員</a></h2>
  <h3 class="job-company"><a href="/company-jobs/pacific-coffee-company/00028652" target="_blank">PACIFIC COFFEE CO. LTD.</a></h3>
  <div class="job-description">
    <ul class="job-desc-list clearfix">
      <li class="job-desc-loc job-desc-small-icon">-</li>
      <li class="job-desc-work-exp">0-1 yr(s)</li>
      <li class="job-desc-salary job-desc-small-icon">-</li>
      <li class="job-desc-post-date">09/11/16</li>
    </ul>
  </div>
  <a class="job-save-btn" title="save this job" style="display: inline;"> </a>
  <div class="job-batch-apply"><span class="checkbox" style="background-position: 0px 0px;"></span><input type="checkbox" class="styled" name="job_checkbox" value="04375145"></div>
  <div class="job-cat job-cat-de"></div>
</div>

然后,您可以从这些输入中检索每个job_id,例如:

 inputs = doc.search('//input[@name="job_id"]')

然后构建网址(我在joblist_preview.js找到了基本网址:

 urls = inputs.map do |input|
   "https://www.ctgoodjobs.hk/english/jobdetails/details.asp?m_jobid=#{input['value']}&joblistmode=previewlist&ga_channel=ct"
 end

答案 1 :(得分:0)

获取浏览器的输出以及wgetcurlnokogiri等工具的输出,您会发现浏览器提供的HTML与原始HTML有很大不同。

这些天浏览器可以处理DHTML,Nokogiri没有。您只能使用能够在没有浏览器的情况下查看内容的内容检索原始 HTML,如上面提到的工具,然后将其与您在文本编辑器中看到的内容进行比较,或者{{1}告诉你。不要相信浏览器 - 他们知道撒谎是因为他们想让你开心。

在这里,我们可以快速了解原始HTML包含的内容,使用以下内容生成:

nokogiri

Nokogiri让我进入IRB:

$ nokogiri "https://www.ctgoodjobs.hk/jobs/part-time"

计算选择器找到的命中数会返回:

Your document is stored in @doc...
Welcome to NOKOGIRI. You are using ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-darwin15]. Have fun ;)

显示找到的文字显示:

>> @doc.search('.job-title > a').size
30

查看实际的>> @doc.search('.job-title > a').map(&:text) [ [ 0] "嬰 兒 奶 粉 沖 調 機 - 兼 職 產 品 推 廣 員 Part Time Promoter (時 薪 高 達 HK$90, 另 設 銷 售 佣 金 )", ... [29] "Customer Services Representative (Part-time)" ]

href

你可以告诉HTML除了Nokogiri告诉你的内容之外什么都不包含,所以浏览器会对HTML进行后期处理,处理DHTML并修改你看到的用于查看HTML的页面。因此,简短的解决方法是,如果您想知道服务器发送给您的信息,请不要信任浏览器。

这就是为什么抓取非常可靠的原因,如果可能的话你应该使用API​​。如果你不能,那么你将不得不卷起袖子并深入研究JavaScript并手动解释它正在做什么,然后检索数据并将其解析为有用的东西。 / p>

您的代码可以清理和简化。我把它简单地写成:

>> @doc.search('.job-title > a').map{ |n| n['href'] }
[
  [ 0] "javascript:void(0);",
...
  [29] "javascript:void(0);"
]

使用url = "https://www.ctgoodjobs.hk/jobs/part-time" doc = Nokogiri::HTML(open(url)) links = doc.search('.job-title > a').map(&:text) 是一个很大的错误。 search(...).text应用于NodeSet时,将连接每个包含节点的文本,使得检索单个文本变得极其困难。考虑一下:

text

第一个结果require 'nokogiri' doc = Nokogiri::HTML(<<EOT) <html> <body> <p>foo</p> <p>bar</p> </body> </html> EOT doc.search('p').class # => Nokogiri::XML::NodeSet doc.search('p').text # => "foobar" doc.search('p').map(&:text) # => ["foo", "bar"] 需要分开才能有用,除非你对内容有特殊的了解,否则试图弄清楚如何做到这将是一个很大的痛苦。

相反,使用foobar遍历元素并将map应用于每个元素,返回每个元素文本的数组。

参见&#34; How to avoid joining all text from Nodes when scraping&#34;和&#34; Taking apart a DHTML page&#34;还