You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Python爬虫遇403 Forbidden错误的绕过方案及脚本优化求助

Python爬虫遇403 Forbidden错误的绕过方案及脚本优化求助

看起来你在爬取目标网站时碰到了挺头疼的403权限限制问题,而且即便用cfscrape能拿到首页内容,也存在深层页面无法访问、图片模糊的情况,我来分享一些实用的解决思路和脚本优化方向:

一、绕过403 Forbidden的常见方案

1. 补全更真实的请求头

你之前试过调整headers,但可能没覆盖足够多的关键字段。网站通常会通过请求头识别是否为真实浏览器访问,建议你照搬Chrome/Firefox等主流浏览器的完整请求头,至少包含这些核心字段:

  • User-Agent:用最新的浏览器UA字符串,比如Chrome的Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36
  • Accepttext/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:如果是从某个页面跳转过来的,设置对应页面的URL
  • Cookie:可以手动访问网站,从浏览器开发者工具的Network面板里复制真实Cookie

把这些headers加到你的请求里,示例:

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.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://目标网站域名/"
}
response = scraper.get("website_url", headers=headers)

2. 会话保持与Cookie处理

很多网站会通过Cookie验证用户会话,cfscrape虽然能绕过Cloudflare,但如果网站还有额外的Cookie验证,你可以:

  • 先用浏览器手动访问网站,获取有效Cookie,然后加到scraper的会话中
  • 或者用Selenium/Playwright模拟浏览器打开页面,获取Cookie后传给cfscrape的scraper对象,实现会话复用

3. 高匿代理的合理使用

如果单纯改headers没用,试试高匿代理(避免用透明代理,容易被识别),注意代理的IP地区尽量和目标网站的受众地区一致。在cfscrape中配置代理的方式:

proxies = {
    "http": "http://username:password@proxy_ip:port",
    "https": "https://username:password@proxy_ip:port"
}
scraper.proxies = proxies

4. 控制请求频率

频繁的请求很容易触发反爬机制,建议在每次请求之间加入随机延迟,模拟人类访问节奏:

import time
import random
# 在请求页面或图片后添加
time.sleep(random.uniform(1, 3))  # 随机延迟1-3秒

二、你的Python脚本优化建议

1. 解决深层页面无法访问的问题

当前脚本只爬取了首页,要获取深层页面,需要遍历页面内的链接并递归/循环爬取:

  • 提取页面中所有<a>标签的href属性
  • 过滤掉非目标域名的链接、重复链接
  • 逐个请求这些链接,重复解析、保存的流程

示例代码片段:

from urllib.parse import urljoin, urlparse
visited_urls = set()  # 记录已爬取的URL,避免重复

def crawl_page(url):
    if url in visited_urls:
        return
    visited_urls.add(url)
    response = scraper.get(url, headers=headers)
    soup = BeautifulSoup(response.content, 'lxml')
    # 保存当前页面
    page_filename = urlparse(url).path.split('/')[-1] or 'index.html'
    with open(page_filename, 'w') as f:
        f.write(str(soup))
    # 爬取当前页面的图片(复用你原来的图片处理逻辑)
    # ...
    # 提取并爬取深层链接
    for a_tag in soup.findAll('a', href=True):
        link = urljoin(url, a_tag['href'])
        # 只爬取目标域名下的链接
        if urlparse(link).netloc == urlparse("website_url").netloc:
            crawl_page(link)
            time.sleep(random.uniform(1, 2))

# 启动爬取
crawl_page("website_url")

2. 解决图片模糊的问题

图片模糊大概率是因为你获取的是缩略图地址,很多网站会把原图地址放在data-srcdata-originalsrcset这类属性里,而不是src。修改你的图片处理逻辑:

for img in soup.findAll('img'):
    # 优先尝试获取原图地址,按优先级检查属性
    img_url = None
    if img.get('data-src'):
        img_url = img['data-src']
    elif img.get('data-original'):
        img_url = img['data-original']
    elif img.get('srcset'):
        # srcset通常包含多个分辨率的地址,取最后一个(最高清)
        img_url = img['srcset'].split(',')[-1].strip().split(' ')[0]
    else:
        img_url = img.get('src')
    
    if img_url:
        # 处理相对路径,拼接成绝对URL
        if not img_url.startswith('http'):
            img_url = urljoin("website_url", img_url)
        name = img_url.split('/')[-1]
        name = urllib.parse.unquote(name)
        # 请求图片时加上Referer头,避免防盗链拦截
        img_response = scraper.get(img_url, headers={**headers, "Referer": url})
        with open(name, "wb") as file:
            file.write(img_response.content)
        time.sleep(random.uniform(0.5, 1.5))

如果这样还是拿到模糊图,可能网站需要登录才能获取原图,或者有更严格的防盗链机制,这时候可以考虑用Selenium直接模拟浏览器截图或者获取图片的真实地址。

额外提醒

爬取网站前一定要查看目标网站的robots.txt文件和使用条款,确保你的爬取行为符合规定,避免法律风险。

备注:内容来源于stack exchange,提问作者Bruno Barros

火山引擎 最新活动