Nokogiri 结果不同于 brower inspect
Nokogiri results different from brower inspect
我正在尝试抓取一个网站,但仅针对链接返回的结果与我使用浏览器检查它时返回的结果不同。
在我的浏览器中,我得到了正常的链接,但是所有的 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
没那么容易,url 是 "obscured" 使用 js 函数,这就是为什么你在请求 href 时得到 javascript: void(0)
的原因...查看 html,每个 link 都有一些隐藏的输入,并且有一个预览 url,您可以使用它来构建作业预览 url(如果这就是您想要的寻找),所以你有这个:
<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"]')
然后构建 urls(我在 joblist_preview.js
:
找到了基础 url
urls = inputs.map do |input|
"https://www.ctgoodjobs.hk/english/jobdetails/details.asp?m_jobid=#{input['value']}&joblistmode=previewlist&ga_channel=ct"
end
获取浏览器的输出和 wget
、curl
或 nokogiri
等工具的输出,您会发现浏览器呈现的 HTML 可能存在巨大差异来自原始 HTML。
如今的浏览器可以处理 DHTML,而 Nokogiri 则不能。您只能检索 raw HTML 使用可以让您在没有浏览器的情况下查看内容的工具,例如上述工具,然后将其与您在文本编辑器中看到的内容进行比较,或者 nokogiri
向您显示的内容。不要相信浏览器 - 众所周知,它们会撒谎,因为它们想让您开心。
下面是原始 HTML 包含的内容的快速浏览,使用以下方法生成:
$ nokogiri "https://www.ctgoodjobs.hk/jobs/part-time"
Nokogiri 让我进入 IRB:
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 ;)
计算选择器找到的命中数 returns:
>> @doc.search('.job-title > a').size
30
显示找到的文本显示:
>> @doc.search('.job-title > a').map(&:text)
[
[ 0] "嬰 兒 奶 粉 沖 調 機 - 兼 職 產 品 推 廣 員 Part Time Promoter (時 薪 高 達 HK, 另 設 銷 售 佣 金 )",
...
[29] "Customer Services Representative (Part-time)"
]
看实际href
:
>> @doc.search('.job-title > a').map{ |n| n['href'] }
[
[ 0] "javascript:void(0);",
...
[29] "javascript:void(0);"
]
你可以告诉 HTML 除了 Nokogiri 告诉你的内容之外什么都不包含,所以浏览器正在 post-处理 HTML,处理 DHTML 和修改你看到的页面,如果你用东西看HTML。因此,简短的解决方法是,如果您想知道服务器发送给您的内容,请不要相信浏览器。
这就是为什么抓取不是很可靠,您应该尽可能使用 API。如果你不能,那么你将不得不卷起袖子深入研究 JavaScript 并手动解释它在做什么,然后检索数据并将其解析为有用的东西。
您的代码可以清理和简化。我会把它写得更简单:
url = "https://www.ctgoodjobs.hk/jobs/part-time"
doc = Nokogiri::HTML(open(url))
links = doc.search('.job-title > a').map(&:text)
search(...).text
的使用是一个大错误。 text
,当应用于 NodeSet 时,将连接每个包含的节点的文本,使得检索单个文本变得极其困难。考虑一下:
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
遍历元素并对每个元素应用 &:text
,返回每个元素文本的数组。
另见“" and "Taking apart a DHTML page”。
我正在尝试抓取一个网站,但仅针对链接返回的结果与我使用浏览器检查它时返回的结果不同。
在我的浏览器中,我得到了正常的链接,但是所有的 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
没那么容易,url 是 "obscured" 使用 js 函数,这就是为什么你在请求 href 时得到 javascript: void(0)
的原因...查看 html,每个 link 都有一些隐藏的输入,并且有一个预览 url,您可以使用它来构建作业预览 url(如果这就是您想要的寻找),所以你有这个:
<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"]')
然后构建 urls(我在 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
获取浏览器的输出和 wget
、curl
或 nokogiri
等工具的输出,您会发现浏览器呈现的 HTML 可能存在巨大差异来自原始 HTML。
如今的浏览器可以处理 DHTML,而 Nokogiri 则不能。您只能检索 raw HTML 使用可以让您在没有浏览器的情况下查看内容的工具,例如上述工具,然后将其与您在文本编辑器中看到的内容进行比较,或者 nokogiri
向您显示的内容。不要相信浏览器 - 众所周知,它们会撒谎,因为它们想让您开心。
下面是原始 HTML 包含的内容的快速浏览,使用以下方法生成:
$ nokogiri "https://www.ctgoodjobs.hk/jobs/part-time"
Nokogiri 让我进入 IRB:
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 ;)
计算选择器找到的命中数 returns:
>> @doc.search('.job-title > a').size
30
显示找到的文本显示:
>> @doc.search('.job-title > a').map(&:text)
[
[ 0] "嬰 兒 奶 粉 沖 調 機 - 兼 職 產 品 推 廣 員 Part Time Promoter (時 薪 高 達 HK, 另 設 銷 售 佣 金 )",
...
[29] "Customer Services Representative (Part-time)"
]
看实际href
:
>> @doc.search('.job-title > a').map{ |n| n['href'] }
[
[ 0] "javascript:void(0);",
...
[29] "javascript:void(0);"
]
你可以告诉 HTML 除了 Nokogiri 告诉你的内容之外什么都不包含,所以浏览器正在 post-处理 HTML,处理 DHTML 和修改你看到的页面,如果你用东西看HTML。因此,简短的解决方法是,如果您想知道服务器发送给您的内容,请不要相信浏览器。
这就是为什么抓取不是很可靠,您应该尽可能使用 API。如果你不能,那么你将不得不卷起袖子深入研究 JavaScript 并手动解释它在做什么,然后检索数据并将其解析为有用的东西。
您的代码可以清理和简化。我会把它写得更简单:
url = "https://www.ctgoodjobs.hk/jobs/part-time"
doc = Nokogiri::HTML(open(url))
links = doc.search('.job-title > a').map(&:text)
search(...).text
的使用是一个大错误。 text
,当应用于 NodeSet 时,将连接每个包含的节点的文本,使得检索单个文本变得极其困难。考虑一下:
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
遍历元素并对每个元素应用 &:text
,返回每个元素文本的数组。
另见“