0

Please read update: SO updates the string to remove certain character in json string which causes the problem. Shared the pastebin link below with original string https://pastebin.com/tkJLFNGS

I am getting a json response from some page with non ascii characters. It has some html content inside.

The string when observed manually looks okay.

It shows as invalid in jsonlint and other sites etc. Some sites mention it to be valid. Possibly this is due to non ascii characters.

I couldn't parse it using json.loads.

I tried using suggestions for non ascii code but they haven't worked.

Is the response incorrect or I am unable to parse it correctly ?

import json
json_string = """{
    "@context": "https://schema.org",
    "@type": "FAQPage",
    "mainEntity": [{
        "name": "Hur mycket kostar ett flyg från LHR till JFK?",
        "@type": "Question",
        "acceptedAnswer": {
            "@type": "Answer",
            "text": "<p>Lägsta angivna pris för ett flyg tur och retur mellan Heathrow och John F. Kennedy Intl. är 5 525 kr. Du måste dock agera kvickt. Denna siffra är baserad på biljettpriserna under den senaste veckan.</p>"
        }
    }, {
        "name": "Måste jag betala en avbokningsavgift om jag avbokar mitt flyg från Heathrow till John F. Kennedy Intl.?",
        "@type": "Question",
        "acceptedAnswer": {
            "@type": "Answer",
            "text": "<p>Många flyg kan avbokas online, men huruvida du måste betala en avgift kan variera mellan flygbolagen. Om du behöver avboka ditt flyg kan du följa instruktionerna i vår <a href=\"https://www.expedia.se/service/?langid=1053\">kundtjänst</a>.</p>"
        }
    }, {
        "name": "Hur gör man för att hitta billiga flyg med en flexibel ombokningspolicy från Heathrow till John F. Kennedy Intl.?",
        "@type": "Question",
        "acceptedAnswer": {
            "@type": "Answer",
            "text": "<p>Många flygbolag ger dig möjligheten att boka om ditt flyg utan ombokningsavgift. Du betalar endast mellanskillnaden mellan priset på ditt ursprungliga flyg och ditt nya flyg. När du söker på flyg från Heathrow till John F. Kennedy Intl. kan du välja filtret \"Inga ändringsavgifter\" för att se flyg utan avgifter.</p>"
        }
    }, {
        "name": "Hur många timmar tar flyget från London (LHR-Heathrow) till New York, New York (JFK-John F. Kennedy Intl.)?",
        "@type": "Question",
        "acceptedAnswer": {
            "@type": "Answer",
            "text": "<p>Det finns gott om bra sätt att få den 7 timmar och 55 minuter långa resan mellan LHR och JFK att gå fortare. Du kan till exempel passa på att vara produktiv och sortera dina foton eller din e-post. En kraftlur får också resan att kännas kortare.</p>"
        }
    }, {
        "name": "Hur långt är det från Heathrow till    John F. Kennedy Intl.?",
        "@type": "Question",
        "acceptedAnswer": {
            "@type": "Answer",
            "text": "<p>Avståndet är cirka 5 500 kilometer. Resekudde? Japp! Tandborste? Jajamensan! Du bör packa några förnödenheter till denna långa resa från Hounslow till Jamaica.</p>"
        }
    }, {
        "name": "Vilka flygbolag har direktflyg från London (LHR-Heathrow) till New York, New York (JFK-John F. Kennedy Intl.)?",
        "@type": "Question",
        "acceptedAnswer": {
            "@type": "Answer",
            "text": "<p>Med så många bra flygbolag att välja bland lär du hitta det perfekta flyget från Heathrow (LHR) till John F. Kennedy Intl. (JFK) på bara ett par klick. Nedan följer en lista över populära flygbolag som trafikerar denna sträcka:</p><p><ul><li>British Airways – (BA) med 212 flyg per månad.</li><li>Virgin Atlantic – (VS) med 152 flyg per månad.</li><li>American Airlines – (AA) med 121 flyg per månad.</li><li>Delta Air Lines – (DL) med 60 flyg per månad.</li></ul></p>"
        }
    }, {
        "name": "Är flygbiljetter från Heathrow till John F. Kennedy Intl. billigare när man köper dem i sista minuten?",
        "@type": "Question",
        "acceptedAnswer": {
            "@type": "Answer",
            "text": "<p>Ibland kan man ha tur när man bokar en flygbiljett från Heathrow (LHR) till John F. Kennedy Intl. (JFK) i sista minuten – men ibland inte. Ibland går det att hitta toppenerbjudanden, men det finns också en risk att du helt missar chansen att köpa en biljett. Om du föredrar att göra dina planer i god tid, jämför Expedia biljetterbjudanden upp till ett år i förväg. Men kom ihåg att inte alla flygbolag publicerar sina flygpriser så långt i förväg. Vi rekommenderar att du kontrollerar priserna ofta eftersom de hela tiden uppdateras.</p>"
        }
    }, {
        "name": "Går det att flyga från London (LHR-Heathrow) till New York, New York (JFK-John F. Kennedy Intl.) just nu?",
        "@type": "Question",
        "acceptedAnswer": {
            "@type": "Answer",
            "text": "<p>Vill du läsa mer om potentiella reseriktlinjer eller karantänkrav på New York, New York (JFK-John F. Kennedy Intl.) kan du gå till vår sida med <a href=\"https://www.expedia.se/lp/b/travel-advisor\">reseråd under covid-19</a>. Gå igenom all information innan du slutför bokningen, så att du inte råkar fastna någonstans när du reser.</p>"
        }
    }]
}"""

parsed_json = json.loads(json_string)

It throws this error

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/Cellar/python@3.11/3.11.4_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/json/__init__.py", line 346, in loads
    return _default_decoder.decode(s)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/Cellar/python@3.11/3.11.4_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/json/decoder.py", line 337, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/Cellar/python@3.11/3.11.4_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/json/decoder.py", line 353, in raw_decode
    obj, end = self.scan_once(s, idx)
               ^^^^^^^^^^^^^^^^^^^^^^
json.decoder.JSONDecodeError: Expecting ',' delimiter: line 16 column 197 (char 867)

As suggested by @Michael Butscher . When I try to use the raw version on the unformatted string, it still throws the error.

json_string = r'''{            "@context": "https://schema.org",            "@type": "FAQPage",            "mainEntity":             [{"name": "Hur mycket kostar ett flyg från LHR till JFK?","@type": "Question","acceptedAnswer": {    "@type": "Answer",    "text": "<p>Lägsta angivna pris för ett flyg tur och retur mellan Heathrow och John F. Kennedy Intl. är 5 525 kr. Du måste dock agera kvickt. Denna siffra är baserad på biljettpriserna under den senaste veckan.</p>"}}, {"name": "Måste jag betala en avbokningsavgift om jag avbokar mitt flyg från Heathrow till John F. Kennedy Intl.?","@type": "Question","acceptedAnswer": {    "@type": "Answer",    "text": "<p>Många flyg kan avbokas online, men huruvida du måste betala en avgift kan variera mellan flygbolagen. Om du behöver avboka ditt flyg kan du följa instruktionerna i vår <a href=\"https://www.expedia.se/service/?langid=1053\">kundtjänst</a>.</p>"}}, {"name": "Hur gör man för att hitta billiga flyg med en flexibel ombokningspolicy från Heathrow till John F. Kennedy Intl.?","@type": "Question","acceptedAnswer": {    "@type": "Answer",    "text": "<p>Många flygbolag ger dig möjligheten att boka om ditt flyg utan ombokningsavgift. Du betalar endast mellanskillnaden mellan priset på ditt ursprungliga flyg och ditt nya flyg. När du söker på flyg från Heathrow till John F. Kennedy Intl. kan du välja filtret \"Inga ändringsavgifter\" för att se flyg utan avgifter.</p>"}}, {"name": "Hur många timmar tar flyget från London (LHR-Heathrow) till New York, New York (JFK-John F. Kennedy Intl.)?","@type": "Question","acceptedAnswer": {    "@type": "Answer",    "text": "<p>Det finns gott om bra sätt att få den 7 timmar och 55 minuter långa resan mellan LHR och JFK att gå fortare. Du kan till exempel passa på att vara produktiv och sortera dina foton eller din e-post. En kraftlur får också resan att kännas kortare.</p>"}}, {"name": "Hur långt är det från Heathrow till     John F. Kennedy Intl.?","@type": "Question","acceptedAnswer": {    "@type": "Answer",    "text": "<p>Avståndet är cirka 5 500 kilometer. Resekudde? Japp! Tandborste? Jajamensan! Du bör packa några förnödenheter till denna långa resa från Hounslow till Jamaica.</p>"}}, {"name": "Vilka flygbolag har direktflyg från London (LHR-Heathrow) till New York, New York (JFK-John F. Kennedy Intl.)?","@type": "Question","acceptedAnswer": {    "@type": "Answer",    "text": "<p>Med så många bra flygbolag att välja bland lär du hitta det perfekta flyget från Heathrow (LHR) till John F. Kennedy Intl. (JFK) på bara ett par klick. Nedan följer en lista över populära flygbolag som trafikerar denna sträcka:</p><p><ul><li>British Airways – (BA) med 212 flyg per månad.</li><li>Virgin Atlantic – (VS) med 152 flyg per månad.</li><li>American Airlines – (AA) med 121 flyg per månad.</li><li>Delta Air Lines – (DL) med 60 flyg per månad.</li></ul></p>"}}, {"name": "Är flygbiljetter från Heathrow till John F. Kennedy Intl. billigare när man köper dem i sista minuten?","@type": "Question","acceptedAnswer": {    "@type": "Answer",    "text": "<p>Ibland kan man ha tur när man bokar en flygbiljett från Heathrow (LHR) till John F. Kennedy Intl. (JFK) i sista minuten – men ibland inte. Ibland går det att hitta toppenerbjudanden, men det finns också en risk att du helt missar chansen att köpa en biljett. Om du föredrar att göra dina planer i god tid, jämför Expedia biljetterbjudanden upp till ett år i förväg. Men kom ihåg att inte alla flygbolag publicerar sina flygpriser så långt i förväg. Vi rekommenderar att du kontrollerar priserna ofta eftersom de hela tiden uppdateras.</p>"}}, {"name": "Går det att flyga från London (LHR-Heathrow) till New York, New York (JFK-John F. Kennedy Intl.) just nu?","@type": "Question","acceptedAnswer": {    "@type": "Answer",    "text": "<p>Vill du läsa mer om potentiella reseriktlinjer eller karantänkrav på New York, New York (JFK-John F. Kennedy Intl.) kan du gå till vår sida med <a href=\"https://www.expedia.se/lp/b/travel-advisor\">reseråd under covid-19</a>. Gå igenom all information innan du slutför bokningen, så att du inte råkar fastna någonstans när du reser.</p>"}}]            }'''
json_parsed = json.loads(json_string) 

Error

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/Cellar/python@3.11/3.11.4_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/json/__init__.py", line 346, in loads
    return _default_decoder.decode(json_parsed)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/Cellar/python@3.11/3.11.4_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/json/decoder.py", line 337, in decode
    obj, end = self.raw_decode(json_parsed, idx=_w(json_parsed, 0).end())
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/Cellar/python@3.11/3.11.4_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/json/decoder.py", line 353, in raw_decode
    obj, end = self.scan_once(json_parsed, idx)
               ^^^^^^^^^^^^^^^^^^^^^^
json.decoder.JSONDecodeError: Invalid control character at: line 1 column 1919 (char 1918) 

Any help is appreciated

Update : It seems Stack Overflow is formatting the string and showing something else. Please see the pastebin link below

Diff checker shows a difference in some tab character. I believe the space character doesn't work in python.

The Stack Overflow version works but the original does not.

This is the original unformatted string shared via pastebin

https://pastebin.com/tkJLFNGS

enter image description here

Trying to remove non-ascii characters using this hasn't worked either https://stackoverflow.com/a/35492167/2251058

Akshay Hazari
  • 3,186
  • 4
  • 48
  • 84
  • 1
    Please make a [mre]. This is a lot of data to go through. – wjandrea Aug 22 '23 at 03:21
  • 1
    The error is correct. There is an embedded double quote in line 16, exactly as it said. That's not valid JSON. – Tim Roberts Aug 22 '23 at 03:29
  • For the shown code it can be fixed by making the string with the JSON raw: `json_string = r"""{` – Michael Butscher Aug 22 '23 at 03:51
  • @MichaelButscher Stack Overflow is editing the string to remove the tab like character which is not working – Akshay Hazari Aug 23 '23 at 04:46
  • @MichaelButscher Updated the question Pastebin link added for the original string – Akshay Hazari Aug 23 '23 at 05:02
  • 1
    Yes, trying to decode that file produces this error: *control characters from U+0000 through U+001F must be escaped at line 1, column 1983*. Which points to that John F. Kennedy part. The file simply contains characters it shouldn't, and is thus invalid JSON. Who encoded this JSON? – deceze Aug 23 '23 at 05:13
  • @deceze We are crawling some internal website pages and the pages have some json data which needs to be parsed and certain fields in the json needs to be extracted. This is from the swedish version of the site. I believe we won't be able to ask anyone to update the parts of the webpage, and have to fetch it on our own. There could be other characters in other pages as well, which could be from other different versions of the site. – Akshay Hazari Aug 23 '23 at 05:35
  • Web pages contain HTML and JavaScript, not JSON. Your crawler either extracted a JavaScript object assignment from a script (I doubt it) or *HTML* text that looks like JSON. That text may have been encoded or manipulated so it displays nicely. – Panagiotis Kanavos Aug 23 '23 at 06:59
  • I suspect the actual data is raw text, including newlines, tabs etc, that someone blindly injected into a page template and called it "JSON". Neither HTML nor JSON allow such characters without escaping. HTML will treat such characters as whitespace but any JSON parser will choke. You could try *removing* such control characters with a regex, or replace them with a single space, before you pass the text to a JSON parser – Panagiotis Kanavos Aug 23 '23 at 07:24
  • Perhaps you can try `json=text.replace("[\x00-\x1F]+", " ")` ? Or you can use the `regex` module and remove all control characters with `json=regex.sub(r'\p{C}', '', line)`. `\p{C}+` matches any Unicode character in the Control category, not just those up to `0x1F` – Panagiotis Kanavos Aug 23 '23 at 07:28
  • @PanagiotisKanavos removing control characters worked. For some reason I couldn't install regex module, but used unicodedata. You can add that as an answer `import unicodedata def remove_control_characters(s): return "".join(ch for ch in s if unicodedata.category(ch)[0]!="C")` – Akshay Hazari Aug 23 '23 at 09:25

2 Answers2

1

If you are sure the special characters are only in the strings of the JSON data, you can use:

escape_table = {k: f"\\u{k:04x}" for k in range(32) if not k in (10, 13)}

def escape(s):
    return s.translate(escape_table)

and then

json_string = escape(json_string)

before processing the string further.

Michael Butscher
  • 10,028
  • 4
  • 24
  • 25
0

As @Panagiotis Kanavos suggested in the comments, I removed control characters.

His suggestions were to use the following, where we need to install regex library

# This doesn't work for me, still gave same error
json=text.replace("[\x00-\x1F]+", " ") 

Or

json=regex.sub(r'\p{C}', '', line) # I couldn't install regex package

I used unicodedata library since I was having a problem installing regex having some problem with python3.11.

import unicodedata 
import json

def remove_control_characters(s):      
    return "".join(ch for ch in s if unicodedata.category(ch)[0]!="C")
parsed_json = json.loads(remove_control_characters(json_string))
Akshay Hazari
  • 3,186
  • 4
  • 48
  • 84