我需要提取网页上的"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)