Это очень хакерский подход, но, похоже, он работает ...
Из проверки данных кажется, что сервер возвращает эквивалент словаря Python, который был преобразован в строку, например
>>> s = str({'a': 'b'})
>>> s
"{'a': 'b'}"
Обычный способ извлечения словаря из строки - использовать ast.literal_eval , но ast.literal_eval
не может оценить строку (она не работает с ValueError: malformed node or string: <_ast.Name object at 0x7f719518c7b8>
) *.
Тем не менее, похоже, что в строковом словаре есть только два ключа: isSuccess и content.Интерес представляет только значение «content», поэтому мы можем извлечь его из строки.
quoted = re.sub(r'\{.*content:', '', html.text[:-1])
quoted
выглядит так:
quoted[:20]
"'%3Cul%3E%3Cli%3E%3C"
Это выглядит так, как будто оно содержит% -кодированный текст.Это может быть декодировано с использованием urllib.parse.unquote :
unquoted = urllib.parse.unquote(quoted)
unquoted
выглядит как
unquoted[:60]
'\'<ul><li><table><tr><td><img id="3383" title="%u54C1%u724CX"'
Это выглядит лучше, но выглядит так, как будтодолжны быть экранированными в Unicode символьными последовательностями, где "%" должно быть "\".Давайте попробуем заменить "%" на обратную косую черту, когда за ней следуют "и" и четыре шестнадцатеричных символа.
replaced = re.sub(r'(%)(u[A-Fa-f0-9]{4})', r'\\\g<2>', unquoted)
replaced[:60]
'\'<ul><li><table><tr><td><img id="3383" title="\\u54C1\\u724CX"'
Это почти правильно, но двойную обратную косую черту необходимо удалить.Кодирование текста в формате latin-1 сохранит все байты, затем декодирование с помощью кодека 'unicode-escape' удалит лишние обратные слеши.
markup = replaced.encode('latin-1').decode('unicode-escape')
markup[:60]
'\'<ul><li><table><tr><td><img id="3383" title="品牌X" src="http'
Это выглядит достаточно хорошо, чтобы перейти к BeautifulSoup.
soup = bs4.BeautifulSoup(markup)
soup.find("div", {"class": "con"})
<div class="con"><img src="/public/static/images/icons/g-gas.png"/> 废气<br/>● 环境违规事项:工业废气污染源;<br/>● 潜在影响:空气质量、公众健康。</div>
* Мне было бы интересно узнать , почему ast.literal_eval
не может разобрать строковый диктат.