标签,该标签同时承载跳转链接(href 属性)和职位标题(其内部 的文本内容)。因此,应优先采用基于 class 和语义标签的相对 XPath,而非深度定位的绝对路径。
✅ 推荐 XPath 表达式如下:
-
提取所有职位 URL(href 属性值):
//div[@class="col-sm-9"]/a/@href
-
提取所有职位标题(
文本): //div[@class="col-sm-9"]/a/h2/text()
-
一次性获取 URL 与标题(混合结果,按文档顺序交替):
//div[@class="col-sm-9"]/a/@href | //div[@class="col-sm-9"]/a/h2/text()
在 Scrapy Shell 中实际使用示例:
# 启动请求并抓取响应
r = scrapy.Request('https://www.northropgrumman.com/jobs?remote=yes-may-consider-full-time-teleworking-for-this-position&country=united-states-of-america&_job_category=global-supply-chain,business-management,program-management')
fetch(r)
# 获取职位链接列表(相对路径,需拼接 base_url)
urls = response.xpath('//div[@class="col-sm-9"]/a/@href').getall()
# 输出示例: ['/jobs/Business-Management/Contract/.../R10151186/principal-sr-principal-contract-administrator', ...]
# 获取职位标题列表
titles = response.xpath('//div[@class="col-sm-9"]/a/h2/text()').getall()
# 输出示例: ['Principal / Sr Principal Contract Administrator', ...]
# 验证数量一致,便于 zip 组合
assert len(urls) == len(titles), "URL 与标题数量不匹配,请检查页面结构是否动态加载"
⚠️ 注意事项:
- 所有 href 均为相对路径,在 Scrapy 中建议用 response.urljoin(href) 自动补全为绝对 URL;
- 若页面启用 JavaScript 渲染(如 React 动态注入),response 可能不含完整职位数据,此时需配合 Splash 或 Playwright;
- col-sm-9 是 Bootstrap 布局类,稳定性较高;若未来改版,可先用 response.css('div.col-sm-9 a::attr(href)').getall() 作为 CSS 选择器备选方案;
- 始终用 .getall() 而非 .get() 进行调试,避免因单条缺失导致静默失败。
总结:XPath 的健壮性不在于“精准到第几个 div”,而在于锚定具有业务含义的容器与标签。抓住 div.col-sm-9 → a → h2 这一稳定结构链,即可实现高复用、低维护的职位数据抽取。