🚀 爬虫工程师高频面试题精选

大家好!这篇文章是我整理的爬虫工程师面试高频20问精简优化版——去掉原内容重复项,补了实用的代码片段,加了重点折叠提示,控制在2k多字,方便快速刷面试题~


一、 爬虫基础认知(必背入门5题)

1. 简述爬虫定义及大厂版优化流程

普通版是「请求→响应→解析→存储」,大厂加分版流程是这样的:

  1. 去重层:请求前先过布隆/Redis Set去重
  2. 请求控制层:构造合规Header、选代理IP、加自适应延迟
  3. 请求/响应异常捕获层:try-except超时、连接、状态码异常
  4. 响应解析层:选合适的解析器
  5. 存储前置去重层:避免重复入数据库
  6. 监控告警层:失败率、解析率异常触发通知

2. GET与POST在爬虫中的实战区别(选API时的关键)

维度GETPOST
参数位置URL拼接(显式可见)Request Body(可隐蔽)
长度限制浏览器/服务器限制(约2KB)无明确限制(JSON可带大对象)
爬虫用途翻页、公开数据获取(首选!)登录、敏感查询、大表单提交
缓存触发易被浏览器/CDN缓存很少被缓存

3. 常见HTTP状态码的爬虫应对逻辑

原文章只说了含义,这里加个面试能说的应对:

  • 200 OK:先检查返回内容是不是真数据(反爬可能返回空壳HTML!)
  • 301/302 Redirect:requests默认自动跟随,可关了抓Location字段;Scrapy在DOWNLOADER_MIDDLEWARES可自定义处理
  • 403 Forbidden:大概率触发反爬(UA被识别、IP超限、缺Referer/Cookie)
  • 404 Not Found:要么URL拼错,要么页面失效,设置重试上限后标记
  • 500 Internal Server Error:服务器问题,设置指数退避重试

4. GET请求带参数的代码示例

用Python的requests库(新手必备)和httpx库(支持异步)写个:

# requests 同步写法
import requests

url = "https://api.example.com/data"
params = {
    "page": 1,
    "size": 20,
    "keyword": "爬虫面试"
}
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36"
}

response = requests.get(url, params=params, headers=headers, timeout=10)
print(response.json())

5. HTTP与HTTPS的区别,爬虫生产环境怎么处理SSL

HTTPS = HTTP + SSL/TLS加密层,传输更安全但握手慢、可能有证书问题。 生产环境不要随便加verify=False(虽然简单,但会有安全警告+可能被反爬识别),建议:

  1. 更新certifi库:pip install --upgrade certifi
  2. 如果是自签名证书,手动指定路径:verify="/path/to/your/self-signed.crt"

二、 数据解析与去重(工程化5题)

6. 三大主流解析器的使用场景决策树

原文章直接列优缺点,画决策树更直观:

flowchart TD
    A[拿到原始数据] --> B{数据类型}
    B -->|JSON/结构化JS变量| C[Python json/execjs取JSON片段]
    B -->|HTML/XHTML| D{定位需求复杂度}
    D -->|层级溯源(找父/祖节点)| E[lxml+XPath]
    D -->|前端语法习惯/简单定位| F[BeautifulSoup+CSS选择器/lxml+CSS选择器]
    D -->|非标签内容/简单字符串提取| G[Python re]

7. 布隆过滤器(Bloom Filter)亿级URL去重的首选

原文章说了优点和原理,这里补个Python代码实现+Redis版本的提示(面试常问如何用Redis做持久化布隆):

# 本地内存版(小规模测试用)
import mmh3
from bitarray import bitarray

class SimpleBloomFilter:
    def __init__(self, capacity=1e8, error_rate=0.001):
        self.capacity = int(capacity)
        self.error_rate = error_rate
        self.bit_size = self._get_bit_size()
        self.hash_count = self._get_hash_count()
        self.bit_array = bitarray(self.bit_size)
        self.bit_array.setall(0)
    
    def _get_bit_size(self):
        from math import log, ceil
        return ceil(-self.capacity * log(self.error_rate) / (log(2)**2))
    
    def _get_hash_count(self):
        from math import log
        return round(self.bit_size / self.capacity * log(2))
    
    def add(self, url):
        for i in range(self.hash_count):
            index = mmh3.hash(url, i) % self.bit_size
            self.bit_array[index] = 1
    
    def contains(self, url):
        for i in range(self.hash_count):
            index = mmh3.hash(url, i) % self.bit_size
            if not self.bit_array[index]:
                return False
        return True
生产环境Redis版本

推荐用redis-py-cluster+pyprobables库,或者Redis 4.0+的BF.ADD/BF.EXISTS原生布隆过滤器命令!

8. 亿级爬虫数据库选型优先选MongoDB的3个核心原因

原文章说了3点,这里简化成面试能快速讲的:

  1. Schema-free(无固定表结构):目标站页面改版、字段变动不用改表
  2. 完美支持JSON嵌套:直接存API返回的结构化数据
  3. 横向扩展(分片集群):处理TB/PB级数据比MySQL简单得多

9. MongoDB爬虫字段去重的2种方法

方法1:设置唯一索引(最简单)
from pymongo import MongoClient, ASCENDING

client = MongoClient("mongodb://localhost:27017/")
db = client["spider_db"]
collection = db["product_data"]

# 对url字段设置唯一索引
collection.create_index([("url", ASCENDING)], unique=True)

# 插入时忽略重复项(不抛错)
collection.insert_one({"url": "https://example.com/1", "name": "测试"}, upsert=False)

::: :::details 方法2:插入前用Redis Set/Bloom预检查(高性能) 如果同时有爬虫请求层和存储层去重,重复率会更低!


三、 反爬突破与工具选型(核心攻坚8题)

10. 反爬手段的分类速记表

原文章列了4类,这里用emoji+关键示例速记:

  • 🕵️ 身份类:UA/Referer/Cookie检查、TLS JA3指纹识别
  • ⏱️ 行为类:IP访问频率/时长/请求数限制、单IP多Cookie限制
  • 🚫 内容类:JS动态渲染、CSS偏移视觉欺骗、FontAwesome字体加密
  • 🤖 交互类:滑块/文字点选/旋转验证码

11. IP封禁问题的4个核心解决方向

  1. 代理IP池:自建或接入高匿代理(透明代理会暴露真实IP)
  2. 自适应爬取延迟:不要用固定延迟,用random.uniform(1, 3)模拟人类点击
  3. 分布式爬虫:多台机器/多个Docker容器分散流量
  4. 寻找备用接口:优先找App端接口(验证强度通常比PC端低)

12. JS动态渲染的3种实战方案

:::warning 首选方案:逆向API接口! 直接抓F12 Network里的XHR/Fetch请求,获取结构化JSON,性能比渲染工具高10-100倍! ::: 如果找不到API接口,再用渲染工具:

  1. Playwright/Puppeteer:现代化无头浏览器,性能比Selenium好,带自动等待功能
  2. Selenium+undetected-chromedriver:适合老项目,能绕过大部分基础的浏览器特征检测

13. Selenium/Playwright降低被识别风险的3个小技巧

  • undetected-chromedriver(Selenium)或playwright.chromium.launch(headless=False, args=["--disable-blink-features=AutomationControlled"])(Playwright)隐藏navigator.webdriver等特征
  • 伪造真实的用户UA、视口尺寸、鼠标轨迹、键盘输入速度
  • 不要开太快的自动化操作,加page.wait_for_timeout(random.uniform(500, 1500))模拟人类思考

14. 字体加密(Iconfont)的基础处理流程

  1. 下载目标站的.woff/.ttf字体文件
  2. fontTools库将字体文件转成XML或TXT格式,获取字符编码和坐标的映射关系
  3. OCR(如pytesseract)或坐标比对还原真实字符

15. JS逆向的入门工具速查

  • 调试工具:Chrome DevTools(Sources面板断点调试)
  • 执行工具PyExecJSnodejs(直接写JS脚本执行)
  • 还原工具:AST抽象语法树(如js-beautify解基础混淆,obfuscator-io-deobfuscator解OB混淆)

16. TLS JA3指纹检测的2024-2026年主流绕过方案

JA3指纹是服务器通过检查客户端SSL握手时的特征(如TLS版本、加密套件、椭圆曲线)来判断是否为Python requests/urllib。 主流绕过库:

  1. curl_cffi:模拟Chrome/Firefox的JA3/JA4指纹
  2. httpx:支持自定义TLS配置(需手动调,不如curl_cffi方便)

17. 验证码处理的降维打击优先策略

:::warning 千万不要一开始就上AI模型/打码平台! 成本高、速度慢! ::: 优先顺序:

  1. 找App端/小程序端/轻量版网页(通常无验证码或验证强度极低)
  2. 找是否有Cookie复用的可能(登录一次后保存Cookie,长期使用)
  3. 最后才用打码平台(便宜的如超级鹰)或AI模型(字符用CNN,滑块用YOLO+OpenCV模板匹配+贝塞尔曲线轨迹模拟)

四、 工程化与合规(收尾2题)

18. 高可用爬虫的核心设计思路(口述必背)

  1. 调研阶段:分析目标站数据加载方式(静态/动态)、找隐藏接口、robots.txt检查、robots协议遵守
  2. 架构设计阶段:协程/框架选一个(中小规模用aiohttp+asyncio,大规模用Scrapy-Redis)、监控告警模块(Prometheus+Grafana+飞书/钉钉机器人)、持久化模块
  3. 健壮性设计阶段:异常捕获+指数退避重试、随机UA+随机Referer+随机代理切换、双重去重(请求层+存储层)
  4. 合规设计阶段:设置合理的QPS(每秒请求数)、不给对方运维增加压力、不爬取敏感数据

19. 爬虫工程化的3个核心工具链

  • 开发工具:Python 3.10+、PyCharm/VS Code、Chrome DevTools
  • 部署工具:Docker、Docker Compose、K8s(大规模用)
  • 监控告警工具:Prometheus(监控指标采集)、Grafana(可视化展示)、Alertmanager(告警规则配置)、飞书/钉钉/企业微信机器人(告警通知)

五、 彩蛋:面试时的加分金句

  1. 「我一般会在抓取前先检查robots.txt,遵守Disallow规则」
  2. 「我通常会优先找App端接口,验证强度比PC端低,性能也更好」
  3. 「我会用双重去重(请求层布隆+存储层唯一索引),降低重复率」
  4. 「我会用Prometheus+Grafana监控抓取成功率、403率、数据增长曲线,异常时会用飞书机器人秒级通知」