通过Python从Marketscreener获取ETF持仓数据并导出CSV
解决Marketscreener ETF持仓数据爬取(JS渲染页面)问题
你的判断没错——这个页面的持仓表格是通过JavaScript动态渲染的,requests只能抓取页面初始的静态HTML,不会执行页面中的JS代码,所以无法获取到动态加载的持仓数据。下面是用Playwright模拟浏览器渲染来解决这个问题的方案:
步骤1:安装依赖
先安装Playwright库和Chromium浏览器驱动:
pip install playwright playwright install chromium
步骤2:完整爬取代码
from playwright.sync_api import sync_playwright import csv # ETF持仓页面URL url = 'https://de.marketscreener.com/kurs/etf/DEKA-EURO-ISTOXX-EX-FIN-D-40509374/einzelwerte/' with sync_playwright() as p: # 启动无头模式的Chromium(headless=True可改为False查看浏览器窗口) browser = p.chromium.launch(headless=True) page = browser.new_page(user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36") # 访问目标页面 page.goto(url) # 等待持仓表格加载完成(超时时间10秒) page.wait_for_selector('table.BordCollapseYear2', timeout=10000) # 提取表格数据 all_data = {} tables = page.locator('table.BordCollapseYear2').all() for table in tables: # 获取表格标题(前一个<b>标签的文本) table_name = table.locator('xpath=preceding-sibling::b[1]').text_content().strip() all_data[table_name] = [] # 遍历表格行 rows = table.locator('tr').all() for row in rows: # 提取每行的单元格文本,清理换行符 cells = row.locator('td').all() row_data = [cell.text_content().strip().replace('\n', ' ') for cell in cells] if len(row_data) == 7: # 筛选有效数据行 all_data[table_name].append(row_data) # 关闭浏览器 browser.close() # 将数据保存为CSV文件 with open('etf_holdings.csv', 'w', newline='', encoding='utf-8') as csvfile: writer = csv.writer(csvfile, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL) for table_name, rows in all_data.items(): writer.writerow([table_name]) writer.writerows(rows) print("持仓数据已成功导出到etf_holdings.csv")
关键说明
- Playwright模拟真实浏览器加载页面,自动执行所有JS代码,能获取到动态渲染的表格内容。
wait_for_selector方法确保等待表格元素加载完成后再提取数据,避免因页面未加载完全导致空数据。- 你原来的代码存在一个小问题:已经用带headers的
requests.get获取了响应,但创建BeautifulSoup时又重新调用无headers的requests.get(url),这会增加被网站拦截的概率,但核心问题仍是JS渲染。
内容的提问来源于stack exchange,提问作者Silver
相关产品推荐
相关产品推荐

