纳斯达克IPO数据爬取异常:DataFrame全为NaN值的解决需求
纳斯达克IPO数据爬取全NaN问题解决
问题根源分析
- 动态内容加载:Nasdaq的IPO定价页面依赖JavaScript动态渲染数据,
requests仅能获取初始静态HTML,其中不包含实际IPO表格数据,导致pd.read_html解析出空的无名列(Unnamed)。 - 表格索引错误:即使页面存在静态表格,直接调用
pd.read_html(content)[0]也可能选中非目标表格(如导航栏或空提示占位表格)。 - 列操作不规范:初始DataFrame未定义
Link列,直接使用df['Link'].append()会导致数据无法正确匹配,且索引逻辑混乱。 - 日期格式验证:需确认URL中的月份参数格式是否与网站要求一致(原代码的
pd.Period对象转字符串需确保为网站接受的格式)。
解决方案与修正代码
改用Selenium处理动态渲染内容,同时修正表格选择、列处理逻辑:
import pandas as pd from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from bs4 import BeautifulSoup import re from time import sleep from datetime import datetime # 定义日期范围 start_date = datetime(2023, 1, 1) end_date = datetime(2023, 5, 31) dates = pd.period_range(start_date, end_date, freq='M') # 初始化空DataFrame,包含Link列 df = pd.DataFrame(columns=['Company Name', 'Symbol', 'Market', 'Price', 'Shares', 'Link']) # 初始化Selenium浏览器(需提前安装对应浏览器驱动,如ChromeDriver) options = webdriver.ChromeOptions() options.add_argument('--headless=new') # 无头模式,不显示浏览器窗口 options.add_argument('user-agent=non-profit learning project') driver = webdriver.Chrome(options=options) try: for idx in dates: print(f'Fetching data for {idx}') # 格式化日期为YYYY-MM,匹配网站参数要求 month_param = str(idx) url = f'https://www.nasdaq.com/markets/ipos/activity.aspx?tab=pricings&month={month_param}' driver.get(url) # 等待目标IPO表格加载完成 WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.ID, 'two_column_main_content_rptPricing')) ) sleep(2) # 额外等待确保数据完全渲染 page_source = driver.page_source soup = BeautifulSoup(page_source, 'lxml') # 检查当前月份是否无数据 empty_msg = soup.find(text=re.compile('There is no data for this month')) if empty_msg: print(f'No data for {idx}') continue # 解析目标IPO表格 table = soup.find('table', id='two_column_main_content_rptPricing') rows = table.find_all('tr')[1:] # 跳过表头行 month_data = [] links = [] for row in rows: cols = row.find_all('td') # 提取每行核心数据 company_name = cols[0].text.strip() symbol = cols[1].text.strip() market = cols[2].text.strip() price = cols[3].text.strip() shares = cols[4].text.strip() month_data.append([company_name, symbol, market, price, shares]) # 提取公司详情链接并补全域名 link = cols[0].find('a')['href'] links.append(f'https://www.nasdaq.com{link}') # 转换为临时DataFrame并合并到总数据 temp_df = pd.DataFrame(month_data, columns=['Company Name', 'Symbol', 'Market', 'Price', 'Shares']) temp_df['Link'] = links df = pd.concat([df, temp_df], ignore_index=True) print(f'Fetched {len(temp_df)} records for {idx}') finally: driver.quit() # 确保浏览器正常关闭,避免资源泄漏 print(df)
关键修正点说明
- 动态内容处理:使用Selenium模拟浏览器加载页面,等待目标表格元素出现后再获取源码,确保拿到完整的IPO数据。
- 精准表格定位:通过表格ID
two_column_main_content_rptPricing直接定位目标表格,避免解析错误的无关表格。 - 列数据匹配:逐行解析表格数据,同时对应提取每行的公司链接,保证数据与链接一一对应。
- 资源安全:使用
try-finally块确保浏览器无论是否报错都会正常关闭,避免资源占用。
内容的提问来源于stack exchange,提问作者Salvador Macías
相关产品推荐
相关产品推荐

