【问题标题】:How do I handle exceptions in BeautifulSoup if the element I'm looking for is not found?如果找不到我要查找的元素,如何处理 BeautifulSoup 中的异常?
【发布时间】:2019-11-11 01:48:49
【问题描述】:

我正在向网站发出 http 请求并解析其内容以查找一些属性值。我需要知道的是,如果代码返回 []None 或什么都不返回,我该如何处理异常。

我尝试过的:

import requests
from urllib3.util.retry import Retry
from requests.adapters import HTTPAdapter
from bs4 import BeautifulSoup

def get_url():

    s = requests.Session()

    retries = Retry(total=5,
                    backoff_factor=10
                    status_forcelist=[ 500, 502, 503, 504 ])

    s.mount('http://', HTTPAdapter(max_retries=retries))

    r = s.get('http://httpstat.us/500')

def find_data():

    soup = BeautifulSoup(r.text, "lxml")
    try:
        id = soup.find('a', class_="class").get('id')
    except:
        print('id not found')
        get_url()

基本上如果id 找不到我想再次发出该GET 请求并尝试找到它。

【问题讨论】:

  • 您可能正在寻找forwhile 循环。一般来说,如果你再次尝试get,它不会返回任何不同的东西,所以请注意,如果你把它放入一个循环中,你最终可能会陷入无限循环。
  • @SumnerEvans 同意,OP 显然只是在寻找一种方法来处理其代码中缺失的元素。
  • 另外,这是完整的代码吗? r 来自哪里?请参阅:minimal reproducible example

标签: python beautifulsoup


【解决方案1】:

您可以应用“先看后跳”(LBYL)原则并检查find() 的结果 - 如果未找到元素,它将返回None。然后,您可以将事物放入循环并在有值时退出,同时使用循环计数器限制来保护自己:

RETRIES = 10

id = None
session = requests.Session()

for attempt in range(1, RETRIES + 1):
    response = session.get(url)
    soup = BeautifulSoup(r.text, "lxml")

    element = soup.find('a', class_="class", id=True)
    if element is None:
        print("Attempt {attempt}. Element not found".format(attempt=attempt))
        continue
    else:
        id = element["id"]
        break

print(id)

情侣笔记:

  • id=True 设置为仅查找存在 id 元素的元素。您也可以使用 CSS selector soup.select_one("a.class[id]") 进行等效操作
  • Session() 有助于在多次向同一主机发出请求时提高性能。在Session Objects 上查看更多信息

【讨论】:

  • 但是如果我希望将请求放在单独的def 中以更好地处理错误怎么办?查看我更新的代码。
【解决方案2】:

如果您只想再次发出相同的请求,您可以执行以下操作:

import requests
from bs4 import BeautifulSoup

def find_data(url):
    found_data = False
    while not found_data:
        r = requests.get(url)
        soup = BeautifulSoup(r.text, "lxml")
        try:
            id = soup.find('a', class_="class").get('id')
            found_data = True
        except:
            pass

如果数据确实不存在,这会使您面临无限循环的风险。您可以这样做来避免无限循环:

import requests
from bs4 import BeautifulSoup

def find_data(url, attempts_before_fail=3):
    found_data = False
    while not found_data:
        r = requests.get(url)
        soup = BeautifulSoup(r.text, "lxml")
        try:
            id = soup.find('a', class_="class").get('id')
            found_data = True
        except:
            attempts_before_fail -= 1
            if attempts_before_fail == 0:
                raise ValueError("couldn't find data after all.")

【讨论】:

  • 但是如果我希望将请求放在单独的def 中以更好地处理错误怎么办?查看我更新的代码。
猜你喜欢
  • 2013-02-10
  • 2020-10-04
  • 1970-01-01
  • 2022-01-20
  • 2018-12-14
  • 1970-01-01
  • 2021-10-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多