Python 屏幕根据对应span中的其他文本值从span中刮取文本值,并使用beautiful soup

Python 屏幕根据对应span中的其他文本值从span中刮取文本值,并使用beautiful soup,python,python-3.x,beautifulsoup,python-requests,css-selectors,Python,Python 3.x,Beautifulsoup,Python Requests,Css Selectors,我有一些漂亮的代码,如下面的示例代码。我用它来筛选雅虎财经关于共同基金的财务数据。在这段代码中,我试图获取“债券评级”百分比,并将其保存在字典中。我一直试图根据span class=“Fl(end)”选择元素值,但我发现它错误地将一些共同基金的文本拉到了“AAA”值。我想知道是否有办法提取百分比的文本值,可能在跨度之间使用债券名称文本,例如美国政府从相应的0.00%中获取0.00% 下面是一些示例代码、示例数据和所需输出 代码: 靓汤样品: URL='https://finance.yahoo.

我有一些漂亮的代码,如下面的示例代码。我用它来筛选雅虎财经关于共同基金的财务数据。在这段代码中,我试图获取“债券评级”百分比,并将其保存在字典中。我一直试图根据span class=“Fl(end)”选择元素值,但我发现它错误地将一些共同基金的文本拉到了“AAA”值。我想知道是否有办法提取百分比的文本值,可能在跨度之间使用债券名称文本,例如美国政府从相应的0.00%中获取0.00%

下面是一些示例代码、示例数据和所需输出

代码:

靓汤样品:

URL='https://finance.yahoo.com/quote/TRARX/holdings?p=TRARX'

req = requests.get(URL)

soup = bs(req.text)

soup
数据:


更新:我正在运行beautifulsoup4 4.6.3

您可以使用以下
css选择器
来识别父标签和子标签

from bs4 import BeautifulSoup
import requests

bond_rating_list=['us_government_bond_perc',
        'AAA_bond_perc',
        'AA_bond_perc',
        'A_bond_perc',
        'BBB_bond_perc',
        'BB_bond_perc',
        'B_bond_perc',
        'below_B_bond_perc',
        'others_bond_perc']

bond_rating_dct={}
URL='https://finance.yahoo.com/quote/TRARX/holdings?p=TRARX'
req = requests.get(URL)
soup=BeautifulSoup(req.text,'html.parser')
childelements=soup.select("div[class^='Mb']:contains('Bond Ratings') span[class^='Fl'][class*='end']")
for n in range(len(childelements)):
    bond_rating_dct[bond_rating_list[n]]=childelements[n].text

print(bond_rating_dct)
from bs4 import BeautifulSoup
import requests
import re

bond_rating_list=['us_government_bond_perc',
        'AAA_bond_perc',
        'AA_bond_perc',
        'A_bond_perc',
        'BBB_bond_perc',
        'BB_bond_perc',
        'B_bond_perc',
        'below_B_bond_perc',
        'others_bond_perc']

bond_rating_dct={}
URL='https://finance.yahoo.com/quote/TRARX/holdings?p=TRARX'
req = requests.get(URL)
soup=BeautifulSoup(req.text,'html.parser')
parentele=soup.find(text=re.compile('Bond Ratings')).find_previous('div')
childelements=parentele.select("span[class^='Fl'][class*='end']")
for n in range(len(childelements)):
    bond_rating_dct[bond_rating_list[n]]=childelements[n].text

print(bond_rating_dct)
输出:

{'AAA_bond_perc': '50.23%', 'AA_bond_perc': '3.20%', 'others_bond_perc': '3.40%', 'below_B_bond_perc': '2.32%', 'BBB_bond_perc': '15.75%', 'B_bond_perc': '8.71%', 'BB_bond_perc': '8.08%', 'A_bond_perc': '8.31%', 'us_government_bond_perc': '0.00%'}

您可以使用regex
re
查找父标记,然后查找子标记

from bs4 import BeautifulSoup
import requests

bond_rating_list=['us_government_bond_perc',
        'AAA_bond_perc',
        'AA_bond_perc',
        'A_bond_perc',
        'BBB_bond_perc',
        'BB_bond_perc',
        'B_bond_perc',
        'below_B_bond_perc',
        'others_bond_perc']

bond_rating_dct={}
URL='https://finance.yahoo.com/quote/TRARX/holdings?p=TRARX'
req = requests.get(URL)
soup=BeautifulSoup(req.text,'html.parser')
childelements=soup.select("div[class^='Mb']:contains('Bond Ratings') span[class^='Fl'][class*='end']")
for n in range(len(childelements)):
    bond_rating_dct[bond_rating_list[n]]=childelements[n].text

print(bond_rating_dct)
from bs4 import BeautifulSoup
import requests
import re

bond_rating_list=['us_government_bond_perc',
        'AAA_bond_perc',
        'AA_bond_perc',
        'A_bond_perc',
        'BBB_bond_perc',
        'BB_bond_perc',
        'B_bond_perc',
        'below_B_bond_perc',
        'others_bond_perc']

bond_rating_dct={}
URL='https://finance.yahoo.com/quote/TRARX/holdings?p=TRARX'
req = requests.get(URL)
soup=BeautifulSoup(req.text,'html.parser')
parentele=soup.find(text=re.compile('Bond Ratings')).find_previous('div')
childelements=parentele.select("span[class^='Fl'][class*='end']")
for n in range(len(childelements)):
    bond_rating_dct[bond_rating_list[n]]=childelements[n].text

print(bond_rating_dct)

两个脚本都返回相同的输出。

为了更健壮一点,我希望不再使用类,因为类往往是动态的,而是使用元素之间的关系。我仍然使用
:contains
来锚定
h3

我添加了
会话
,以提高tcp重复使用的效率。我还重新考虑了代码以使用一个函数,该函数将符号作为参数并返回所需的字典;为了便于代码重用

在这里,我使用映射字典来生成所需的键,如果该表中出现新元素,则可以扩展这些键

from bs4 import BeautifulSoup as bs
import requests

def get_dict(symbol):
    bond_ratings = {}
    r = s.get(f'https://finance.yahoo.com/quote/{symbol}/holdings?p={symbol}')
    soup = bs(r.content, 'lxml') # html.parser
    
    for i in soup.select('div:has(> h3:contains("Bond Ratings")) [class]:nth-child(n+2)'):
        for j in i.select_one('span'):
            bond_ratings[mappings[j.span.text]] = j.parent.next_sibling.text
    return bond_ratings

mappings = { 
        'US Government': 'us_government_bond_perc',
        'AAA': 'AAA_bond_perc',
        'AA': 'AA_bond_perc',
        'A': 'A_bond_perc',
        'BBB': 'BBB_bond_perc',
        'BB': 'BB_bond_perc',
        'B': 'B_bond_perc',
        'Below B': 'below_B_bond_perc',
        'Others': 'others_bond_perc'
}

symbols = ['TRARX', 'FLCEX']

with requests.Session() as s:    
    for symbol in symbols:
        bond_rating_dct = get_dict(symbol)
        print(bond_rating_dct)

如果您决定在输出字典键中更加一致,并且不介意检索具有%s的所有项,则可以删除映射并使用以下方法:

from bs4 import BeautifulSoup as bs
import requests

def get_dict(symbol):
    bond_ratings = {}
    r = s.get(f'https://finance.yahoo.com/quote/{symbol}/holdings?p={symbol}')
    soup = bs(r.content, 'lxml') # html.parser
    
    for i in soup.select('div:has(> h3:contains("Bond Ratings")) [class]:nth-child(n+2)'):
        for j in i.select_one('span'):
            bond_ratings[j.span.text.replace(' ','_').lower() + '_bond_perc'] = j.parent.next_sibling.text
    return bond_ratings

symbols = ['TRARX', 'FLCEX']

with requests.Session() as s:   
    for symbol in symbols:
        bond_rating_dct = get_dict(symbol)
        print(bond_rating_dct)

在您提供的页面上显示
AAA
为0.00%。我怎样才能得到50.23的值?@Parzival谢谢你指出这一点。很抱歉,我最初在文章顶部发布了错误的url。我已将其更新为与最后列出的url相匹配。谢谢您的建议。我在运行你的代码时遇到这个错误,我认为这与我的beautifulsoup版本有关。如果使用已安装的其他模块升级beautifulsoup版本,可能会出现问题。错误:“NotImplementedError:仅实现以下伪类:类型的第n个。”谢谢。当我尝试你的建议时,我得到了下面的错误。这似乎与我的beautifulsoup4版本5.6.3有关。您知道如何修改您的代码以使用我的soup版本吗?错误:“NotImplementedError:仅实现以下伪类:类型的第n个。”我强烈建议将bs4(4.9.3)/SoupSive(2.2.1)升级到最新版本。在以后的版本中有更多的功能和改进。AFAIK没有5.6.3版本。重新编写可能会失去我试图构建的一些健壮性。对不起,我是说4.6.3。我一直在尝试用anaconda进行更新,或者安装一个新版本,但它似乎有问题。你知道如何用anaconda将其更新到新版本吗?我正在ubuntu服务器上运行它。恐怕我没有,但希望你能得到你最新问题的答案。
from bs4 import BeautifulSoup as bs
import requests

def get_dict(symbol):
    bond_ratings = {}
    r = s.get(f'https://finance.yahoo.com/quote/{symbol}/holdings?p={symbol}')
    soup = bs(r.content, 'lxml') # html.parser
    
    for i in soup.select('div:has(> h3:contains("Bond Ratings")) [class]:nth-child(n+2)'):
        for j in i.select_one('span'):
            bond_ratings[j.span.text.replace(' ','_').lower() + '_bond_perc'] = j.parent.next_sibling.text
    return bond_ratings

symbols = ['TRARX', 'FLCEX']

with requests.Session() as s:   
    for symbol in symbols:
        bond_rating_dct = get_dict(symbol)
        print(bond_rating_dct)