【问题标题】:Access deeply nested data inside HTML <script> tag with Python使用 Python 访问 HTML <script> 标记内的深层嵌套数据
【发布时间】:2020-02-25 12:34:13
【问题描述】:

所以我正在尝试从具有深度嵌套的 &lt;script&gt; 标记的站点中获取特定数据。

使用import json,希望尝试使事情变得更容易,导致著名的Expecting value: line 1 column 1 (char 0) 错误。所以,我尝试了以下方法1,但成功率为零。

本质上,连接到站点的相对简单的步骤,捕捉特定的&lt;script&gt;标签是没有问题的。从中获取我需要的数据似乎有问题。

假设以下元素:

script_tag = '''
<script id="startup" type="text/javascript">
$(document).ready(function () {createJsonChart({
"series":[{"name":"BNames","color":"#0043de","legendIndex":0,
"stack":null,
"data":[{"name":"BNames","color":"#0043de","y":0.0,
"legendIndex":0,
"events":{"click":function(){return false;}},
"subtotal":0.0,"displayValue":"0","tooltip":""},
{"name":"BNames","color":"#0043de","y":114.6,
"legendIndex":0,
"events":{"click":function(){return false;}},
"subtotal":0.0,"displayValue":"0",
"tooltip":"BNames: 114,60 % <br/> Month: oktober 2018"},
{"name":"BNames","color":"#0043de","y":108.5,
"legendIndex":0,
"events":{"click":function(){return false;}},
"subtotal":0.0,"displayValue":"0",
"tooltip":"BNames: 108,50 % <br/> Month: september 2019"},
{"name":"BNames","color":"#0043de","y":0.0,
"legendIndex":0,
"events":{"click":function(){return false;}},
"subtotal":0.0,"displayValue":"0","tooltip":""}]},
{"type":"line","marker":{"enabled":false,
"linecolor":null,"lineWidth":0,
"fillColor":null,"symbol":null,"radius":4},
"dashStyle":"Solid","lineWidth":2,
"step":"center","zIndex":"2","name":"Mandatory","color":"#f20808",
"legendIndex":0,"stack":1,
"data":[{"name":"Mandatory","color":"#f20808","y":104.1,
"legendIndex":0,
"events":{"click":function(){return false;}},"subtotal":0.0,"displayValue":"0",
"tooltip":"Mandatory: 104,10 %: 104,10 %"},
{"name":"Mandatory","color":"#f20808","y":104.1,
"legendIndex":0,
"events":{"click":function(){return false;}},
"subtotal":0.0,"displayValue":"0",
"tooltip":"Mandatory: 104,10 %"},
{"name":"Mandatory","color":"#f20808","y":104.1,
"legendIndex":0,
"events":{"click":function(){return false;}},
"subtotal":0.0,"displayValue":"0",
"tooltip":"Mandatory: 104,10 %"}]},
{"type":"line","marker":{"enabled":false,
"linecolor":null,"lineWidth":0,"fillColor":null,
"symbol":null,"radius":4},"dashStyle":"Solid","lineWidth":2,
"step":"center", "zIndex":"2","name":"Preferred","color":"#38d615",
"legendIndex":0,"stack":2,
"data":[{"name":"Preferred","color":"#38d615","y":121.0,
"legendIndex":0,
"events":{"click":function(){return false;}},"subtotal":0.0,"displayValue":"0",
"tooltip":"Preferred: 121,00 %: 121,00 %"},
{"name":"Preferred","color":"#38d615","y":121.0,
"legendIndex":0,
"events":{"click":function(){return false;}},"subtotal":0.0,"displayValue":"0",
"tooltip":"Preferred: 121,00 %"},
{"name":"Preferred","color":"#38d615","y":121.0,
"legendIndex":0,
"events":{"click":function(){return false;}},"subtotal":0.0,"displayValue":"0",
"tooltip":"Preferred: 121,00 %"}]}],
"resizeElement":null,"credits":{"enabled":false}});$('#__Page').lumnaInit('');});
</script>
'''

实际上这个&lt;script&gt; 标签更大。它包含 3 部分数据,此处命名为 BNamesMandatoryPreferred。我需要来自BNames 的数据,特别是最后一个条目。因此,预期结果将来自"tooltip":"BNames: 108,50 % &lt;br/&gt; Month: september 2019"} 部分,其中BNames: 108,50 % 在一个变量中,Month: september 2019 在另一个变量中。

使用正则表达式回答

url_part=soup.find("script", attrs={'id':'startup'}).text
info=re.findall(r'\s\w*\s\d*', url_part)[-1]
result=re.findall(r'(BNames: (\d+[,]\d+\s[%]))', url_part)[-1][1]

首先定义要处理的 HTML 标记。其次,查找所有出现的实例,其中包含任意大小的字母 (\w*),后跟空格 (\s) 和任意大小的数字 (\d*)。这与 2019 年 9 月或 2019 年 8 月之类的任何内容相匹配。最后,查找与 BNames: 匹配的实例以及此设置中的数字:数字、逗号、数字、空格和百分号。因此(\d+[,]\d+\s[%] 这确实匹配从 80,6 % 到 120,05 % 的所有内容

【问题讨论】:

  • 不用深入,用正则搜索脚本标签内的文本,我不喜欢用抓取功能来处理javascript标签,正则表达式更快.我已经在这里回答了这个javascript-scrape

标签: python python-3.x web-scraping beautifulsoup


【解决方案1】:

Beleidsdekkingsgraad 字符串上使用以下正则表达式匹配。 BNames 的想法相同。

import re, requests

r = requests.get('https://www.pensioenfondstno.nl/overons/dekkingsgraad')
p = re.compile(r'"(Beleidsdekkingsgraad:[\s\S]*?)"', re.MULTILINE)
data = p.findall(r.text)[-1].split(' <br/> ')
print(data[0])
print(data[1])

正则表达式:

【讨论】:

  • 好吧,QHarr 非常接近,并且对样本数据非常有效。然而,在实际场景中,它捕获了太多必要的信息。这真的是一件很烦人的事情。所以,按照 Linh Nguyen 的建议,看看正则表达式。所以我做了。最终代码已添加到我的问题中。虽然它不像你的那么整洁,但它确实有效。如果您有任何改进代码的建议,我会全力以赴。
  • 能否提供源码?
  • source url。您应该在此处看到 BNames 为 Beleidsdekkingsgraad 和 Month 在原始设置中为 Periode
  • 你只想要这两个值吗?
  • 正则表达式的强大背后有一些美妙之处。测试它并完美运行。因此接受您的答案作为解决方案。
猜你喜欢
  • 1970-01-01
  • 2020-12-15
  • 1970-01-01
  • 1970-01-01
  • 2022-01-18
  • 1970-01-01
  • 2021-10-04
  • 2021-10-08
  • 2021-12-20
相关资源
最近更新 更多