如何使用 Beautiful Soup 从 <script> 中提取内容

Posted

技术标签:

【中文标题】如何使用 Beautiful Soup 从 <script> 中提取内容【英文标题】:How to extract content from <script> using Beautiful Soup 【发布时间】:2020-05-04 18:37:34 【问题描述】:

我正在尝试从此处脚本标签中的代码中提取campaign_hearts 和postal_code(整个代码太长,无法发布):

<script>
...    
"campaign_hearts":4817,"social_share_total":11242,"social_share_last_update":"2020-01-17T10:51:22-06:00","location":"city":"Los Angeles, CA","country":"US","postal_code":"90012","is_partner":false,"partner":,"is_team":true,"team":"name":"Team STEVENS NATION","team_pic_url":"https://d2g8igdw686xgo.cloudfront.net
...

我可以使用以下代码识别我需要的脚本:

from bs4 import BeautifulSoup
import numpy as np
import pandas as pd
from time import sleep
import requests 
import re
import json


page = requests.get("https://www.gofundme.com/f/eric-stevens-care-trust")

soup = BeautifulSoup(page.content, 'html.parser')

all_scripts = soup.find_all('script')
all_scripts[0]

但是,我不知道如何提取我想要的值。 (我对 Python 很陌生。) This thread 为类似问题推荐了以下解决方案(经过编辑以反映我正在使用的 html)。

data = json.loads(all_scripts[0].get_text()[27:])

但是,运行它会产生错误:JSONDecodeError: Expecting value: line 1 column 1 (char 0).

既然我已经识别了正确的脚本,我可以做些什么来提取我需要的值?我也尝试过here 列出的解决方案,但在导入 Parser 时遇到了问题。

【问题讨论】:

【参考方案1】:

您可以使用json 模块解析&lt;script&gt; 的内容,然后获取您的值。例如:

import re
import json
import requests

url = 'https://www.gofundme.com/f/eric-stevens-care-trust'

txt = requests.get(url).text

data = json.loads(re.findall(r'window\.initialState = (.*?);', txt)[0])

# print( json.dumps(data, indent=4) )  # <-- uncomment this to see all data

print('Campaign Hearts =', data['feed']['campaign']['campaign_hearts'])
print('Postal Code     =', data['feed']['campaign']['location']['postal_code'])

打印:

Campaign Hearts = 4817
Postal Code     = 90012

【讨论】:

从来不知道这种加载 JSON 的方式。惊人的! :) re.findall()[0] 不只是re.search() @AMC 可以写成re.search(r'window\.initialState = (.*?);', txt).group(1)re.search(..)[1]。这只是口味问题。 只是口味问题。只是有点,因为.findall()会得到每一个匹配项,不管它是否被丢弃。【参考方案2】:

你使用的库越多;代码效率越低!这是一个更简单的解决方案-

#This imports the website content.

import requests
url = "https://www.gofundme.com/f/eric-stevens-care-trust"
a = requests.post(url)
a= (a.content)
print(a)

#These will show your data.

campaign_hearts = str(a,'utf-8').split('campaign_hearts":')[1]
campaign_hearts = campaign_hearts.split(',"social_share_total"')[0]
print(campaign_hearts)

postal_code = str(a,'utf-8').split('postal_code":"')[1]
postal_code = postal_code.split('","is_partner')[0]
print(postal_code)   

【讨论】:

只是补充一点:我不会说代码变得不那么“高效”,因为在谈论效率时通常暗示 speed 效率,这里不是这样。但它会变得不那么直截了当,因为它增加了理解更多不同库的需要。 是的。我的意思是当工作可以用时间石完成时,你不需要整个无限手套哈哈 :) 确实如此 :) 我很好奇,你为什么使用 POST 请求? 说到效率,如果 OP 想要整个 JSON 内容怎么办?【参考方案3】:

您的json.loads 因最后一个分号而失败。如果您使用正则表达式仅提取对象字符串(不包括最后的分号),它将起作用。

from bs4 import BeautifulSoup
import numpy as np
import pandas as pd
from time import sleep
import requests 
import re
import json



page = requests.get("https://www.gofundme.com/f/eric-stevens-care-trust")

soup = BeautifulSoup(page.content, 'html.parser')

all_scripts = soup.find_all('script')
txt = all_scripts[0].get_text()
data = json.loads(re.findall(r'window\.initialState = (.*?);', txt)[0])

【讨论】:

【参考方案4】:

现在应该没问题,我可能会尝试编写一个纯 lxml 版本或至少改进元素的搜索。

此解决方案使用正则表达式仅获取 JSON 数据,不使用 window.initialState = 和分号。

import json
import re

import requests
from bs4 import BeautifulSoup

url_1 = "https://www.gofundme.com/f/eric-stevens-care-trust"

req = requests.get(url_1)

soup = BeautifulSoup(req.content, 'lxml')

script_tag = soup.find('script')

raw_json = re.fullmatch(r"window\.initialState = (.+);", script_tag.text).group(1)

json_content = json.loads(raw_json)

【讨论】:

以上是关于如何使用 Beautiful Soup 从 <script> 中提取内容的主要内容,如果未能解决你的问题,请参考以下文章

使用 Beautiful Soup 从非类部分获取数据

Beautiful Soup 的使用

Beautiful Soup 如何解码 <script> 对象中的 html json 数据

如何使用 Python 和 Beautiful Soup 从框架中抓取信息

如何使用涉及html表的Beautiful Soup从页面中抓取产品信息[关闭]

从解析的 Beautiful Soup 列表中删除 <br> 标签?