BeautifulSoup извлекает данные из <script>с помощью юникода - PullRequest
0 голосов
/ 21 февраля 2020

Я пытаюсь разобрать JSON в скрипте страницы html.

import requests
from bs4 import BeautifulSoup
import json

headers = {
    "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36 OPR/64.0.3417.47",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
    "Accept-Language": "fr-FR,en;q=0.5",
    "Accept-Encoding": "gzip, deflate",
    "Connection": "keep-alive",
    "Cache-Control": "max-age=0",
    "Upgrade-Insecure-Requests": "1",
}

proxy = "http://stack:overflow@45.135.149.142:14758"

url = "https://www.seloger.com/list.htm?projects=2%2C5&types=2%2C1&natures=1%2C2%2C4&places=%5B%7Bci%3A60088%7D%5D&enterprise=0&qsVersion=1.0"
r = requests.get(url, proxies={"http": proxy, "https": proxy}, headers=headers)
soup = BeautifulSoup(r.text, 'html.parser')
for script in soup.find_all('script'):
    if "initialData" in script.text:
        data = script.text.split('JSON.parse("', 1)[1].split('");window["tags"]', 1)[0]
        json_data = json.loads(data)

И эта ошибка возвращается:

json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)

Проблема в том, что \ u0022 не преобразуется в кавычку ", которая вызывает ошибку декодера json.

Кроме того, всякий раз, когда я печатаю код сценария, вместо u выводится \ u0022". Я уже пробовал кодирование и декодирование в нескольких форматах, прежде чем передать его json .loads, но ничего не получилось.

Эта проблема возникает только тогда, когда код анализируется непосредственно из ответа на запрос. Я не могу повторить проблему. Этот код работает должным образом:

snippet = '''<script>
window["initialData"] = JSON.parse("{\u0022foo\u0022:\u0022bar\u0022,\u0022xxx\u0022:\u0022xyz\u0022}")
</script>
'''
soup = BeautifulSoup(snippet, 'html.parser')
for script in soup.find_all('script'):
    data = script.text.split('JSON.parse("')[1].split('")')[0]
    json_data = json.loads(data)
    print(json_data)
    # output : {'foo': 'bar', 'xxx': 'xyz'}

Как я могу это исправить?

Ответы [ 3 ]

1 голос
/ 21 февраля 2020

Вы можете сделать это с помощью регулярных выражений (не лучшим образом), но у меня это сработало:

import requests,json,re
proxy='http://stack:overflow@45.135.149.142:14758'
url='https://www.seloger.com/list.htm?projects=2%2C5&types=2%2C1&natures=1%2C2%2C4&places=%5B%7Bci%3A60088%7D%5D&enterprise=0&qsVersion=1.0'
r = requests.get(url, proxies={"http": proxy, "https": proxy})
json_data = json.loads(json.loads('"' + re.search(r'JSON\.parse\("(.+)"\);w', r.text).group(1) + '"')) # note it needs to be double wrapped
json_data.keys()
# dict_keys(['cards', 'navigation', 'SEO', 'tracking', 'adverts', 'bookmarks', 'failure', 'engine'])
1 голос
/ 21 февраля 2020

Содержимое, которое вы пытаетесь очистить, включает escape-последовательности Юникода, которые, по-видимому, на самом деле экранированы сами.

Решение, которое я нашел, включает кодирование и затем декодирование строки, хотя может быть лучший способ :

data.encode("utf-8").decode("unicode-escape")

Я также сделал некоторые другие изменения в вашем коде, особенно в том, как анализируются данные, которые можно увидеть в этом фрагменте, который я использовал в качестве демонстрации / теста:

json_re = re.compile(r"window\[\"initialData\"] = JSON\.parse\(\"(.*)\"\);window\[\"tags\"]")

with open("../out/temp.html", 'rb') as file_in:
    soup = BeautifulSoup(file_in.read(), 'lxml')

raw_data = ""
for script in soup.find_all('script'):
    if "initialData" in script.text:
        res_text = script.get_text(strip=True)
        raw_data = json_re.search(res_text).group(1)
        break

print(raw_data)
t_1 = raw_data.encode("utf-8")
print(t_1)

t_2 = t_1.decode("unicode-escape")
print(t_2)

t_3 = json.loads(t_2)
print(t_3)
0 голосов
/ 21 февраля 2020

Возможно, проблема в шаге разбиения, но у меня были похожие проблемы с json и кодировками. Попробуйте перекодировать response.text с помощью «utf-8» или «latin». Несколько раз это работало для меня. Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...