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

Python图片下载程序下载到第5张后图片损坏,该如何排查修复及优化?

问题产生原因
  • 未校验HTTP响应状态:代码直接将requests.get()返回的所有内容都作为图片二进制写入文件,若网站触发反爬限流、返回429/403等错误响应时,错误页面的文本内容会被当成图片写入,自然出现损坏,且你使用了无差别的except捕获所有异常,错误不会抛出,程序不会终止。
  • 请求频率过高无间隔:连续快速发起图片请求,大部分网站都会对短时间高频请求做限流,通常前几次请求正常返回,后续请求直接拦截返回非图片内容,和你遇到的第5张之后全部损坏的现象完全吻合。
  • 代码存在未定义变量隐患:getPhotosFromFirstToN函数中直接使用了未赋值的directory、z变量,原代码能运行大概率是粘贴时漏了前置逻辑,变量逻辑错误也会导致文件写入路径、循环范围异常,引发图片损坏。
  • 文件句柄管理不规范:未使用上下文管理器操作文件,若写入过程中出现异常,文件可能没有正常关闭,也会导致本地文件损坏。
解决&优化方案
  • 新增响应状态校验:只有HTTP状态码为200,且响应内容是图片类型时,才写入本地文件,否则触发重试逻辑。
  • 增加请求间隔:每次请求完成后休眠1~2秒,降低触发反爬的概率。
  • 修正变量逻辑:补全directory、z的赋值逻辑,文件夹名可以用传入的资源id命名,避免路径错误。
  • 规范异常捕获和文件操作:指定捕获网络相关异常,不要吞所有错误;用with语句管理文件打开关闭,避免句柄泄漏。
  • 新增重试机制:单张图片请求失败后重试2~3次,仍然失败再标记错误,避免偶发网络波动导致的图片损坏。
优化后代码示例

urlextractor.py

import requests
from bs4 import BeautifulSoup
import os
import time

def id_to_url_conv(id):
    return f'http://web2.anl.az:81/read/page.php?bibid={id}&pno=1'

def getLastPage(url):
    # 修正requests.get参数错误,html.parser是BeautifulSoup的参数,不是requests的
    req = requests.get(url, timeout=10)
    req.encoding = 'utf-8'
    soup = BeautifulSoup(req.text, 'html.parser')
    x = soup.find(id="last_link")
    if not x:
        return 1
    z = str(x)
    page_number = ''
    index = z.find('pno')
    for i in range(index+4, len(z)):
        if z[i] != '"':
            page_number += z[i]
        else:
            break
    return int(page_number) if page_number.isdigit() else 1

def getPhotosFromFirstToN(id1, number):
    # 补全目录定义,用id作为文件夹名,避免重复
    directory = f'bibid_{id1}'
    # 目录已存在就不重复创建
    if not os.path.exists(directory):
        os.mkdir(directory)
    # 补全z的定义,从第1页开始下载
    z = 0
    for i in range(z + 1, number + 1):
        photourl = f'http://web2.anl.az:81/read/img.php?bibid={id1}&pno={i}'
        retry_count = 0
        # 单张图最多重试3次
        while retry_count < 3:
            try:
                resp = requests.get(photourl, timeout=10)
                # 校验响应状态和内容类型是否为图片
                if resp.status_code == 200 and 'image' in resp.headers.get('Content-Type', ''):
                    # 用with管理文件句柄,自动关闭
                    with open(f'{directory}/p{i}.png', 'wb') as fhand:
                        fhand.write(resp.content)
                    print(f'page number {i} has been created {round(i/number * 100, 2)}%')
                    break
                else:
                    retry_count += 1
                    print(f'#{i} request failed, status code: {resp.status_code}, retry {retry_count}')
                    time.sleep(2)
            except Exception as e:
                retry_count += 1
                print(f'#{i} error occured: {str(e)}, retry {retry_count}')
                time.sleep(2)
        if retry_count >= 3:
            print(f'#{i} download failed after 3 retries')
        # 每次请求后休眠1秒,控制频率
        time.sleep(1)

main.py

import urlextractor
import time
import sys

if __name__ == '__main__':
    n = input('enter id:')
    url = urlextractor.id_to_url_conv(n)
    maxpage = urlextractor.getLastPage(url)
    print(f'This is max page==>{maxpage}')
    m = int(input('Sehife sayi:'))
    if m < int(maxpage):
        urlextractor.getPhotosFromFirstToN(n, m)
    else:
        print('You have exceeded max page limit')
        time.sleep(3)
        sys.exit()

内容的提问来源于stack exchange,提问作者ICY Counter-Strike and League

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.14 09:15:02