
本文教你使用 selenium 替代 requests + beautifulsoup,稳定抓取 javascript 渲染的动态表格,并将交替出现的标题行与数据行自动构造成字典结构,解决 vba 转 python 用户常见的“奇偶行分层解析”难题。
本文教你使用 selenium 替代 requests + beautifulsoup,稳定抓取 javascript 渲染的动态表格,并将交替出现的标题行与数据行自动构造成字典结构,解决 vba 转 python 用户常见的“奇偶行分层解析”难题。
在从静态 HTML 表格迁移至现代 JS 渲染页面时,requests + BeautifulSoup 常因无法执行 JavaScript 而失效——正如目标网址 modernarmor.worldoftanks.com 所示:其表格内容由前端脚本动态注入,原始 HTML 中 <tbody> 为空或结构不完整。此时,<strong>Selenium 是更可靠的选择</strong>,它通过真实浏览器驱动模拟用户行为,确保 DOM 完全加载后再提取数据。<p>核心思路是识别“标题-数据”交替模式:每两个 <code><tr> 组成一对,其中第 0、2、4… 行(索引为偶数)作为键(header),紧随其后的第 1、3、5… 行(索引为奇数)作为值(data list)。关键在于精准定位元素并按序遍历:<pre class="brush:php;toolbar:false;">from selenium.webdriver import Chrome
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
URL = "https://modernarmor.worldoftanks.com/en/cms/guides/map-labels-tiers-eras/"
def reject_cookies(driver):
"""自动点击“拒绝全部 Cookie”按钮(若存在),避免遮挡主内容"""
wait = WebDriverWait(driver, 5)
try:
button = wait.until(EC.element_to_be_clickable((By.ID, "onetrust-reject-all-handler")))
button.click()
except: # 按钮未出现则跳过
pass
def parse_table_as_dict(driver):
"""
解析表格为 {header: [item1, item2, ...]} 字典
假设 DOM 中 tr 元素严格按 header/data 交替排列
"""
wait = WebDriverWait(driver, 10)
# 使用高置信度 CSS 选择器定位表格行(避免通用 tr 导致误匹配)
rows = wait.until(EC.presence_of_all_elements_located(
(By.CSS_SELECTOR, "tr.news_post-widget-table-tr")
))
result = {}
header = None
for i, row in enumerate(rows):
text = row.text.strip()
if not text: # 跳过空行
continue
if i % 2 == 0: # 偶数索引 → 标题行
header = text
else: # 奇数索引 → 数据行;按换行符分割为列表
if header and text:
# 多个地图名通常以换行符分隔(非逗号!原代码正则逻辑在此不适用)
items = [item.strip() for item in text.split("\n") if item.strip()]
result[header] = items
return result
# 主流程
with Chrome() as driver:
driver.get(URL)
reject_cookies(driver)
data_dict = parse_table_as_dict(driver)
# 输出示例(格式化展示)
for header, maps in list(data_dict.items())[:3]: # 仅显示前3组
print(f"▶ {header}")
for m in maps[:3]: # 每组最多列3个地图
print(f" └─ {m}")
if len(maps) > 3:
print(f" └─ ... and {len(maps)-3} more")</pre>
<p>⚠️ <strong>重要注意事项:</strong> </p>
<ul>
<li>
<strong>不要硬编码索引逻辑</strong>:原问题中尝试用 <code>stringCount == 2 判断 header 的方式不可靠——实际网页中标题长度多变,且分隔符是 \n 而非 ,,正则替换反而破坏结构;应直接依赖 DOM 顺序和语义(如 class 名 news_post-widget-table-tr)。
selenium 并配置 ChromeDriver(推荐使用 webdriver-manager 自动管理): pip install selenium webdriver-manager
然后将 with Chrome() as driver: 替换为:
from webdriver_manager.chrome import ChromeDriverManager from selenium.webdriver.chrome.service import Service service = Service(ChromeDriverManager().install()) with Chrome(service=service) as driver:
EC.visibility_of_element_located)、异常重试机制,并对 header 去重/标准化(如去除多余空格、统一大小写)。最终,你将获得一个结构清晰、可直接用于 Pandas DataFrame 构建或 JSON 导出的 Python 字典——告别二维数组手动索引,真正实现“语义化解析”。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











