Python中使用Yahoo Financials获取股票数据并存储到DataFrame时出现ValueError的问题排查
Alright, let's figure out where you went wrong and fix it step by step!
Why You Got the ValueError
The error happens because you're passing a YahooFinancials class instance directly to the pandas DataFrame constructor. The DataFrame expects structured data like a dictionary, list of dictionaries, or another DataFrame—not an instance of the YahooFinancials class. That's why it throws the "constructor not properly called" error.
Solution: Extract Data First, Then Build Your DataFrame
We need to pull the specific data points you want (PE ratio, price-to-sales, currency, adjusted closing prices) from the YahooFinancials instance, format them into structured data, and then assemble them into usable DataFrames. Here's how to do it:
First, make sure you have the necessary imports:
import pandas as pd from yahoo_fin import YahooFinancials # Assuming you're using the yahoo_fin library
Let's assume your assets variable is a list of tickers like ["AAPL", "MSFT", "GOOG"]. We'll reuse a single YahooFinancials instance instead of creating multiple ones (more efficient):
Step 1: Initialize the YahooFinancials Instance
assets = ["AAPL", "MSFT", "GOOG"] yahoo_financials = YahooFinancials(assets)
Step 2: Build the Fundamental Metrics DataFrame
This will hold your asset names, PE ratio, price-to-sales, and currency:
# Fetch the fundamental data as dictionaries pe_ratios = yahoo_financials.get_pe_ratio() price_to_sales = yahoo_financials.get_price_to_sales() currencies = yahoo_financials.get_currency() # Convert to a DataFrame fundamental_df = pd.DataFrame({ "资产名称": list(pe_ratios.keys()), "市盈率(PE ratio)": list(pe_ratios.values()), "市销率(Price to Sales)": list(price_to_sales.values()), "货币类型": list(currencies.values()) }) print("基本面数据表格:") print(fundamental_df)
Step 3: Build the Historical Adjusted Closing Prices DataFrame
This will give you a date-indexed table of daily adjusted closes for each asset:
# Fetch historical price data historical_data = yahoo_financials.get_historical_price_data( start_date="2013-01-01", end_date="2021-01-30", time_interval="daily" ) # Extract adjusted closes for each asset price_data = {} for ticker in assets: # Get the list of price entries for the ticker ticker_prices = historical_data[ticker]["prices"] # Pull out formatted date and adjusted close, then map dates to values price_data[ticker] = {entry["formatted_date"]: entry["adjclose"] for entry in ticker_prices} # Convert to a DataFrame (dates as index, tickers as columns) price_df = pd.DataFrame(price_data).rename(columns={ticker: f"{ticker}_调整收盘价" for ticker in assets}) print("\n每日调整收盘价表格:") print(price_df.head())
What This Gives You
fundamental_df: A table where each row is an asset with its current PE ratio, price-to-sales ratio, and currency.price_df: A time-series table where each row is a date, and each column is the adjusted closing price for an asset.
If you want to combine these (though note that fundamental metrics are static while prices are daily), you could repeat the fundamental data for each date, but that's usually not necessary for analysis—keeping them separate is cleaner for most use cases.
Key Takeaway
Never pass the raw YahooFinancials instance to pandas. Always extract the specific data you need (which comes as dictionaries or lists from the library's methods) and then structure that data into the format pandas expects.
内容的提问来源于stack exchange,提问作者JD_BNL

