2016-07-19 10 views
1

Ich versuche, JSON-Daten aus einem HTML-Skript zu extrahieren (was zu sein scheint). Die HTML-Skript sieht wie folgt auf der Seite:Scrapy: JSON aus dem HTML-Skript extrahieren

<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> 

Ich möchte folgendes herausziehen:

[{"id":"6436","name":"SUMMER 16","inquiry":true,"ordering":true},{"id":"6517","name":"FALL 16","inquiry":true,"ordering":true}] 

Verwendung des folgenden Codes, ich bin in der Lage, die vollständige Skript zu erhalten.

def parse(self, response): 
     print response.xpath('/html/body/script[2]').extract() 

Gibt es eine einfache Möglichkeit, um dann die Werte für „id“ zu extrahieren, „name“ usw. aus diesem Skript. Oder gibt es einen direkteren Weg, den Xpath zu ändern? Ich kann auf dem XPath mit Firebug nicht tiefer gehen.

+0

Würden diese Hilfe: http : //stackoverflow.com/questions/13323976/how-to-extract-a-json-object-that-was-defined-in-html-page-javascript-block-us – Koba

Antwort

-1

Sie können nicht "tiefer" gehen, weil der Inhalt dieses Elements nur Text ist. Es ist nicht allzu schwer, die JSON aus dem JavaScript vorzulesen:

line = javascript.strip().splitlines()[1] 
the_json = line.split('(', 1)[1].split(')', 1)[0] 
0

ich es mit einem regulären Ausdruck extrahieren würde, so etwas wie:

response.xpath('/html/body/script[2]').re_first('\((\[.*\])\)') 
+0

Es funktioniert! Nach ein bisschen mehr Forschung habe ich eine ähnliche Methode gefunden, wie Sie gerade geschrieben haben. Dein ist jedoch viel sauberer. Vielen Dank. – ridingsolo

+0

Sie sind herzlich willkommen. Bitte zögern Sie nicht, dies als Antwort zu markieren, wenn es Ihr Problem gelöst hat. – Wilfredo

3

Sie js2xml dafür verwenden können.

Zur Veranschaulichung lassen Sie sich zuerst einen Scrapy Wähler mit Ihrem HTML-Beispiel erstellen, und die JavaScript-Anweisungen greifen:

>>> 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' 

Dann können wir den JavaScript-Code mit js2xml analysieren. Sie erhalten einen Lxml-Baum zurück:

>>> import js2xml 
>>> jssnippet = selector.xpath('//script//text()').extract_first() 
>>> jstree = js2xml.parse(jssnippet) 
>>> jstree 
<Element program at 0x7fc7c6bae1b8> 

Wie sieht der Baum aus? Es ist ziemlich ausführliches:

>>> 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> 

Sie Ihre XPath Fähigkeiten nutzen können, um den JavaScript-Array Punkt (Sie das erste Argument des „Punktes“ Accessor wollen für das new Konstrukt zugewiesen var terms):

>>> 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> 

Schließlich jetzt, dass Sie das <array> Element haben, können Sie es zu js2xml.jsonlike.make_dict() passieren ein schönes Python-Objekt zu erhalten, mit zu arbeiten (make_dict irgendwie falsch benannt ist):

>>> 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'}] 
>>> 

Hinweis: Sie können auch die Verknüpfung js2xml.jsonlike.getall() verwenden, um alles zu holen, der wie ein Python dict oder Liste (Sie 2 Listen erhalten, sind Sie in der 1. ein Interesse) aussieht:

>>> 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'}]