我正在尝试从this页面的最新日期(表格的第一行)抓取数据网址链接。但似乎表的内容是由Javascript函数生成的。我尝试使用Nokogiri得到它但是徒劳无益,因为nokogiri无法刮掉Javascript。然后,我尝试使用Nokogiri获取脚本部分:
url = "http://www.sgx.com/wps/portal/sgxweb/home/marketinfo/historical_data/derivatives/daily_data"
doc = Nokogiri::HTML(open(url))
js = doc.css("script").text
puts js
在输出中,我找到了我想要的类名为 sgxTableGrid 的表。但问题是Javascript函数中没有关于数据URL链接的线索,并且所有内容都是动态生成的。所以,我想知道是否有人知道更好的方法来解决这个问题。
答案 0 :(得分:7)
查看该页面的HTML,该表由JSON收到,作为JavaScript请求的结果。
您可以通过向后搜索页面的源代码来弄清楚发生了什么。如果你想在JavaScript之外检索JSON,你需要的是一些内容,但是仍然需要用它来实际做一些事情:
从此代码开始:
require 'open-uri'
require 'nokogiri'
doc = Nokogiri::HTML(open('http://www.sgx.com/wps/portal/sgxweb/home/marketinfo/historical_data/derivatives/daily_data'))
scripts = doc.css('script').map(&:text)
puts scripts.select{ |s| s['sgxTableGrid'] }
查看编辑器中的文本输出。搜索sgxTableGrid
。您会看到如下行:
var tableHeader = "<table width='100%' class='sgxTableGrid'>"
往下看,你会看到:
var totalRows = data.items.length - 1;
data
来自被调用函数的参数,因此这就是我们开始的地方。
获取包含函数名称loadGridns_
的唯一部分并搜索它。每次找到它时,查找参数data
,然后查看data
的定义位置。如果它被传递到该方法,则搜索以查看调用它的方法。重复该过程,直到您发现变量未传递给函数,此时您将知道您正在创建它的方法。
我发现自己处于以loadGridDatans
开头的函数中,它是一个块的一部分,它执行xhrPost
调用以检索URL。该URL是您所追求的目标,因此请抓取包含该函数的名称,并循环传入URL的调用,就像您在上一步中所做的那样。
该搜索最终显示在一行:
var url = viewByDailyns_7_2AA4H0C090FIE0I1OH2JFH20K1_...
此时,您可以开始重建所需的网址。打开一个JavaScript调试器,如Firebug,并在该行上放置一个断点。重新加载页面,JavaScript应该停止在该行执行。单步或设置断点,并观察url
变量的创建,直到它处于最终形式。此时,您可以在OpenURI
中使用某些内容,应该检索您想要的JSON。
注意,它们的函数名称可能是动态生成的;我没有检查,所以尝试使用函数的全名可能会失败。
他们可能也会序列化日期时间戳或使用序列化的会话密钥使函数名称唯一/更不透明,这样做有很多原因。
即使将这些东西分开也很痛苦,但这也是动态页面工作方式的一个很好的教训。