Python在HTML中查找JSON并获取select值

2024-09-30 01:21:12 发布

您现在位置:Python中文网/ 问答频道 /正文

嘎。我花了相当长的时间试图找到如何正确地,甚至粗鲁地做这件事,我只是被难住了。我从一个站点下载了2500多个HTML文件,我只需要从任何给定的页面提取有限的信息:页面描述的演讲标题(这样我就可以用我们已经拥有的一个巨大的CSV来整理这些数据),然后是给定演讲的事件,以及演讲发表的日期。在

这些页面的HTML是扩展的,并且填充了<script>元素。我只想要后面跟q的那个。开始此块的行如下所示:

<script>q("talkPage.init", {

下面是相当多的数据。我只需要这三样东西:

^{pr2}$

幸运的是,"filmed"和{}在这个大的块中只出现一次,但是{}出现了好几次。它总是一样的,所以我不在乎这些脚本中的哪一个。在

我的想法是使用BeautifulSoup来找到<script>q元素,然后将其传递到json模块进行解析,但是我无法找到hot-tellsoup来获取<script>元素,然后再加上一个q——类和id很容易。然后。。。没那么多。在

为了开始处理JSON部分,我创建了一个文本文件,其中只包含<script>q元素的内容,但是我承认让JSON模块来加载它并不是很好。在

我为实验准备的代码首先用我感兴趣的JSON块加载文本文件,然后尝试对其进行解码,以便我可以使用它执行其他操作:

import json

text = open('dawkins_script_element.txt', 'r').read()
data = json.loads(text)

但是很明显JSON解码器不喜欢我所拥有的,因为它抛出了一个ValueError: Expecting value: line 1 column 1 (char 0)。呸!在

此脚本元素的前三行如下所示:

<script>q("talkPage.init", {
"el": "[data-talk-page]",
"__INITIAL_DATA__":

这就是我目前的处境。如果能给json提供帮助,我们将不胜感激。在


Tags: 模块数据text脚本json元素datainit
3条回答

这是我最后使用的脚本,感谢@Idlehands和@Three。为了深入研究奇怪的单引号JSON,我将整个JSON元素读入一个列表中,并用逗号分隔。这是一个黑客,但基本上是有效的。在

def get_metadata(the_file):

    # Load the modules we need
    from bs4 import BeautifulSoup
    import json
    import re
    from datetime import datetime

    # Read the file, load it into BS, then grab section we want
    text = the_file.read()
    soup = BeautifulSoup(text, "html5lib")
    my_list = [i.string.lstrip('q("talkPage.init", {\n\t"el": "[data-talk-page]",\n\t "__INITIAL_DATA__":')
               .rstrip('})')
               for i in soup.select('script') 
               if i.string and i.string.startswith('q')]

    # Read first layer of JSON and get out those elements we want
    pre_json = '{"' + "".join(my_list)
    my_json = json.loads(pre_json)
    slug = my_json['slug']
    vcount = my_json['viewed_count']
    event = my_json['event']

    # Read second layer of JSON and get out listed elements:
    properties = "filmed,published" # No spaces between terms!
    talks_listed = str(my_json['talks']).split(",")
    regex_list = [".*("+i+").*" for i in properties.split(",")]
    matches = []
    for e in regex_list:
        filtered = filter(re.compile(e).match, talks_listed)
        indexed = "".join(filtered).split(":")[1]
        matches.append(indexed)
    filmed = datetime.utcfromtimestamp(float(matches[0])).strftime('%Y-%m-%d')
    # published = datetime.utcfromtimestamp(float(matches[1])).strftime('%Y-%m-%d')
    return slug, vcount, event, filmed, #published

在不了解全部情况的情况下,有一个穷人的尝试:

假设您的html如下所示:

<script>foo</script>
<script>bar</script>
<script>q("talkPage.init",{
"foo1":"bar1",
"event":"TEDGlobal 2005",
"filmed":1120694400,
"published":1158019860,
"foo2":"bar2"
})</script>
<script>q("talkPage.init",{
"foo1":"bar1",
"event":"foobar",
"filmed":123,
"published":456,
"foo2":"bar2"
})</script>
<script>foo</script>
<script>bar</script>

您可以这样编写代码:

^{pr2}$

然后您可以开始解释JSON:

print(my_jsons[0]['event'])
print(my_jsons[0]['filmed'])
print(my_jsons[0]['published'])

# Output:
# TEDGlobal 2005
# 1120694400
# 1158019860

这里有很多假设。假设<script>q元素中的所有文本始终以q("talkPage.init",开头,以)结尾。它还假设返回的文本遵循json格式,以便下一阶段的解析。我还假设您了解如何解析json结果。在

可以使用正则表达式匹配所需的部分。在

import re
# Filters the script-tag all the way to end ')' of q.
scipt_tag = re.findall(r'<script>q\((?s:.+)\)', t)
json_content = re.search(r'(?<=q\()(?s:.+)\)', script_tag[0]).group()
json_content = json_content[:-1]  # Strip last ')'

要找到您需要的东西,您可以使用pythons json库来解析它,或者将最后的东西与您想要的匹配。因为filmed和{}是唯一的,event没有区别(据我所知?)在

^{pr2}$

def get_val(a):
re.search('r(?<=' + a + r'\": )(.+)').group(0)

后者需要过滤一点,以除去尾随的]"和前面的{},或者您不希望从中得到的内容。在

我听说beauthoulsoup也是一个很好的匹配html的库,但是我不太熟悉它。在

相关问题 更多 >

    热门问题