首页 > 解决方案 > 如果不是 http 200 状态,如何比较变量

问题描述

我目前已经编写了一个网络抓取,我在其中比较了两个值,以查看之前请求与新请求相比是否有任何增加的值。

import json
import re
import time
from dataclasses import dataclass
from typing import Optional, List

import requests
from bs4 import BeautifulSoup


@dataclass
class Product:
    name: Optional[str]
    price: Optional[str]
    image: Optional[str]
    sizes: List[str]

    @staticmethod
    def get_sizes(doc: BeautifulSoup) -> List[str]:
        pat = re.compile(
            r'^<script>var JetshopData='
            r'(\{.*\})'
            r';</script>$',
        )
        for script in doc.find_all('script'):
            match = pat.match(str(script))
            if match is not None:
                break
        else:
            return []

        data = json.loads(match[1])
        return [
            variation
            for get_value in data['ProductInfo']['Attributes']['Variations']
            if get_value.get('IsBuyable')
            for variation in get_value['Variation']
        ]

    @classmethod
    def from_page(cls, url: str) -> Optional['Product']:
        with requests.get(url) as response:
            response.raise_for_status()
            doc = BeautifulSoup(response.text, 'html.parser')

        name = doc.select_one('h1.product-page-header')
        price = doc.select_one('span.price')
        image = doc.select_one('meta[property="og:image"]')

        return cls(
            name=name and name.text.strip(),
            price=price and price.text.strip(),
            image=image and image['content'],
            sizes=cls.get_sizes(doc),
        )


def main():
    product = Product.from_page("https://shelta.se/sneakers/nike-air-zoom-type-whiteblack-cj2033-103")

    previous_request = product.sizes

    while True:
        product = Product.from_page("https://shelta.se/sneakers/nike-air-zoom-type-whiteblack-cj2033-103")

        if set(product.sizes) - set(previous_request):
            print("new changes on the webpage")
            previous_request = product.sizes

        else:
            print("No changes made")

        time.sleep(500)


if __name__ == '__main__':
    main()

我面临的问题是存在产品可以被取下来的情况。例如,如果我现在找到['US 9,5/EUR 43', 'US 10,5/EUR 44,5']了尺寸并且网页被管理员删除并返回 404。几个小时后,他们重新添加网页并再次添加值['US 9,5/EUR 43', 'US 10,5/EUR 44,5']- 这不会打印我们之前已经拥有的值我们之前的有效请求。

我想知道如果网页从 404 返回到 200(即使它们添加相同的值?),打印出这些值的最佳方法是什么?

标签: pythonpython-3.xpython-requestscomparison

解决方案


在这种情况下使用response.raise_for_status()不正确。如果网站返回 404、500 或类似信息,退出您的程序,这只会引发异常。改变response.raise_for_status()

if response.status_code is not 200:
    return cls(None,None,None,None)

编辑,因为我误解了这个问题:

如果发生错误,现在将返回一个空产品。现在唯一需要检查的是尺寸是否发生了变化。

def main():
    url = "https://shelta.se/sneakers/nike-air-zoom-type-whiteblack-cj2033-103"

    previous_product = Product.from_page(url) 
    while True:
        product = Product.from_page(url)
        
        if not product.sizes == previous_product.sizes:
            print("new changes on the webpage")
        else:
            print("No changes made")
        
        previous_product = product
        time.sleep(500)

previous_product已经搬到外面去了。在这种确切的情况下,这并不重要,但它提高了可读性。

的使用set(...) - set(...)已被删除,因为当某些内容从网站上删除时它不会捕获,只有在添加某些内容时才会捕获。如果某些内容首先被删除然后重新添加,那么它也会被您的程序捕获。


推荐阅读