快速抓取目标站点表格技术求助:优化Selenium方案或替代高效方法
高效抓取动态渲染表格的解决方案
针对你需要抓取15000个动态渲染表格的需求,直接用Selenium+Pandas确实会因为频繁启动浏览器而效率极低。下面提供几个更高效的方案,按优先级排序:
1. 直接调用后端API(最优解,速度提升100+倍)
之所以requests/Scrapy抓不到表格,是因为页面的表格数据是通过AJAX动态加载的,初始HTML里根本没有表格内容,#后面的是前端路由参数,实际数据来自后端API接口。
操作步骤:
- 打开Chrome DevTools(F12),切换到「Network」标签页
- 刷新目标页面,筛选「Fetch/XHR」类型的请求
- 寻找返回JSON格式数据的请求,里面应该包含你需要的表格内容(通常会有
results、table之类的关键字段) - 复制该API的请求URL和请求头(尤其是
User-Agent、Cookie等可能的验证字段),直接用requests批量请求
示例代码:
假设找到的API地址是https://greyhoundbet.racingpost.com/api/dog-results,参数和原URL一致:
import requests import pandas as pd from concurrent.futures import ThreadPoolExecutor API_URL = "https://greyhoundbet.racingpost.com/api/dog-results" HEADERS = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36", # 可以从DevTools里复制实际的Cookie、Referer等字段 } def fetch_table(params): try: response = requests.get(API_URL, headers=HEADERS, params=params, timeout=10) response.raise_for_status() data = response.json() # 假设表格数据在data['tableData']里,根据实际结构调整 df = pd.DataFrame(data['tableData']) return df except Exception as e: print(f"Failed to fetch {params}: {e}") return None # 假设你有15000个参数列表,每个参数对应一个页面的race_id、dog_id等 params_list = [ {"race_id": "1807732", "dog_id": "539402", "r_date": "2021-01-01", "track_id": "4", "r_time": "13:24"}, # 更多参数... ] # 用线程池批量请求,提升效率 with ThreadPoolExecutor(max_workers=20) as executor: results = list(executor.map(fetch_table, params_list)) # 合并所有结果并保存 final_df = pd.concat([df for df in results if df is not None], ignore_index=True) final_df.to_csv('all_tables.csv', encoding='utf-8', index=False)
2. 优化Selenium的使用(如果必须用浏览器)
如果找不到API,只能用浏览器渲染,那可以通过以下方式大幅提升速度:
优化点:
- 使用无头模式,避免浏览器界面渲染开销
- 复用浏览器实例,不要每次请求都启动新Chrome进程
- 用显式等待替换固定
time.sleep(8),只等表格加载完成就继续 - 禁用图片、CSS、非必要JS,减少页面加载时间
优化后的代码:
import pandas as pd import time from selenium import webdriver from selenium.webdriver.chrome.service import Service from webdriver_manager.chrome import ChromeDriverManager from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By # 配置Chrome选项,启用无头模式并禁用不必要的加载 options = webdriver.ChromeOptions() options.add_argument('--headless=new') # 新版无头模式,更接近真实浏览器 options.add_argument('--disable-gpu') options.add_argument('--disable-images') options.add_argument('--disable-css') options.add_argument('--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36') options.add_experimental_option('excludeSwitches', ['enable-automation']) options.add_experimental_option('useAutomationExtension', False) # 初始化一次浏览器,复用实例 wd = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=options) wd.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})") def extract(url): try: wd.get(url) # 显式等待表格加载完成,最多等5秒(比固定8秒快) WebDriverWait(wd, 5).until( EC.presence_of_element_located((By.ID, 'sortableTable')) ) all_tables = pd.read_html(wd.page_source, attrs={'id': 'sortableTable'}) return pd.concat(all_tables) except Exception as e: print(f"Failed to extract {url}: {e}") return None # 假设你有15000个URL列表 url_list = [ "https://greyhoundbet.racingpost.com/#results-dog/race_id=1807732&dog_id=539402&r_date=2021-01-01&track_id=4&r_time=13:24", # 更多URL... ] # 批量处理 results = [] for url in url_list: df = extract(url) if df is not None: results.append(df) # 合并保存 final_df = pd.concat(results, ignore_index=True) final_df.to_csv('all_tables.csv', encoding='utf-8', index=False) # 最后关闭浏览器 wd.quit()
3. 用Playwright替代Selenium(更现代的浏览器自动化工具)
Playwright是微软开发的自动化工具,速度比Selenium快,API更简洁,自带自动等待功能,支持多浏览器。
示例代码:
import pandas as pd from playwright.sync_api import sync_playwright from concurrent.futures import ThreadPoolExecutor def extract_table(url): with sync_playwright() as p: 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/96.0.4664.110 Safari/537.36") page.route("**/*.png", lambda route: route.abort()) # 阻止图片加载 page.route("**/*.css", lambda route: route.abort()) # 阻止CSS加载 page.goto(url, wait_until="domcontentloaded") # 自动等待表格出现 page.wait_for_selector("#sortableTable") html = page.content() browser.close() all_tables = pd.read_html(html, attrs={'id': 'sortableTable'}) return pd.concat(all_tables) # 批量处理(Playwright也支持异步,效率更高) url_list = [ "https://greyhoundbet.racingpost.com/#results-dog/race_id=1807732&dog_id=539402&r_date=2021-01-01&track_id=4&r_time=13:24", # 更多URL... ] with ThreadPoolExecutor(max_workers=10) as executor: results = list(executor.map(extract_table, url_list)) final_df = pd.concat([df for df in results if df is not None], ignore_index=True) final_df.to_csv('all_tables.csv', encoding='utf-8', index=False)
内容的提问来源于stack exchange,提问作者farhan jatt
相关产品推荐
相关产品推荐

