Python Selenium for循环中动态拼接XPath爬取数据问题求解
Selenium循环拼接动态XPath抓取表格数据解决方案
问题背景
使用Python+Selenium开展网页数据抓取,目标是从加拿大统计局贸易数据查询页面提取表格内容,需要在for循环中传入动态行号参数拼接XPath,逐行定位单元格元素。
目标页面:加拿大统计局贸易进口数据查询页
原代码存在的核心错误
- 拼写错误:循环方法误写为
rane(25),正确方法为range(),且原写法未指定起始值,默认从0开始计数,和表格行号从1开始的规则不匹配 - 语法错误:XPath字符串外层用双引号包裹,内部属性选择器
id="report_table"也使用双引号,会直接导致字符串截断报错;整数类型的循环变量直接用+和字符串拼接,会触发类型不匹配错误 - 逻辑错误:循环内首个元素定位硬编码为
tr[1],未使用动态行号,每次循环只会重复抓取第一行内容,完全无法实现逐行遍历 - 输出错误:直接打印定位到的WebElement对象,只能拿到对象内存地址,无法获取单元格实际文本内容
- 冗余代码:循环前提前赋值
cel = 1无实际作用,for循环遍历过程中会自动覆盖该变量
修正后完整代码
from selenium import webdriver from selenium.webdriver.common.by import By import time # 初始化浏览器(高版本Selenium不需要手动指定chromedriver路径,若本地驱动配置异常可自行补全executable_path参数) driver = webdriver.Chrome() driver.get('https://www150.statcan.gc.ca/n1/pub/71-607-x/71-607-x2021004-eng.htm') time.sleep(2) # 点击导入数据入口 button = driver.find_element(By.XPATH, '//*[@id="cimt_import"]/p[1]/a') button.click() time.sleep(2) # 点击对应主题 button = driver.find_element(By.XPATH, '//*[@id="topic3s"]') button.click() time.sleep(2) # 选择起始年月 driver.find_element(By.XPATH, '//*[@id="fromYear"]/option[1]').click() driver.find_element(By.XPATH, '//*[@id="fromMonth"]/option[1]').click() # 选择结束年月 driver.find_element(By.XPATH, '//*[@id="toYear"]/option[1]').click() driver.find_element(By.XPATH, '//*[@id="toMonth"]/option[5]').click() # 选择商品章节 driver.find_element(By.XPATH, '//*[@id="report_hs"]/option[1]').click() time.sleep(1) # 选择具体商品 driver.find_element(By.XPATH, '//*[@id="report_hs"]/option[2]').click() # 点击生成报告 driver.find_element(By.XPATH, '//*[@id="report"]/div[1]/div[3]/div[5]/p[2]/button').click() time.sleep(3) # 等待表格加载完成,可替换为显式等待提升稳定性 # 循环遍历表格前25行 for row_num in range(1, 26): # 拼接动态XPath,外层用单引号包裹,内部属性用双引号避免冲突 commodity_link = driver.find_element(By.XPATH, f'//*[@id="report_table"]/tbody/tr[{row_num}]/td[2]/a') # 打印商品名称 print(commodity_link.text) # 取第4列内容 col4 = driver.find_element(By.XPATH, f'//*[@id="report_table"]/tbody/tr[{row_num}]/td[4]').text print(col4) # 取第7列内容 col7 = driver.find_element(By.XPATH, f'//*[@id="report_table"]/tbody/tr[{row_num}]/td[7]').text print(col7) # 取第8列abbr标签内容 col8_abbr = driver.find_element(By.XPATH, f'//*[@id="report_table"]/tbody/tr[{row_num}]/td[8]/abbr').text print(col8_abbr) print('---'*20) time.sleep(3) driver.quit()
关键编写要点
- 动态拼接XPath优先使用f-string语法,比
+拼接可读性更高,且会自动处理数字到字符串的类型转换,避免类型报错 - 严格注意引号嵌套规则:如果XPath外层用单引号包裹,内部属性值就用双引号;如果外层用双引号,内部就用单引号,绝对不能内外使用相同引号导致字符串提前截断
- 高版本Selenium已废弃
find_element_by_xpath这类旧写法,统一使用find_element(By.XPATH, 路径)的新语法,需要提前导入By类 - 表格遍历更稳定的写法是先一次性定位所有行元素:
rows = driver.find_elements(By.XPATH, '//*[@id="report_table"]/tbody/tr'),再遍历rows列表取索引,避免逐行定位时因为页面加载、行号不连续导致的定位失败 - 固定时长的
time.sleep()可替换为Selenium显式等待,判断表格加载完成后再执行抓取,能大幅提升脚本运行速度和稳定性
内容的提问来源于stack exchange,提问作者user16832397
相关产品推荐
相关产品推荐

