如何使用 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
模块解析<script>
的内容,然后获取您的值。例如:
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 如何解码 <script> 对象中的 html json 数据
如何使用 Python 和 Beautiful Soup 从框架中抓取信息