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

for循环中urlopen重复调用异常:仅爬取初始页面未跳转下一页

嘿,你遇到的重复爬取初始页面的问题,和urlopen本身完全无关,是代码里的语法错误和逻辑漏洞导致的!我帮你拆解一下问题根源,再给你修正后的解决方案:

问题出在哪?

  1. 错误的finally块位置
    在Python里,finally必须紧紧跟在try-except或try-else结构后面,不能在中间插入其他代码。你现在在try块结束后写了NumOfCrawledPages +=1和Url= URL_Next,才加finally,这会直接触发语法错误(如果你的代码真的运行无报错,大概率是粘贴时格式乱了)。就算侥幸运行,也会打乱执行顺序,导致Url的赋值逻辑失效。

  2. 混乱的URL赋值逻辑
    你在循环里既用if-else分支设置Url,又在循环末尾手动给Url赋值,这种重复操作很容易导致逻辑冲突。如果下一页链接提取失败,URL_Next没被正确更新,下一次循环就会继续用初始URL。

  3. 脆弱的下一页链接提取
    你用page_soup.findAll("li", {"class": "next"})[0].contents[0].get("href")提取下一页链接,太依赖固定的DOM层级了——只要页面里多了个空格、换行或者嵌套标签,这行代码就会出问题,导致URL_Next无法更新。

修正后的代码

import re
from math import ceil
from urllib.request import urlopen as uReq, Request
from bs4 import BeautifulSoup as soup

InitUrl = "https://mtgsingles.gr/search?q="
NumOfCrawledPages = 0
current_url = InitUrl  # 用单一变量跟踪当前要爬的URL,避免混淆
NumOfPages = 5

for i in range(NumOfPages):
    print(f"正在爬取第 {i+1} 页...")
    try:
        # 发起请求并解析页面
        UClient = uReq(current_url)
        page_html = UClient.read()
        UClient.close()

        page_soup = soup(page_html, "html.parser")
        cards = page_soup.findAll("div", {"class": ["iso-item", "item-row-view"]})

        # 提取卡片信息,增加异常处理避免中断
        for card in cards:
            # 提取卡片名称
            try:
                card_name = card.div.div.strong.span.contents[3].contents[0].replace("\xa0 ", "")
            except (IndexError, AttributeError):
                card_name = "无法获取卡片名称"
            
            # 提取P/T信息
            cardP_T = "Does not exist"
            if len(card.div.contents) > 3:
                try:
                    cardP_T = card.div.contents[3].contents[1].text.replace("\n", "").strip()
                except (IndexError, AttributeError):
                    pass
            
            # 提取卡片类型
            try:
                cardType = card.contents[3].text
            except (IndexError, AttributeError):
                cardType = "无法获取卡片类型"
            
            print(f"{card_name}\n{cardP_T}\n{cardType}\n")

        # 优化下一页链接提取,更健壮
        next_li = page_soup.find("li", {"class": "next"})
        if next_li and next_li.a:
            current_url = "https://mtgsingles.gr" + next_li.a.get("href")
            print(f"下一页URL: {current_url}\n")
        else:
            print("没有更多页面了,提前结束爬取\n")
            break  # 没有下一页就跳出循环,避免无效循环

    except Exception as e:
        print(f"爬取第 {i+1} 页时出错: {str(e)}\n")
        break

    NumOfCrawledPages += 1
    print(f"准备爬取第 {NumOfCrawledPages + 1} 页\n")

print(f"爬取完成,共爬取 {NumOfCrawledPages} 页")

关键改进点

  • 移除了错误的finally结构,改用更清晰的异常处理,避免语法错误。
  • 用current_url单一变量跟踪当前爬取地址,彻底解决URL赋值混乱的问题。
  • 给卡片信息提取增加了异常捕获,就算页面结构有小变化,程序也不会直接崩溃。
  • 优化了下一页链接的提取逻辑,用find替代findAll,并检查标签是否存在,更健壮。
  • 增加了提前终止循环的逻辑,当没有下一页时直接跳出,避免无效的循环次数。

内容的提问来源于stack exchange,提问作者Petris

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:31:31