【问题标题】:Scraping data from Morningstar using an API使用 API 从 Morningstar 抓取数据
【发布时间】:2021-11-16 16:43:45
【问题描述】:

我有一个非常具体的问题,我无法找到解决方案。 最近,我开始了一个项目,根据从晨星获得的特定数据,我正在监控大约 100 只 ETF 和共同基金。当前的解决方案效果很好 - 但后来我发现我需要来自网站内另一个“选项卡”的更多数据。具体来说,我正在尝试从以下网站的第一个表中获取数据:https://www.morningstar.dk/dk/funds/snapshot/snapshot.aspx?id=F00000Z1MC&tab=1

现在,我有下面的代码,用于从网站上的“Indhold”选项卡中的表格中抓取数据,并将其导出到 Excel。因此,我的问题是:如何调整代码以从网站的另一部分抓取数据?

简要解释代码并重申:下面的代码从同一网站的另一个标签中抓取数据。很多很多的 ID 用于代表每个共同基金/ETF 的每个网站。设置工作得很好,所以我希望简单地调整它(如果可能的话)以从上面的链接中提取表格。我对该主题的了解非常有限,因此非常感谢任何帮助。

import requests
import re
import pandas as pd
from openpyxl import load_workbook

auth = 'https://www.morningstar.dk/Common/funds/snapshot/PortfolioSAL.aspx'

# Create a Pandas Excel writer using XlsxWriter as the engine.
path= r'/Users/karlemilthulstrup/Downloads/data2.xlsm'
book = load_workbook(path ,read_only = False, keep_vba=True)
writer = pd.ExcelWriter(path, engine='openpyxl')
writer.book = book

ids = ['F00000VA2N','F0GBR064OO','F00000YKC2','F000015MVX','F0000020YA','0P00015YTR','0P00015YTT','F0GBR05V8D','F0GBR06XKI','F000013CKH','F00000MG6K','F000014G49',
'F00000WC0Z','F00000QSD2','F000016551','F0000146QH','F0000146QI','F0GBR04KZS','F0GBR064VU','F00000VXLM','F0000119R1','F0GBR04L4T','F000015CS3','F000015CS5','F000015CS6',
'F000015CS4','F000013BZE','F0GBR05W0Q','F000016M1C','F0GBR04L68','F00000Z9T9','F0GBR04JI8','F00000Z9TG','F0GBR04L2P','F000014CU8','F00000ZG2G','F00000MLEW',
'F000013ZOY','F000016614','F00000WUI9','F000015KRL','F0GBR04LCR','F000010ES9','F00000P780','F0GBR04HC3','F000015CV6','F00000YWCK','F00000YWCJ','F00000NAI5',
'F0GBR04L81','F0GBR05KNU','F0GBR06XKB','F00000NAI3','F0GBR06XKF','F000016UA9','F000013FC2','F000014NRE','0P0000CNVT','0P0000CNVX','F000015KRI',
'F000015KRG','F00000XLK7','F0GBR04IDG','F00000XLK6','F00000073J','F00000XLK4','F000013CKG','F000013CKJ','F000013CKK','F000016P8R','F000016P8S','F000011JG6',
'F000014UZQ','F0000159PE','F0GBR04KZG','F0000002OY','F00000TW9K','F0000175CC','F00000NBEL','F000016054','F000016056','F00000TEYP','F0000025UI','F0GBR04FV7',
'F00000WP01','F000011SQ4','F0GBR04KZO','F000010E19','F000013ZOX','F0GBR04HD7','F00000YKC1','F0GBR064UG','F00000JSDD','F000010ROF','F0000100CA','F0000100CD',
'FOGBR05KQ0','F0GBR04LBB','F0GBR04LBZ','F0GBR04LCN','F00000WLA7','F0000147D7','F00000ZB5E','F00000WC0Y']
headers = {'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Mobile Safari/537.36'}
payload = {
'languageId': 'da-DK',
'locale': 'da-DK',
'clientId': 'MDC_intl',
'benchmarkId': 'category',
'component': 'sal-components-mip-factor-profile',
'version': '3.40.1'}

for api_id in ids:
    payload = {
        'Site': 'dk',
        'FC': '%s' %api_id,
        'IT': 'FO',
        'LANG': 'da-DK',}
    
    response = requests.get(auth, params=payload)
    
    search = re.search('(tokenMaaS:[\w\s]*\")(.*)(\")', response.text, re.IGNORECASE)
    bearer = 'Bearer ' + search.group(2)
    
    headers.update({'Authorization': bearer})
    
    url = 'https://www.us-api.morningstar.com/sal/sal-service/fund/factorProfile/%s/data' %api_id
    jsonData = requests.get(url, headers=headers, params=payload).json()
    
    rows = []
    for k, v in jsonData['factors'].items():
        row = {}
        row['factor'] = k
        
        historicRange = v.pop('historicRange')
        row.update(v)
        
        for each in historicRange:
            row.update(each)
            
            rows.append(row.copy())
        
    
    df = pd.DataFrame(rows)
    sheetName = jsonData['id']
    df.to_excel(writer, sheet_name=sheetName, index=False)
    print('Finished: %s' %sheetName)

writer.save()
writer.close()

【问题讨论】:

标签: python json api web-scraping python-requests


【解决方案1】:

如果我理解正确,您希望以 pandas 数据框的形式获取该 URL 的第一个表:

import requests
import pandas as pd
from bs4 import BeautifulSoup


# load the page into soup:
url = "https://www.morningstar.dk/dk/funds/snapshot/snapshot.aspx?id=F00000Z1MC&tab=1"
soup = BeautifulSoup(requests.get(url).content, "html.parser")

# find correct table:
tbl = soup.select_one(".returnsCalenderYearTable")

# remove the first row (it's not header):
tbl.tr.extract()

# convert the html to pandas DF:
df = pd.read_html(str(tbl))[0]

# move the first row to header:
df.columns = map(str, df.loc[0])
df = df.loc[1:].reset_index(drop=True).rename(columns={"nan": "Name"})

print(df)

打印:

              Name 2014* 2015* 2016* 2017*  2018  2019  2020 31-08
0  Samlet afkast %  2627  1490  1432   584  -589  2648  -482  1841
1     +/- Kategori  1130   583   808  -255   164    22  -910  -080
2       +/- Indeks   788   591   363  -320  -127  -262 -1106  -162
3  Rank i kategori     2     9     4    80    38    54    92    63

编辑:从多个 URL 加载:

import requests
import pandas as pd
from bs4 import BeautifulSoup


urls = [
    "https://www.morningstar.dk/dk/funds/snapshot/snapshot.aspx?id=F00000VA2N&tab=1",
    "https://www.morningstar.dk/dk/funds/snapshot/snapshot.aspx?id=F0GBR064OO&tab=1",
    "https://www.morningstar.dk/dk/funds/snapshot/snapshot.aspx?id=F00000YKC2&tab=1",
    "https://www.morningstar.dk/dk/funds/snapshot/snapshot.aspx?id=F000015MVX&tab=1",
]


all_data = []
for url in urls:
    print("Loading URL {}".format(url))

    # load the page into soup:
    soup = BeautifulSoup(requests.get(url).content, "html.parser")

    # find correct table:
    tbl = soup.select_one(".returnsCalenderYearTable")

    # remove the first row (it's not header):
    tbl.tr.extract()

    # convert the html to pandas DF:
    df = pd.read_html(str(tbl))[0]

    # move the first row to header:
    df.columns = map(lambda x: str(x).replace("*", "").strip(), df.loc[0])
    df = df.loc[1:].reset_index(drop=True).rename(columns={"nan": "Name"})

    df["Company"] = soup.h1.text.split("\n")[0].strip()
    df["URL"] = url
    all_data.append(df.loc[:, ~df.isna().all()])

df = pd.concat(all_data, ignore_index=True)
print(df)

打印:

               Name    2016    2017    2018    2019   2020 31-08                          Company                                                                             URL
0   Samlet afkast %  1755.0   942.0 -1317.0  1757.0 -189.0  3018        Great Dane Globale Aktier  https://www.morningstar.dk/dk/funds/snapshot/snapshot.aspx?id=F00000VA2N&tab=1
1      +/- Kategori   966.0   -54.0  -186.0  -662.0 -967.0  1152        Great Dane Globale Aktier  https://www.morningstar.dk/dk/funds/snapshot/snapshot.aspx?id=F00000VA2N&tab=1
2        +/- Indeks   686.0    38.0  -854.0 -1153.0 -813.0  1015        Great Dane Globale Aktier  https://www.morningstar.dk/dk/funds/snapshot/snapshot.aspx?id=F00000VA2N&tab=1
3   Rank i kategori    10.0    24.0    85.0    84.0   77.0     4        Great Dane Globale Aktier  https://www.morningstar.dk/dk/funds/snapshot/snapshot.aspx?id=F00000VA2N&tab=1
4   Samlet afkast %     NaN  1016.0  -940.0  1899.0  767.0  2238      Independent Generations ESG  https://www.morningstar.dk/dk/funds/snapshot/snapshot.aspx?id=F0GBR064OO&tab=1
5      +/- Kategori     NaN    20.0   190.0  -520.0  -12.0   373      Independent Generations ESG  https://www.morningstar.dk/dk/funds/snapshot/snapshot.aspx?id=F0GBR064OO&tab=1
6        +/- Indeks     NaN   112.0  -478.0 -1011.0  143.0   235      Independent Generations ESG  https://www.morningstar.dk/dk/funds/snapshot/snapshot.aspx?id=F0GBR064OO&tab=1
7   Rank i kategori     NaN    26.0    69.0    92.0   43.0    25      Independent Generations ESG  https://www.morningstar.dk/dk/funds/snapshot/snapshot.aspx?id=F0GBR064OO&tab=1
8   Samlet afkast %     NaN     NaN  -939.0  1898.0  766.0  2239  Independent Generations ESG Akk  https://www.morningstar.dk/dk/funds/snapshot/snapshot.aspx?id=F00000YKC2&tab=1
9      +/- Kategori     NaN     NaN   191.0  -521.0  -12.0   373  Independent Generations ESG Akk  https://www.morningstar.dk/dk/funds/snapshot/snapshot.aspx?id=F00000YKC2&tab=1
10       +/- Indeks     NaN     NaN  -477.0 -1012.0  142.0   236  Independent Generations ESG Akk  https://www.morningstar.dk/dk/funds/snapshot/snapshot.aspx?id=F00000YKC2&tab=1
11  Rank i kategori     NaN     NaN    68.0    92.0   44.0    24  Independent Generations ESG Akk  https://www.morningstar.dk/dk/funds/snapshot/snapshot.aspx?id=F00000YKC2&tab=1
12  Samlet afkast %     NaN     NaN     NaN     NaN    NaN  2384       Investin Sustainable World  https://www.morningstar.dk/dk/funds/snapshot/snapshot.aspx?id=F000015MVX&tab=1
13     +/- Kategori     NaN     NaN     NaN     NaN    NaN   518       Investin Sustainable World  https://www.morningstar.dk/dk/funds/snapshot/snapshot.aspx?id=F000015MVX&tab=1
14       +/- Indeks     NaN     NaN     NaN     NaN    NaN   381       Investin Sustainable World  https://www.morningstar.dk/dk/funds/snapshot/snapshot.aspx?id=F000015MVX&tab=1
15  Rank i kategori     NaN     NaN     NaN     NaN    NaN    18       Investin Sustainable World  https://www.morningstar.dk/dk/funds/snapshot/snapshot.aspx?id=F000015MVX&tab=1

【讨论】:

  • 您好,感谢您的回答!您对我的理解是正确的,但我只需要可以同时处理大约 100 个 URL 的东西。我展示的代码获取了一些其他数据并将其导出到 100 个不同的 Excel 工作表中,以便之后进行排序。我正在尝试做类似的事情。基本上,为了得到你已经为很多不同的 URL 抓取的表。我也有所有 URL 的列表,但我找不到解决方案
  • @KarlEmilThulstrup 所以遍历 URL 并将结果存储到每个工作表(或一个大数据框)?
  • 是的,这正是我想要做的
  • @稍微调整一下效果就很好!非常感谢,我没有意识到它可以用汤来完成
猜你喜欢
  • 2023-01-19
  • 2022-11-26
  • 2022-11-17
  • 1970-01-01
  • 2018-11-01
  • 2016-04-12
  • 2019-01-18
  • 1970-01-01
  • 2019-05-27
相关资源
最近更新 更多