如何用Python抓取RaceRoster网站的赛事链接及联系信息(解决动态加载内容问题)
如何用Python抓取RaceRoster网站的赛事链接及联系信息(解决动态加载内容问题)
嘿,我看了你的问题和脚本,核心问题一下子就找到了——RaceRoster的搜索结果是通过JavaScript动态加载的!你用requests拿到的只是服务器返回的初始HTML框架,那些赛事卡片是浏览器执行JS之后才生成的,所以BeautifulSoup自然找不到对应的a.search-results__card-event-name元素,这就是为什么你一直看到“Found 0 events”的原因。
下面我给你一步步解决这个问题:
一、为什么原来的脚本失效?
- 动态内容渲染:网站的搜索结果不是直接写在初始HTML里的,而是浏览器加载页面后,通过JS请求数据再渲染出来的。
requests只能获取静态的初始HTML,无法执行JS,所以拿不到渲染后的赛事链接。 - 你检查
soup.prettify()看不到赛事链接,完全符合这个情况。
二、解决方案:用Selenium模拟浏览器
要抓取动态加载的内容,我们需要用能模拟真实浏览器行为的工具——Selenium。它可以打开浏览器,等待页面加载完成(包括JS执行),然后获取完整的渲染后页面源码,再交给BeautifulSoup处理。
准备工作
- 安装Selenium:在终端执行
pip install selenium - 下载对应浏览器的驱动:比如用Chrome的话,下载ChromeDriver(要和你的Chrome版本完全匹配),可以放在系统PATH里,或者在代码里指定驱动路径。
三、修改后的完整脚本
我已经把你的脚本改成了用Selenium处理搜索页,详情页还是用requests(更高效),关键部分都加了注释:
import requests from bs4 import BeautifulSoup 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 selenium.common.exceptions import TimeoutException def scrape_event_contacts(base_url, search_url): headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36" } event_contacts = [] # 初始化Chrome浏览器,无头模式(不显示窗口) options = webdriver.ChromeOptions() options.add_argument("--headless=new") options.add_argument("--disable-blink-features=AutomationControlled") # 避免被反爬识别 options.add_argument(f"user-agent={headers['User-Agent']}") driver = webdriver.Chrome(options=options) try: print(f"Scraping page: {search_url}") driver.get(search_url) # 等待赛事链接加载完成,最多等10秒(防止页面加载慢) try: WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.CSS_SELECTOR, "a.search-results__card-event-name")) ) except TimeoutException: print("等待页面加载超时,未找到赛事链接") driver.quit() return event_contacts # 获取渲染后的完整页面源码 page_source = driver.page_source soup = BeautifulSoup(page_source, "html.parser") # 现在可以正常拿到所有赛事链接了 event_links = soup.select("a.search-results__card-event-name") print(f"Found {len(event_links)} events on the page.") for link in event_links: event_url = link['href'] event_name = link.text.strip() try: print(f"Scraping event: {event_url}") # 详情页用requests抓取,一般静态内容足够 event_response = requests.get(event_url, headers=headers) if event_response.status_code != 200: print(f"Failed to fetch event page: {event_url}, status code: {event_response.status_code}") continue event_soup = BeautifulSoup(event_response.content, "html.parser") # 提取联系人信息,根据页面结构调整选择器 contact_name = event_soup.find("dd", class_="event-details__contact-list-definition") email = event_soup.find("a", href=lambda href: href and "mailto:" in href) contact_name_text = contact_name.text.strip() if contact_name else "N/A" email_address = email['href'].split("mailto:")[1].split("?")[0] if email else "N/A" if contact_name or email: print(f"Found contact: {contact_name_text}, email: {email_address}") event_contacts.append({ "Event Name": event_name, "Event URL": event_url, "Event Contact": contact_name_text, "Email": email_address }) else: print(f"No contact information found for {event_url}") except Exception as e: print(f"Error scraping event {event_url}: {e}") finally: # 不管成功失败,都要关闭浏览器,避免资源占用 driver.quit() print(f"Scraped {len(event_contacts)} events.") return event_contacts def save_to_spreadsheet(data, output_file): if not data: print("No data to save.") return df = pd.DataFrame(data) df.to_excel(output_file, index=False) print(f"Data saved to {output_file}") if __name__ == "__main__": base_url = "https://raceroster.com" search_url = "https://raceroster.com/search?q=5k&t=upcoming" output_file = "/Users/my_name/Documents/event_contacts.xlsx" contact_data = scrape_event_contacts(base_url, search_url) if contact_data: save_to_spreadsheet(contact_data, output_file) else: print("No contacts were scraped.")
四、关键修改说明
- Selenium初始化:用无头模式运行Chrome,既不影响你使用电脑,也能避免一些反爬检测;同时设置了自定义User-Agent,伪装成真实浏览器。
- 等待页面加载:用
WebDriverWait等待赛事链接元素出现,确保页面完全渲染后再抓取,避免因为加载慢导致的空结果。 - 获取渲染后源码:通过
driver.page_source拿到浏览器渲染后的完整HTML,再交给BeautifulSoup解析,这样就能拿到所有赛事链接了。 - 详情页优化:详情页一般是静态内容,用
requests抓取比Selenium更高效,节省资源。
五、注意事项
- 确保ChromeDriver版本和你的Chrome浏览器版本一致,否则会启动失败。
- 如果网站有反爬机制,可以尝试加入随机延迟(比如
time.sleep(random.uniform(1,3))),避免请求过于频繁。 - 如果联系人信息的选择器不对,需要打开赛事详情页,用浏览器开发者工具重新查看HTML结构,调整对应的选择器。
备注:内容来源于stack exchange,提问作者Guill T
相关产品推荐
相关产品推荐

