使用BeautifulSoup爬取网页仅获部分表格 如何修改代码实现全量爬取
问题根因
你仅能爬取到5个目标表格,核心是三个问题:
- 目标站点是Angular构建的单页应用,9个目标表格里有4个位于非默认激活的选项卡、默认折叠的面板容器内,固定写死的
sleep(10)只能保证首屏默认展示的5个表格完成渲染,非激活区域的内容还未触发渲染流程 - 无头模式下Chrome默认窗口尺寸极小,会触发站点响应式布局逻辑,部分非首屏内容会走懒加载策略,不会在页面初始加载时自动渲染
- 提取页面源码的时机完全靠固定等待,没有校验目标元素是否全部加载完成,过早执行了源码解析逻辑
具体修改点
- 给Chrome启动参数添加固定窗口尺寸配置,避免小窗口触发响应式懒加载
- 替换固定时长的
sleep等待为Selenium显式等待,持续检测页面上目标表格的数量,直到9个表格全部渲染完成再提取源码,等待超时时间可设为30秒,比固定等待更稳定也更高效 - 若显式等待后仍无法凑齐9个表格,增加自动点击逻辑:遍历页面上所有选项卡、折叠面板的可点击元素,逐个触发点击让对应区域内容渲染,点击完成后再次校验表格数量
修改后完整代码
from selenium import webdriver from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.common.by import By from bs4 import BeautifulSoup import time def ScrapeSecScreen(): options = webdriver.ChromeOptions() options.add_argument('--ignore-certificate-errors') options.add_argument('--incognito') options.add_argument('--headless=new') # 固定窗口尺寸,避免响应式布局导致内容不加载 options.add_argument('--window-size=1920,1080') # 旧版Selenium可在Chrome()内传入executable_path参数指定chromedriver路径 driver = webdriver.Chrome(options=options) driver.get('https://www.panamacompra.gob.pa/Inicio/v2/#!/vistaPreviaCP?NumLc=2022-0-30-0-08-CL-024792&esap=0&nnc=0&it=1') target_table_selector = 'table.table.table-condensed.table-bordered.last-line-table' # 第一次显式等待,等首屏表格加载 try: WebDriverWait(driver, 30).until( lambda d: len(d.find_elements(By.CSS_SELECTOR, target_table_selector)) >=5 ) except: pass # 校验当前表格数量,不足9个就点击所有选项卡、折叠面板触发渲染 current_table_count = len(driver.find_elements(By.CSS_SELECTOR, target_table_selector)) if current_table_count < 9: # 匹配页面上的选项卡、折叠面板触发按钮 clickable_elements = driver.find_elements(By.CSS_SELECTOR, '.nav-tabs li, .panel-title a, .accordion-toggle') for elem in clickable_elements: try: # 用js点击避免元素遮挡、不可点击的报错 driver.execute_script("arguments[0].click();", elem) time.sleep(0.3) except: continue # 点击完成后再次等待所有表格加载 WebDriverWait(driver, 20).until( lambda d: len(d.find_elements(By.CSS_SELECTOR, target_table_selector)) >=9 ) # 所有表格加载完成后再提取源码解析 sourcecode = driver.page_source soup = BeautifulSoup(sourcecode, "html.parser") l1 = [] tablelist1 = soup.find_all('table', {'class': 'table table-condensed table-bordered last-line-table'}) for table in tablelist1: trs = table.find_all('tr') row = [tr.text.strip() for tr in trs] l1.append(row) print(f"共爬取到{len(l1)}个表格") driver.quit() return l1 if __name__ == "__main__": result = ScrapeSecScreen() print(result)
注意:如果你的本地Selenium版本较低,将
webdriver.Chrome(options=options)改回原有带chromedriver路径的写法即可;如果站点加载速度慢,可适当调大显式等待的超时时间。
内容的提问来源于stack exchange,提问作者Akatsuki
相关产品推荐
相关产品推荐

