如何修改Selenium爬虫代码自动爬取分页表格至最后一页
问题场景
使用Python+Selenium开发网页表格数据爬取脚本时,无法提前获取目标表格的分页总页数。现有代码通过手动设置固定循环次数,仅能爬取前25页数据,但实际场景下目标表格总页数不固定,可能为60页或70页,需要调整代码逻辑,无需手动指定总页数即可自动持续翻页爬取,直到获取最后一页全部内容。
原有问题代码
from selenium import webdriver import pandas as pd import time driver = webdriver.Chrome('C:\Webdriver\chromedriver.exe') driver.get('https://www150.statcan.gc.ca/n1/pub/71-607-x/2021004/imp-eng.htm?r1=(1)&r2=0&r3=0&r4=12&r5=0&r7=0&r8=2022-01-01&r9=2022-01-01') time.sleep(2) Canada_Result=[] for J in range (25): commodities = driver.find_elements_by_xpath('.//*[@id="report_table"]/tbody/tr["i"]/td[2]/a') Countries = driver.find_elements_by_xpath('.//*[@id="report_table"]/tbody/tr["i"]/td[4]') quantities = driver.find_elements_by_xpath('.//*[@id="report_table"]/tbody/tr["i"]/td[7]') weights = driver.find_elements_by_xpath('.//*[@id="report_table"]/tbody/tr["i"]/td[8]/abbr') for i in range(25): temporary_data= {'Commodity': commodities[i].text,'Country': Countries[i].text,'quantity': quantities[i].text, 'weight': weights[i].text } Canada_Result.append(temporary_data) df_data = pd.DataFrame(Canada_Result) df_data df_data.to_excel('Canada_scrapping_result.xlsx', index=False) # click on the Next button driver.find_element_by_xpath('//*[@id="report_results_next"]').click() time.sleep(1)
实现思路
核心逻辑是通过下一页按钮的状态判断是否到达最后一页,不需要提前获取总页数:
- 目标站点最后一页的「下一页」按钮会添加
disabled类名,处于不可点击状态,检测到该状态时终止爬取即可 - 废弃固定次数的for循环,改用while循环持续爬取
- 内层遍历数据时不要固定写死25条的遍历长度,以当前页实际抓取到的商品条目数为准,避免最后一页数据不足25条时触发索引越界
- 去掉循环内重复写入Excel的冗余操作,所有数据爬完后一次性导出,提升运行效率
修改后可运行代码
注:Selenium 4.0+版本已废弃
find_elements_by_xpath这类旧定位写法,代码中使用官方推荐的By定位方式,低版本可自行替换为原有写法,判断逻辑通用
from selenium import webdriver from selenium.webdriver.common.by import By import pandas as pd import time # 初始化驱动 driver = webdriver.Chrome('C:\Webdriver\chromedriver.exe') driver.get('https://www150.statcan.gc.ca/n1/pub/71-607-x/2021004/imp-eng.htm?r1=(1)&r2=0&r3=0&r4=12&r5=0&r7=0&r8=2022-01-01&r9=2022-01-01') time.sleep(2) Canada_Result = [] while True: # 抓取当前页所有字段元素 commodities = driver.find_elements(By.XPATH, './/*[@id="report_table"]/tbody/tr["i"]/td[2]/a') Countries = driver.find_elements(By.XPATH, './/*[@id="report_table"]/tbody/tr["i"]/td[4]') quantities = driver.find_elements(By.XPATH, './/*[@id="report_table"]/tbody/tr["i"]/td[7]') weights = driver.find_elements(By.XPATH, './/*[@id="report_table"]/tbody/tr["i"]/td[8]/abbr') # 按当前页实际数据量遍历,不固定写死长度 for i in range(len(commodities)): temporary_data = { 'Commodity': commodities[i].text, 'Country': Countries[i].text, 'quantity': quantities[i].text, 'weight': weights[i].text } Canada_Result.append(temporary_data) # 定位下一页按钮 next_btn = driver.find_element(By.XPATH, '//*[@id="report_results_next"]') # 判断按钮是否为禁用状态,是则说明到最后一页,退出循环 if 'disabled' in next_btn.get_attribute('class'): break # 未到最后一页则点击翻页,等待加载 next_btn.click() time.sleep(1) # 所有数据爬取完成后一次性导出Excel df_data = pd.DataFrame(Canada_Result) df_data.to_excel('Canada_scrapping_result.xlsx', index=False) driver.quit()
补充说明
- 若目标站点的下一页按钮是通过原生
disabled属性控制状态,可直接用next_btn.is_enabled()方法判断是否可点击,无需读取class属性 - 固定的
time.sleep()等待可替换为Selenium的显式等待WebDriverWait,适配不同网络环境下的页面加载速度,减少等待时间同时避免元素未加载报错
内容的提问来源于stack exchange,提问作者user16832397
相关产品推荐
相关产品推荐

