Selenium爬取Indeed.com遇弹窗仅获取部分数据的问题问询
Selenium爬取意大利Indeed站点分页后岗位文本为空问题解决方案
问题场景
爬取目标为意大利版Indeed招聘网,站点URL格式如下:
https://it.indeed.com/jobs ?q=[搜索关键词] &sort=[排序规则] &start=[起始结果位置] &vjk=[高亮岗位ID] # 可省略
其中start参数控制分页,值为10时从第10条结果开始展示,对应第二页内容。访问第二页及之后的页面时,站点会弹出订阅新闻通讯的弹窗,此时脚本只能爬取到部分岗位内容:
- 经开发者工具确认,所有岗位数据已经完整存在于DOM结构中
- 延长隐式等待时间后问题依然存在
- 主动执行关闭弹窗操作后,部分岗位元素的文本依然无法读取
复现代码核心逻辑为:初始化Chrome驱动后,按10条步长遍历前100页内容,通过XPath定位岗位卡片节点,读取岗位标题、公司名、地点等字段,第二页开始出现大量空字段。
根因定位
问题和弹窗本身没有直接关联,核心是三个逻辑和站点渲染/反爬机制不匹配:
- 全局配置的
implicitly_wait只会等待元素存在于DOM树,不会等待元素可见、也不会等待元素内文本完成渲染。Selenium自带的.text属性存在可见性限制:仅返回当前在视口内可见、未被任何DOM层遮挡的文本。只要元素处于滚动视口外、被透明遮罩覆盖、甚至被z-index更高的不可见残留弹窗节点遮挡,哪怕肉眼能看到内容、DOM里有完整文本,.text也会返回空字符串。 - 页面刚加载完成时一次性获取所有岗位元素存入列表的写法存在缺陷:Indeed页面加载完成后会动态插入广告位、推荐岗位、调整DOM节点顺序,之前缓存的元素引用虽然没有触发常见的stale element报错,但对应节点实际已经被移出可见渲染区域,读取文本自然为空。
- 常规的关弹窗逻辑大概率没有真正生效:多数人写关弹窗逻辑时,不等关闭按钮进入可点击状态就执行点击,点击实际落在了弹窗的透明遮罩层上,弹窗只是被设置为透明度0,并没有从DOM树移除,依然会遮挡下方的岗位卡片。
修复方案
1. 替换等待逻辑,移除全局隐式等待
隐式等待和显式等待混用会导致不可预期的等待时长问题,初始化驱动后删除driver.implicitly_wait(5)配置,统一用显式等待处理所有节点加载逻辑:
import time from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By # 初始化驱动后配置显式等待,最长等待10秒 wait = WebDriverWait(driver, 10)
每一页跳转完成后,优先处理弹窗,确保弹窗真正从DOM中移除:
driver.get(url_indeed(i)) # 处理订阅弹窗 try: # 等待弹窗关闭按钮可点击,适配意大利站点的按钮属性 close_btn = wait.until(EC.element_to_be_clickable( (By.XPATH, "//button[contains(@aria-label, 'chiudere') or contains(@class, 'icl-CloseButton')]") )) close_btn.click() # 等待弹窗节点完全消失,确认没有残留遮挡层 wait.until(EC.invisibility_of_element_located((By.XPATH, "//div[contains(@class, 'icl-Modal')]"))) except: # 无弹窗时直接跳过 pass
2. 替换文本读取方法,绕开可见性限制
不要依赖.text属性读内容,直接通过JS获取节点的textContent属性,无论节点是否可见、是否被遮挡,都能拿到DOM中存储的真实文本:
def get_node_text(element): return driver.execute_script("return arguments[0].textContent.trim();", element)
所有原来读取.text的位置全部替换为调用该方法,例如岗位标题读取改为dictio["work"] = get_node_text(search2[0])。
3. 修复动态DOM导致的元素引用失效问题
处理完弹窗后,先触发所有懒加载节点渲染,再重新获取完整的岗位元素列表,不要用页面刚加载时拿到的元素列表遍历:
# 等待岗位卡片节点加载完成 wait.until(EC.presence_of_all_elements_located( (By.XPATH, "//div[contains(@class, 'result') and contains(@class, 'job_')]") )) # 滚动到页面底部,触发所有懒加载的岗位卡片渲染 driver.execute_script("window.scrollTo(0, document.body.scrollHeight);") time.sleep(0.5) # 重新获取渲染完成后的完整岗位列表 jobs = driver.find_elements(By.XPATH, "//div[contains(@class, 'result') and contains(@class, 'job_')]")
遍历岗位时直接遍历元素对象,不要用固定索引遍历,同时对每个字段的读取加异常捕获,避免个别广告位缺字段导致脚本中断。
额外优化建议
- 废弃旧版本的
find_elements_by_xpath写法,新版本Selenium统一使用find_elements(By.XPATH, 路径)的语法,避免版本兼容问题。 - 翻页间隔加1-2秒的随机延时,请求频率过高会触发Indeed的反爬机制,后续可能出现验证码、内容替换等更严重的拦截。
内容的提问来源于stack exchange,提问作者Federico Dorato
相关产品推荐
相关产品推荐

