Beautiful Soup 如何解码 <script> 对象中的 html json 数据
Posted
技术标签:
【中文标题】Beautiful Soup 如何解码 <script> 对象中的 html json 数据【英文标题】:Beautiful Soup how to decode html json data in <script> object 【发布时间】:2020-09-19 11:00:04 【问题描述】:我从发布简短新闻更新的网站收集文本。最近该网站的前端进行了升级,现在使用 Angular。历史文档加载到新 Angular“新闻”页面的元素中。
此脚本元素中的数据是以 html 格式存储为 JSON。它以我不熟悉的格式编码。我一直无法解码它。但是,Chrome 浏览器会解释元素中的元素。
从存储每个旧文档的元素中提取如下所示:
<script id="ng-agritown-state" type="application/json">
&q;G.api_endpoint/api/v12/pages?parameters=newsId%3D343436565656&a;path=news-article&q;:&q;body&q;:&q;id&q;:&q;8&q;,&q;layout&q;:&q;onecol&q;,&q;info&q;:&q;title&q;:&q;News article&q;
...
&q;&g;&l;span class=\&q;z\&q;&g;Record harvest 2020&l;/span&g;&l;/p&g;\n&l;p class=\&q;a\&q;&g;&l;span class=\&q;z\&q;&g;We are pleased to announce a record harvest in this current
...
&q;isDataComponentAndIsAvailable&q;:true,&q;status&q;:&q;refreshedTime&q;:1590993288947,&q;childComponents&q;:[],&q;params&q;:&q;updates&q;:null,&q;cloneFrom&q;:null,&q;encoder&q;:,&q;map&q;:null]
</script>
任何人都可以识别这种编码格式吗?如何使用 Python / Beautiful Soup 对其进行解码?
【问题讨论】:
如果您有一个指向包含这种编码类型的在线页面的链接,也许可以多说一些。就目前而言,它看起来像是 HTML 实体的某种简写(即&q;
而不是 &quote;
),但目前尚不清楚在没有上下文的情况下如何甚至为什么会起作用。你说你是从一个网站上得到这个的,也许分享一个链接?
文档示例如下页所示。我对实际新闻的缩进部分感兴趣。 londonstockexchange.com/news-article/RGD/…
脚本 id 中的 "ng-
已经暴露了一点:编码是 Angular 对 html 的自定义编码。由于您关注的是整篇文章的内容,因此无法进行简单的搜索和替换——您需要找到一种方法让 Angular 为您解码。最简单的方法可能是让 Python 加载支持 javascript 的引擎,并简单地让它呈现您在浏览器中看到的 html,然后使用 Python 访问生成的文档,就像使用 Selenium 或 PyV8 一样。不过,这些都是繁重的解决方案,如果您需要频繁或轻微地运行此脚本,请不要使用它们。
【参考方案1】:
与我的评论一致:脚本 id 中的 "ng-
已经泄露了它:编码是 Angular 对 HTML 的自定义编码。由于您关注的是整篇文章的内容,因此无法进行简单的搜索和替换——您需要找到一种方法让 Angular 为您解码。
最简单的方法可能是让 Python 加载一个支持 JavaScript 的引擎,让它渲染出您在浏览器中看到的 HTML,然后使用 Python 访问生成的文档,例如使用 Selenium 或 PyV8。不过,这些都是繁重的解决方案,如果您需要频繁运行此脚本或使用少量资源,请不要使用它们。
以下代码使用 Selenium,通过以下方式准备您的虚拟环境:
安装硒pip install selenium
安装适当的浏览器驱动程序,在本例中为 ChromeDriver,从此处:https://sites.google.com/a/chromium.org/chromedriver/home(我只是将可执行文件放在我的脚本文件夹中,在 Windows 上)
运行这个:
from selenium import webdriver
driver = webdriver.Chrome()
driver.get("https://www.londonstockexchange.com/news-article/RGD/year-end-trading-and-covid-19-update/14495760")
elem = driver.find_element_by_class_name('news-article-content-body')
print(elem.text)
当然,只要您也获得了驱动程序,您也可以让它与其他支持的浏览器一起使用。它在其他操作系统上的工作方式类似。
如果您确实需要经常运行,有办法让 Selenium 在服务器上运行以更快地创建会话并重复呈现页面,但这远远超出了 *** 的单一答案。
【讨论】:
【参考方案2】:此内容似乎是自定义编码的。你可以试试简单的str.replace
:
txt = r'''<script id="ng-agritown-state" type="application/json">
&q;G.api_endpoint/api/v12/pages?parameters=newsId%3D343436565656&a;path=news-article&q;:&q;body&q;:&q;id&q;:&q;8&q;,&q;layout&q;:&q;onecol&q;,&q;info&q;:&q;title&q;:&q;News article&q;
...
&q;&g;&l;span class=\&q;z\&q;&g;Record harvest 2020&l;/span&g;&l;/p&g;\n&l;p class=\&q;a\&q;&g;&l;span class=\&q;z\&q;&g;We are pleased to announce a record harvest in this current
...
&q;isDataComponentAndIsAvailable&q;:true,&q;status&q;:&q;refreshedTime&q;:1590993288947,&q;childComponents&q;:[],&q;params&q;:&q;updates&q;:null,&q;cloneFrom&q;:null,&q;encoder&q;:,&q;map&q;:null]
</script>'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(txt, 'html.parser')
print( soup.script.contents[0].replace('&l;', '<').replace('&g;', '>').replace('&q;', '"') )
打印:
"G.api_endpoint/api/v12/pages?parameters=newsId%3D343436565656&a;path=news-article":"body":"id":"8","layout":"onecol","info":"title":"News article"
...
"><span class=\"z\">Record harvest 2020</span></p>\n<p class=\"a\"><span class=\"z\">We are pleased to announce a record harvest in this current
...
"isDataComponentAndIsAvailable":true,"status":"refreshedTime":1590993288947,"childComponents":[],"params":"updates":null,"cloneFrom":null,"encoder":,"map":null]
然后json
/re
模块对信息进行解码。
【讨论】:
这种工作。数据太脏,无法将其转换回 JSON 对象,但它为数据提供了足够的结构来使用正则表达式提取 html。谢谢。以上是关于Beautiful Soup 如何解码 <script> 对象中的 html json 数据的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Beautiful Soup 从 <script> 中提取内容
如何通过 Beautiful Soup 刮掉href中的文本?