禁用Cookie与JS的Firefox可访问URL,urllib爬取报403 Forbidden
网站检测爬虫的可能机制及解决建议
一、检测机制分析
针对你遇到的403问题,idealista.pt大概率通过以下几种方式识别爬虫:
- 请求头完整性校验:你仅设置了User-Agent,但浏览器正常请求会附带
Accept、Accept-Language、Accept-Encoding、Connection等关键头字段,网站会通过校验请求头的完整性来区分爬虫与真实浏览器。 - SSL握手指纹差异:你使用了空的
ssl.SSLContext(),这和Firefox实际使用的SSL上下文(如支持的加密套件、TLS版本、扩展信息等)差异极大,网站可通过TLS握手时的指纹信息识别爬虫工具。 - 请求行为特征识别:urllib发起请求的模式和浏览器不同,比如缺少浏览器默认的请求前预检逻辑,或者请求数据包的结构、时序不符合人类浏览的常规特征,哪怕单次请求也可能被判定为爬虫。
二、代码修正建议
1. 补全完整请求头
直接复制Firefox请求中的所有头信息,模拟真实浏览器请求:
import urllib.request import ssl import gzip from io import BytesIO USER_AGENT_VALUE = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/111.0' TIMEOUT = 10 def get_page(url): # 复制Firefox的完整请求头 headers = { 'User-Agent': USER_AGENT_VALUE, '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', 'Accept-Encoding': 'gzip, deflate, br', 'Connection': 'keep-alive', 'Upgrade-Insecure-Requests': '1', 'TE': 'Trailers' } req = urllib.request.Request(url, headers=headers) # 使用默认SSL上下文,更接近浏览器配置 context = ssl.create_default_context() response = urllib.request.urlopen(req, context=context, timeout=TIMEOUT) data = response.read() # 处理网站可能返回的gzip压缩内容 if response.info().get('Content-Encoding') == 'gzip': data = gzip.GzipFile(fileobj=BytesIO(data)).read() html = data.decode('utf-8') return html
2. 额外注意事项
如果补全请求头后仍无法访问,可尝试:
- 降低请求频率,避免触发IP限流;
- 使用
requests库配合更贴近浏览器的SSL指纹配置; - 极端情况下用
selenium模拟真实浏览器操作(需注意网站的反爬策略)。
内容的提问来源于stack exchange,提问作者ginjaemocoes
相关产品推荐
相关产品推荐

