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

Selenium使用if-else为Dataclass赋值时出现重复条目问题

问题:爬取cellphones.com.vn商品时出现重复条目

我正在从cellphones.com.vn抓取商品信息(名称、价格、图片、链接),商品价格有两种格式:一种是越南盾字符串(比如1.000.000₫),另一种是文本Giá Liên Hệ(意为“联系询价”)。我希望遇到Giá Liên Hệ时将价格设为0,但运行代码后返回了重复的商品条目。


我的数据类(考虑将current_price改为Decimal类型)

@dataclass
class Item:
  url: str
  name: str
  current_price: str
  place: str
  img: str
  date_add: datetime.datetime

爬虫函数代码

def cellphones(query):
  lists = []
  search = query.replace(' ', '%20')
  url = f"https://cellphones.com.vn/catalogsearch/result?q={search}"
  driver.get(url)
  content = driver.find_element(By.CSS_SELECTOR, "div[id*='search-catalog-page']")
  items = content.find_elements(By.CSS_SELECTOR, "div[class*='product-info']")
  for _ in items:
    if _.find_element(By.CSS_SELECTOR, "p[class*='product__price--show']").text == "Giá Liên Hệ":
      item = Item(
        url=_.find_element(By.CSS_SELECTOR, "a").get_attribute('href'),
        name=_.find_element(By.CSS_SELECTOR, "h3").text,
        current_price=Decimal("0"),
        place="Cellphones",
        img=_.find_element(By.CSS_SELECTOR, "img").get_attribute('src'),
        date_add=datetime.datetime.now()
      )
    else:
      item = Item(
        url=_.find_element(By.CSS_SELECTOR, "a").get_attribute('href'),
        name=_.find_element(By.CSS_SELECTOR, "h3").text,
        current_price=Decimal(_.find_element(By.CSS_SELECTOR, "p[class*='product__price--show']").text.replace("₫", "").replace(".","").replace(" ","")),
        place="Cellphones",
        img=_.find_element(By.CSS_SELECTOR, "img").get_attribute('src'),
        date_add=datetime.datetime.now()
      )
    item, created = Product.objects.update_or_create(
        name=item.name,
        place=item.place,
        defaults={
            'current_price': item.current_price,
            'url': item.url,
            'img': item.img,
            'date_add': item.date_add
        }
    )
    lists.append(item)
  return lists

模板代码

{% block content %}

<p>You searched '<span>{{context.name}}</span>'</p>
<p>Return {{lists|length}} products.</p>
<ul class="d-flex flex-row flex-wrap align-content-center justify-content-around align-items-center list-unstyled">
    {% for p in lists %}
        <li>
            <div class="card h-100 mt-2 border-dark mb-3" style="max-width: 18rem;">
                <img src="{{p.img}}" class="card-img-top" style="height:17.813em;width:auto;" alt="product image">
                <div class="card-body">
                    <h5 class="card-title">{{p.name}}</h5>
                    {% if p.current_price == 0 %}
                        <p class="card-text">Giá Liên Hệ</p>
                    {% else %}
                        <p class="card-text">{{p.current_price|intcomma}}</p>
                    {% endif %}
                    <p class="card-text">Store: {{p.place}}</p>
                    <p class="card-text">Add at {{p.date_add}}</p>
                    <a href="{{p.url}}" target="_blank" class="btn btn-primary">Go to store</a>
                </div>
            </div>
        </li>
    {% endfor %}
</ul>{% endblock %}

重复条目原因及解决方法

原因

重复条目核心问题在于update_or_create的匹配逻辑:仅用name和place作为唯一标识,同一店铺可能存在名称相同但实际为不同商品的情况(比如同型号不同配置的设备);同时页面渲染可能存在重复元素,导致同一商品被多次处理后加入列表。

解决方案

  1. 改用唯一标识匹配
    商品的url是全局唯一的,替换name作为update_or_create的匹配键:

    item, created = Product.objects.update_or_create(
        url=item.url,
        place=item.place,
        defaults={
            'current_price': item.current_price,
            'name': item.name,
            'img': item.img,
            'date_add': item.date_add
        }
    )
    
  2. 页面元素去重
    遍历前先通过url过滤重复的页面元素,避免重复处理:

    processed_urls = set()
    unique_items = []
    for _ in items:
        item_url = _.find_element(By.CSS_SELECTOR, "a").get_attribute('href')
        if item_url not in processed_urls:
            processed_urls.add(item_url)
            unique_items.append(_)
    # 遍历去重后的列表
    for _ in unique_items:
        # 原有商品解析逻辑...
    
  3. 修正数据类类型
    数据类中current_price声明为str,但实际赋值Decimal,类型不匹配需修正:

    from decimal import Decimal
    from dataclasses import dataclass
    import datetime
    
    @dataclass
    class Item:
      url: str
      name: str
      current_price: Decimal
      place: str
      img: str
      date_add: datetime.datetime
    
  4. 模板价格判断优化
    由于current_price为Decimal类型,确保模板中判断逻辑兼容:

    {% if p.current_price == Decimal('0') %}
        <p class="card-text">Giá Liên Hệ</p>
    {% else %}
        <p class="card-text">{{p.current_price|intcomma}}</p>
    {% endif %}
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 18:40:25