2016-05-11 2 views
2

Ich versuche mit Scrapy von einer nicht englischen Website zu kratzen. Die geschabt Ergebnisse als JSON in etwa so aussehen:Nicht " u": Wie kann man Unicode in JSON entschlüsseln?

{"price": "13,000", "name": "\u58c1\u6bb4\u308a\u4ee3\u884c\u69d8\u5c02\u7528\u2605 \u30c6\u30ec\u30d3\u672c\u4f53 20v\u578b \u767d \u9001\u6599\u8fbc"}, 

Dies ist der Code, ich verwende:

def parse(self, response): 
    for sel in response.xpath('//section[@class="items-box"]'): 
     item = ShopItem() 
     item['name'] = sel.xpath('a/div/h3/text()').extract() 
     item['price'] = sel.xpath('a/div/div/div[1]/text()').extract().replace("$", "") 
     yield item 

Wie würde ich Ausgabe unescaped Unicode-Zeichen auf die JSON?

+0

Es gab ein Problem neulich über eben diese: https://github.com/scrapy/scrapy/Ausgaben/1963. Überprüfen Sie, wie Sie einen [Exporteur für benutzerdefinierte Elemente] verwenden können (https://github.com/scrapy/scrapy/issues/1963#issuecomment-215797219) ** ohne ** 'ensure_ascii = True' (der Standard mit scrapy) –

+2

Das Beispiel ist gültig json (fast - es hat ein Komma am Ende) und konnte mit 'json.loads' in Python konvertiert werden. Aber deine Frage ist immer noch sehr verwirrend. Wo ist dieser Json genau? Ist es in eine HTML-Seite eingebettet? Wenn 'name' in dem json ist, wie würde dann auch mit dem '' a/div/h3/text() '' xpath zugegriffen werden? – tdelaney

+0

@tdelaney Der JSON wird ausgegeben, indem die Option "-o" zu "scrapy crawl spider" hinzugefügt wird –

Antwort

1

Verwenden the codecs module für (In Python 2 ist es nicht unbedingt notwendig, aber in Python 3 str hat keinen decode Verfahren, weil die Methoden für str sind ->bytes und zurück, nicht str ->str). Unter Verwendung des unicode_escape Codec zur Dekodierung werden Sie die richtigen Daten zurück:

import codecs 

somestr = codecs.decode(strwithescapes, 'unicode-escape') 

So die Namen zu beheben, Sie bekommen, dann würden Sie tun:

item['name'] = codecs.decode(sel.xpath('a/div/h3/text()').extract(), 'unicode-escape') 

Wenn das Problem in JSON ist, dass Sie Produzieren möchten Sie nur sicherstellen, dass das json Modul Zeichenketten nicht zwingen ASCII mit Zeichenkodierungen; Dies geschieht standardmäßig, weil nicht alle JSON-Parser mit echten Unicode-Zeichen umgehen können (sie gehen oft davon aus, dass Daten als ASCII-Bytes mit Escapes gesendet werden). Also, wo immer Sie anrufen json.dump/ (oder erstellen Sie eine json.JSONEncoder), stellen Sie sicher, dass ensure_ascii=False explizit übergeben.

+2

Die '\ uXXXX'-Kodierung ist für JSON gültig. OP hat bereits eine gültige JSON-Zeichenfolge und es ist nicht notwendig, Unicode-Escape durchzuführen. 'json.loads' konvertiert die Zeichenfolge in python. – tdelaney

+0

@tdelaney: Einverstanden, es ist gültig, aber es ist auch vollkommen vernünftig, dies zu vermeiden, entweder weil der Empfänger kein richtiger JSON-Parser ist (viele Implementierungen lassen Teile der Spezifikation weg, oder es ist nicht einmal ein richtiger JSON-Parser, weil irgendein Ruck gerendert ihren eigenen Parsing-Code), oder um die Größe zu reduzieren (in der Regel ist JSON UTF-8-kodiert, und UTF-8 für Nicht-ASCII-Zeichen werden 2-4 Bytes, in der Regel 3 für ostasiatische Sprachen im Vergleich zu einem festen 6 Bytes für der ASCII-Escape-Code). Es sieht so aus, als ob das OP JSON zum Formatieren von Daten verwendet, die in ihrem Skript gecrackt und organisiert sind, wobei JSON nicht von der Site analysiert wird. – ShadowRanger

+0

@tdelaney: Ich denke, dass sie XML/HTML analysieren, um bestimmte Daten herauszuziehen, und sie dann in einem Objekt speichern, das sie JSON kodieren können (was es einfacher macht, später zu verwenden oder zu übertragen). HTML Parsing Kosten). Der HTML-Code enthält diese Escape-Zeichen und sie enden in der JSON-codierten Ausgabe (oder sie verwenden nicht "use_ascii = False" und die JSON-Codierung erstellt sie), sodass meine Ansätze beide Seiten abdecken. Entfernen der Kodierung von den Daten, die aus dem HTML gezogen wurden, und Vermeiden, sie bei der JSON-Serialisierung zu lesen. – ShadowRanger

3

bearbeiten (2016.10.19):

Mit Scrapy 1.2+ können Sie den FEED_EXPORT_ENCODING Satz auf das Zeichen verwenden Sie für die Ausgabe JSON-Datei benötigen kodiert, zB FEED_EXPORT_ENCODING = 'utf-8' (der Standardwert None sein , was bedeutet, \uXXXX Flucht)


Hinweis: ich bin Anpassung what I wrote on GitHub for a similar issue ich in der Frage des Kommentare verknüpft.

Beachten Sie, dass eine offene Frage auf Scrapy gibt es die Ausgabe codiert, um einen Parameter zu machen: https://github.com/scrapy/scrapy/issues/1965


Scrapy's default JSON exporter verwendet (Standardeinstellung) ensure_ascii=True Argument, so dass es Unicode-Zeichen als \uXXXX Sequenzen ausgibt, bevor die Datei zu schreiben. (Dies ist, was verwendet wird, wenn -o somefile.json getan wird)

Einstellung ensure_ascii=False im Exporteur wird Unicode-Zeichenfolgen ausgeben, which will end up as UTF-8 encoded on file. Siehe unten im Abschnitt zum benutzerdefinierten Exportcode.

Zur Veranschaulichung, lassen Sie uns Ihre Eingabe JSON-String zurück in einige Daten lesen zu arbeiten:

>>> import json 
>>> test = r'''{"price": "13,000", "name": "\u58c1\u6bb4\u308a\u4ee3\u884c\u69d8\u5c02\u7528\u2605 \u30c6\u30ec\u30d3\u672c\u4f53 20v\u578b \u767d \u9001\u6599\u8fbc"}''' 
>>> json.loads(test) 
{u'price': u'13,000', u'name': u'\u58c1\u6bb4\u308a\u4ee3\u884c\u69d8\u5c02\u7528\u2605 \u30c6\u30ec\u30d3\u672c\u4f53 20v\u578b \u767d \u9001\u6599\u8fbc'} 

Die Eingabe mit \uXXXX Sequenzen ist gültig JSON für Python (wie es sein sollte) und loads() erzeugt eine gültige Python dict.

Nun wollen wir wieder zu JSON serialisiert:

>>> # dumping the dict back to JSON, with default ensure_ascii=True 
>>> json.dumps(json.loads(test)) 
'{"price": "13,000", "name": "\\u58c1\\u6bb4\\u308a\\u4ee3\\u884c\\u69d8\\u5c02\\u7528\\u2605 \\u30c6\\u30ec\\u30d3\\u672c\\u4f53 20v\\u578b \\u767d \\u9001\\u6599\\u8fbc"}' 
>>> 

Und jetzt mit ensure_ascii=False

>>> # now dumping with ensure_ascii=False, you get a Unicode string 
>>> json.dumps(json.loads(test), ensure_ascii=False) 
u'{"price": "13,000", "name": "\u58c1\u6bb4\u308a\u4ee3\u884c\u69d8\u5c02\u7528\u2605 \u30c6\u30ec\u30d3\u672c\u4f53 20v\u578b \u767d \u9001\u6599\u8fbc"}' 
>>> 

Druck Lassen Sie uns den Unterschied zu sehen:

>>> print json.dumps(json.loads(test)) 
{"price": "13,000", "name": "\u58c1\u6bb4\u308a\u4ee3\u884c\u69d8\u5c02\u7528\u2605 \u30c6\u30ec\u30d3\u672c\u4f53 20v\u578b \u767d \u9001\u6599\u8fbc"} 

>>> print json.dumps(json.loads(test), ensure_ascii=False) 
{"price": "13,000", "name": "壁殴り代行様専用★ テレビ本体 20v型 白 送料込"} 

Wenn Sie JSON Artikel schreiben möchten als UTF-8 können Sie es so machen:

1 .. Definieren Sie einen benutzerdefinierten Artikelexporteur, z. in einer exporters.py Datei in Ihrem Projekt

$ cat myproject/exporters.py 
from scrapy.exporters import JsonItemExporter 


class Utf8JsonItemExporter(JsonItemExporter): 

    def __init__(self, file, **kwargs): 
     super(Utf8JsonItemExporter, self).__init__(
      file, ensure_ascii=False, **kwargs) 

2 .. den Standard JSON Artikel Exporteur ersetzt in Ihrem settings.py

FEED_EXPORTERS = { 
    'json': 'myproject.exporters.Utf8JsonItemExporter', 
}