[英]scrapy/regex get json_object from html <script></script>
[英]Scrapy: extract JSON from within HTML script
我正在嘗試從 HTML 腳本中提取(似乎是)JSON 數據。 網站上的 HTML 腳本如下所示:
<script>
$(document).ready(function(){
var terms = new Verba.Compare.Collections.Terms([{"id":"6436","name":"SUMMER 16","inquiry":true,"ordering":true},{"id":"6517","name":"FALL 16","inquiry":true,"ordering":true}]);
var view = new Verba.Compare.Views.CourseSelector({el: "body", terms: terms});
});
</script>
我想提取以下內容:
[{"id":"6436","name":"SUMMER 16","inquiry":true,"ordering":true},{"id":"6517","name":"FALL 16","inquiry":true,"ordering":true}]
使用以下代碼,我可以獲得完整的腳本。
def parse(self, response):
print response.xpath('/html/body/script[2]').extract()
有沒有一種簡單的方法可以從該腳本中提取“id”、“name”等的值。 或者,有沒有更直接的方法通過修改xpath? 我似乎無法使用 firebug 更深入地了解 xpath。
您可以為此使用js2xml 。
為了說明,首先,讓我們使用示例 HTML 創建一個 Scrapy 選擇器,並獲取 JavaScript 語句:
>>> import scrapy
>>> sample = '''<script>
... $(document).ready(function(){
... var terms = new Verba.Compare.Collections.Terms([{"id":"6436","name":"SUMMER 16","inquiry":true,"ordering":true},{"id":"6517","name":"FALL 16","inquiry":true,"ordering":true}]);
... var view = new Verba.Compare.Views.CourseSelector({el: "body", terms: terms});
... });
... </script>'''
>>> selector = scrapy.Selector(text=sample, type='html')
>>> selector.xpath('//script//text()').extract_first()
u'\n $(document).ready(function(){\n var terms = new Verba.Compare.Collections.Terms([{"id":"6436","name":"SUMMER 16","inquiry":true,"ordering":true},{"id":"6517","name":"FALL 16","inquiry":true,"ordering":true}]);\n var view = new Verba.Compare.Views.CourseSelector({el: "body", terms: terms});\n });\n'
然后我們可以用 js2xml 解析 JavaScript 代碼。 你得到一個 lxml 樹:
>>> import js2xml
>>> jssnippet = selector.xpath('//script//text()').extract_first()
>>> jstree = js2xml.parse(jssnippet)
>>> jstree
<Element program at 0x7fc7c6bae1b8>
樹長什么樣子? 它非常冗長:
>>> print(js2xml.pretty_print(jstree))
<program>
<functioncall>
<function>
<dotaccessor>
<object>
<functioncall>
<function>
<identifier name="$"/>
</function>
<arguments>
<identifier name="document"/>
</arguments>
</functioncall>
</object>
<property>
<identifier name="ready"/>
</property>
</dotaccessor>
</function>
<arguments>
<funcexpr>
<identifier/>
<parameters/>
<body>
<var name="terms">
<new>
<dotaccessor>
<object>
<dotaccessor>
<object>
<dotaccessor>
<object>
<identifier name="Verba"/>
</object>
<property>
<identifier name="Compare"/>
</property>
</dotaccessor>
</object>
<property>
<identifier name="Collections"/>
</property>
</dotaccessor>
</object>
<property>
<identifier name="Terms"/>
</property>
</dotaccessor>
<arguments>
<array>
<object>
<property name="id">
<string>6436</string>
</property>
<property name="name">
<string>SUMMER 16</string>
</property>
<property name="inquiry">
<boolean>true</boolean>
</property>
<property name="ordering">
<boolean>true</boolean>
</property>
</object>
<object>
<property name="id">
<string>6517</string>
</property>
<property name="name">
<string>FALL 16</string>
</property>
<property name="inquiry">
<boolean>true</boolean>
</property>
<property name="ordering">
<boolean>true</boolean>
</property>
</object>
</array>
</arguments>
</new>
</var>
<var name="view">
<new>
<dotaccessor>
<object>
<dotaccessor>
<object>
<dotaccessor>
<object>
<identifier name="Verba"/>
</object>
<property>
<identifier name="Compare"/>
</property>
</dotaccessor>
</object>
<property>
<identifier name="Views"/>
</property>
</dotaccessor>
</object>
<property>
<identifier name="CourseSelector"/>
</property>
</dotaccessor>
<arguments>
<object>
<property name="el">
<string>body</string>
</property>
<property name="terms">
<identifier name="terms"/>
</property>
</object>
</arguments>
</new>
</var>
</body>
</funcexpr>
</arguments>
</functioncall>
</program>
您可以使用您的 XPath 技能來指向 JavaScript 數組(您需要分配給var terms
的new
結構的“點”訪問器的第一個參數):
>>> jstree.xpath('//var[@name="terms"]')
[<Element var at 0x7fc7c565e638>]
>>> jstree.xpath('//var[@name="terms"]/new/arguments/*')
[<Element array at 0x7fc7c565e5a8>]
>>> jstree.xpath('//var[@name="terms"]/new/arguments/*')[0]
<Element array at 0x7fc7c565e5a8>
最后,現在你有了<array>
元素,你可以將它傳遞給js2xml.jsonlike.make_dict()
以獲得一個很好的 Python 對象來使用( make_dict
有點命名錯誤):
>>> js2xml.jsonlike.make_dict(jstree.xpath('//var[@name="terms"]/new/arguments/*')[0])
[{'ordering': True, 'inquiry': True, 'id': '6436', 'name': 'SUMMER 16'}, {'ordering': True, 'inquiry': True, 'id': '6517', 'name': 'FALL 16'}]
>>>
注意:您還可以使用快捷方式js2xml.jsonlike.getall()
獲取所有看起來像 Python dict 或列表的內容(您得到 2 個列表,您對第一個感興趣):
>>> js2xml.jsonlike.getall(jstree)
[[{'ordering': True, 'inquiry': True, 'id': '6436', 'name': 'SUMMER 16'}, {'ordering': True, 'inquiry': True, 'id': '6517', 'name': 'FALL 16'}], {'el': 'body', 'terms': 'terms'}]
我會使用正則表達式提取它,例如:
response.xpath('/html/body/script[2]').re_first('\((\[.*\])\)')
chompjs提供了將 JavaScript 對象解析為 dict 的 API。
例如,如果 JavaScript 代碼包含var data = {field: "value", secondField: "second value"}
; 您可以按如下方式提取該數據:
import chompjs
javascript = response.css('script::text').get()
data = chompjs.parse_js_object(javascript)
最終結果是{'field': 'value', 'secondField': 'second value'}
a
您無法“深入”,因為該元素的內容只是文本。 從 JavaScript 中讀出 JSON 並不難:
line = javascript.strip().splitlines()[1]
the_json = line.split('(', 1)[1].split(')', 1)[0]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.