You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无法抓取Indeed/LinkedIn数据:403错误及元素定位问题求助

问题解决指南:爬虫403拦截与元素定位失败

一、403响应问题(Indeed/LinkedIn职位页面)

原因

Indeed和LinkedIn的职位页面都有严格的反爬机制,直接用requests请求会被识别为爬虫:

  • 请求头信息不足或UA版本过旧(你使用的Chrome 77版本太老,易被检测)
  • 缺少会话维持(未处理Cookie)
  • 请求频率过高,触发IP限制
  • LinkedIn还会检测浏览器指纹,普通Selenium易被识别

解决方案

  1. 更新请求头并使用Session维持会话
    补充必要的请求头字段,用requests.Session()自动处理Cookie,模拟真实用户会话:

    import requests
    session = requests.Session()
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
        "Accept-Language": "en-US,en;q=0.5",
        "Referer": "https://www.indeed.co.in/",
        "Connection": "keep-alive"
    }
    session.headers.update(headers)
    
  2. 控制请求频率
    每次请求后加入2-5秒延迟,避免触发频率限制:

    import time
    time.sleep(3)
    
  3. 针对LinkedIn:使用指纹绕过工具
    普通Selenium易被检测,改用undetected-chromedriver或Playwright,绕过浏览器指纹验证。

二、元素定位失败问题

原因

  • 页面内容动态渲染:requests获取的静态HTML中不存在目标元素(比如Indeed的职位卡片由JS加载)
  • 元素的class/id动态生成:Indeed/LinkedIn会随机更新元素标识,依赖固定id/class定位会失效
  • 内容嵌套在iframe中:部分页面内容需切换iframe才能访问

解决方案

  1. 处理动态渲染页面
    改用支持JS渲染的工具(如Playwright、undetected-chromedriver),替代requests+BeautifulSoup。

  2. 使用稳定选择器
    避免依赖易变的class/id,优先选择:

    • data-testid属性(网站用于测试的标识,通常不会频繁变更)
    • 标签结构+文本特征
    • CSS选择器(如div[data-testid="mosaic-jobResults"])
  3. 修正代码中的空值判断
    你当前代码中outer_most_point可能为None(因为403返回的页面没有目标元素),导致调用find('ul')触发AttributeError。需先判断元素是否存在:

    outer_most_point = soup.find('div', attrs={'id': 'mosaic-provider-jobcards'})
    if outer_most_point:
        ul_element = outer_most_point.find('ul')
        if ul_element:
            for i in ul_element:
                # 处理逻辑
                pass
    else:
        print("目标容器未找到,检查页面结构或反爬状态")
    

修正后的完整示例(Indeed爬虫)

import requests
from bs4 import BeautifulSoup
import time
import pandas as pd

session = requests.Session()
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
    "Accept-Language": "en-US,en;q=0.5",
    "Referer": "https://www.indeed.co.in/",
    "Connection": "keep-alive"
}
session.headers.update(headers)

skill = input('Enter your Skill: ').strip()
place = input('Enter the location: ').strip()
no_of_pages = int(input('Enter the # of pages to scrape: '))

job_data = []

for page in range(no_of_pages):
    # 编码特殊字符,避免URL错误
    url = f'https://www.indeed.co.in/jobs?q={requests.utils.quote(skill)}&l={requests.utils.quote(place)}&sort=date&start={page * 10}'
    
    try:
        response = session.get(url)
        response.raise_for_status()
        print(f"Page {page+1} Status: {response.status_code}")
        
        soup = BeautifulSoup(response.text, 'lxml')
        # 使用稳定的选择器定位职位容器
        job_container = soup.find('div', {'data-testid': 'mosaic-jobResults'}) or soup.find('div', class_='jobsearch-JobSearchResults')
        
        if job_container:
            job_cards = job_container.find_all('div', class_='job_seen_beacon')
            for card in job_cards:
                title = card.find('h2').get_text(strip=True) if card.find('h2') else 'N/A'
                company = card.find('span', class_='companyName').get_text(strip=True) if card.find('span', class_='companyName') else 'N/A'
                location = card.find('div', class_='companyLocation').get_text(strip=True) if card.find('div', class_='companyLocation') else 'N/A'
                job_data.append({"Title": title, "Company": company, "Location": location})
        else:
            print(f"Page {page+1}: 未找到职位容器,可能页面结构变更或被反爬拦截")
        
        time.sleep(3)
        
    except requests.exceptions.HTTPError as e:
        print(f"Page {page+1} HTTP错误: {e}")
    except Exception as e:
        print(f"Page {page+1} 错误: {e}")

# 保存数据到CSV
pd.DataFrame(job_data).to_csv('indeed_jobs.csv', index=False)
print(f"抓取完成,共{len(job_data)}条职位数据")

内容的提问来源于stack exchange,提问作者KRISHNANDU RANJN ROY

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 17:35:36