使用 BeautifulSoup4 从 html 中检索 JavaScript 字典值



我需要提取网页上的"album_release_date"值。它列在页面上看起来像字典值的脚本标签中,我不确定是否可以使用 bs4 访问它。我能想到的唯一解决方案是使用正则表达式,这是最好的方法吗?

以下是页面源代码的结构:

<script type="text/javascript">
var TralbumData = {
current: {
"upc":null,"title":"BLACK&WHITE MEDICINE","purchase_title":null,
"download_desc_id":null,"minimum_price":0.0,"set_price":7.0,"mod_date":"17 Jun 2018 11:47:50 GMT"
},
album_is_preorder: null,
album_release_date: "17 Jun 2018 00:00:00 GMT",
}
</script>

我已经搜索了所有内容,但除了访问从 bs4 导出的词典之外找不到任何内容。

BS4 解析 HTML,因此您可以使用它来查找此script标记的内容。例如,如果这是页面中唯一的脚本:

script = soup.script.text

但它不解析 JavaScript。

因此,您有以下几种选择:

  • 下载(或编写(一个 JavaScript 解释器,使用它来执行脚本中的代码,然后检查它以查看它放入 JS 全局变量中的变量和值。
  • 下载(或编写(JavaScript 解析器,然后扫描节点以查找您要查找的var语句,并提取和解释其值。
  • 为有限的 JavaScript 子集编写一个解析器来处理这种特定情况,但如果他们稍后重写页面以在script标记中执行完全不同的操作,则会引发一个嘈杂的异常。

你想做哪一个取决于你想完成什么。但我怀疑最后一个是你在这里真正想要的。在这种情况下,不会有任何现成的东西可以为您完成所有工作。但你可以作弊。

您实际上并不需要整个TralbumData值,只需要它album_release_date成员。所以语法可以像这个正则表达式一样简单:

r'album_release_date: "(.*?)"'

所以:

script = soup.script.text
reldatematch = re.search(r'album_release_date: "(.*?)"', script)
if reldatematch:
reldate = your_date_parser_func(reldatematch.group(1))

是否要使其更强大取决于您。

例如,如果您想验证这实际上是TralbumData.album_release_date值,而不仅仅是恰好与album_release_date匹配的东西,那么您想要的语法只是var TralbumData = OBJECT_LITERAL,并且OBJECT_LITERAL几乎是 JSON,除了它有裸键。第一部分,你可以只用字符串方法处理:

empty, lead, literal = script.partition('var TralbumData = ')
if empty or not lead:
raise SomeException

为了解析literal,你可以调整一个JSON解析器,比如pyparsing的JSON示例或stdlib的json模块。或者,或者,您可以做一些黑客的事情,例如预先引用所有密钥,然后json.loads它。

提取脚本内容并使用正则表达式提取对象

from bs4 import BeautifulSoup
import re

html = '''<script type="text/javascript">
var TralbumData = {
current: {
"upc":null,"title":"BLACK&WHITE MEDICINE","purchase_title":null,
"download_desc_id":null,"minimum_price":0.0,"set_price":7.0,"mod_date":"17 Jun 2018 11:47:50 GMT"
},
album_is_preorder: null,
album_release_date: "17 Jun 2018 00:00:00 GMT",
}
</script>'''

pattern = re.compile(r'album_release_date: "(.*?)"', re.MULTILINE)
soup = BeautifulSoup(html, 'html.parser')
script = soup.script.text
release_date = re.search(pattern, script).group(1)
print (release_date)

最新更新