微信关注,获取更多

跟着AI学Python 第17课:爬虫请求优化 — Session + 超时重试

第1段:Session — 让请求之间”认识”彼此

# 普通请求:像每次换一个浏览器访问
resp1 = requests.get("https://books.toscrape.com")
print(f"普通请求:状态码 {resp1.status_code}")

# Session请求:像同一个浏览器在访问,自动管理Cookie
session = requests.Session()
session.headers.update({
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
})

resp2 = session.get("https://books.toscrape.com")
print(f"Session请求:状态码 {resp2.status_code}")
print(f"Session获得Cookie:{dict(session.cookies)}")

# 第2次请求自动带上Cookie,网站觉得你是"老访客"
resp3 = session.get("https://books.toscrape.com/catalogue/page-2.html")
print(f"第2次Session请求:状态码 {resp3.status_code}")

核心概念:

对比 普通请求 Session请求
比喻 每次换一个浏览器 同一个浏览器
Cookie 不保持 自动带上
登录状态 每次丢失 保持登录

第2段:Session的采购场景

print("场景1:访问需要登录的供应商网站")
print("  - 普通请求:每次都是'陌生人',登录状态丢失")
print("  - Session:保持登录状态,登录一次,后面自动带Cookie")
print()
print("场景2:网站根据Cookie给你推荐内容")
print("  - 普通请求:每次看到默认页面")
print("  - Session:网站知道你来过,给你个性化内容")
# 用Session抓一页数据试试
from bs4 import BeautifulSoup

resp = session.get("https://books.toscrape.com", timeout=10)
soup = BeautifulSoup(resp.text, "lxml")
books = soup.find_all("article", class_="product_pod")[:5]

print("用Session抓取前5本书:")
for i, book in enumerate(books, 1):
    name = book.h3.a["title"]
    price = book.find("p", class_="price_color").text
    print(f"  {i}. {name} - {price}")

第3段:超时设置 — 不让程序卡死

# 没有超时:如果网站没响应,程序会一直等下去(卡死)
# 设置超时:超过指定秒数就放弃,程序继续运行

try:
    # timeout=15表示最多等15秒
    resp = session.get("https://books.toscrape.com", timeout=15)
    print(f"正常响应:状态码 {resp.status_code}")
except requests.exceptions.Timeout:
    print("请求超时!15秒内没收到响应")
except Exception as e:
    print(f"请求出错:{e}")

核心概念:

  • timeout=15 — 最多等15秒
  • requests.exceptions.Timeout — 超时异常
  • 不设超时 → 网站没响应程序永远卡住

第4段:safe_get超时重试 — 失败了自动再试

USER_AGENTS = [
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0",
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Edg/120.0.0.0",
]

def safe_get(url, max_retries=3, timeout=10):
    """安全的请求函数:超时自动重试"""
    for attempt in range(1, max_retries + 1):
        try:
            ua = random.choice(USER_AGENTS)
            headers = {"User-Agent": ua}
            resp = session.get(url, headers=headers, timeout=timeout)
            resp.raise_for_status()           # 状态码非200就抛异常
            return resp
        except requests.exceptions.Timeout:
            print(f"  第{attempt}次超时,重试中……")
        except requests.exceptions.ConnectionError:
            print(f"  第{attempt}次连接失败,重试中……")
        except requests.exceptions.HTTPError as e:
            print(f"  HTTP错误:{e}")
            return None
        except Exception as e:
            print(f"  未知错误:{e}")
            return None

        if attempt < max_retries:
            wait = random.uniform(2, 5)     # 随机等2-5秒再重试
            time.sleep(wait)

    print(f"  重试{max_retries}次均失败")
    return None

# 测试
resp = safe_get("https://books.toscrape.com")
if resp:
    print(f"请求成功!页面大小:{len(resp.text)}字符")

safe_get 的流程:

请求 → 成功?→ 返回结果
         ↓失败
      随机等2-5秒 → 重试
         ↓再次失败
      再等再试(最多3次)
         ↓全失败
      返回None,程序继续运行不崩溃

第5段:实战 — 用safe_get翻页抓取

all_books = []

for page in range(1, 4):
    url = f"https://books.toscrape.com/catalogue/page-{page}.html"
    print(f"正在采集第{page}页……")

    resp = safe_get(url)
    if not resp:
        continue

    soup = BeautifulSoup(resp.text, "lxml")
    books = soup.find_all("article", class_="product_pod")

    for book in books:
        name = book.h3.a["title"]
        price = book.find("p", class_="price_color").text
        all_books.append({"name": name, "price": price})

    time.sleep(1)

print(f"\n共抓取 {len(all_books)} 本书")
print("前5本:")
for i, b in enumerate(all_books[:5], 1):
    print(f"  {i}. {b['name']} - {b['price']}")

# 保存到JSON
filepath = os.path.join(DIR, "books_session.json")
with open(filepath, "w", encoding="utf-8") as f:
    json.dump(all_books, f, ensure_ascii=False, indent=2)
print(f"\n已保存到:{filepath}")

第17课核心速查:

操作 代码
创建Session session = requests.Session()
设置请求头 session.headers.update({"User-Agent": "..."})
Session请求 session.get(url)
超时设置 session.get(url, timeout=15)
状态码检查 resp.raise_for_status()
封装重试函数 safe_get(url, max_retries=3)
随机等待 time.sleep(random.uniform(2, 5))

未经允许不得转载:百花谷博客 » 跟着AI学Python 第17课:爬虫请求优化 — Session + 超时重试

评论

4+7=

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏