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

Python爬取Mamaearth产品数据报'NoneType'无text属性错误

报错根因

触发AttributeError: 'NoneType' object has no attribute 'text'的直接原因是:你对BeautifulSoup的find()返回结果直接调用.text,但find()没匹配到对应元素时会返回None,None类型没有text属性就会抛出这个错误。结合代码和站点特征,具体触发场景有三个:

  • 你写死的产品名class包含动态哈希值:ProductDetailsRevamp__ProdName-sc-1w9tx2u-1 dTITDo里的dTITDo是CSS模块编译生成的随机字符串,站点做A/B测试、版本迭代、不同品类产品页模板差异时,这个哈希值会变化,部分页面匹配不到对应h1标签就会返回None。
  • 价格选择器兼容性差:你写死匹配td.price,但Mamaearth目前有新旧两套产品页模板,老版用表格布局放价格,新版用div容器承载价格字段,爬取到新版页面时找不到td标签直接返回None。
  • 请求逻辑有缺陷:你遍历产品链接时没有复用已经初始化的Session,也没做状态码校验、延时、重试,部分请求被反爬策略拦截返回验证码/403页面,页面结构完全不符,自然找不到目标元素。

另外代码还有几个隐藏逻辑bug:

  • Product_link字段错误赋值为全局API地址,不是当前遍历的产品详情页URL
  • Prod_list定义在while循环内部,每次翻页都会清空之前爬取的结果
  • DataFrame在单个产品的循环里反复重建,效率极低还容易出现变量未定义问题
修复方案

核心修复思路是:放弃依赖动态哈希类名的定位方式,增加空值判断,补全反爬兼容和异常捕获,修正原有逻辑bug。修正后的可运行代码如下:

from bs4 import BeautifulSoup
import requests
import pandas as pd
import time

base = 'https://mamaearth.in/product/{}'
api_link = 'https://mmrth-nd-api.honasa-production.net/v1/products/shopAllProducts'
params = {
    'pagenumber': 1,
    'pagesize': '20',
    'categoryId': '-1'
}
headers = {
    'Referer': 'https://mamaearth.in/',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
    'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8'
}
Prod_list = []

with requests.Session() as s:
    s.headers.update(headers)
    while True:
        res = s.get(api_link, params=params, timeout=10)
        if res.status_code != 200:
            break
        try:
            container = res.json()['response']['list']['entities']['products']
        except KeyError:
            break
        if not container:
            break
        hreff = []    
        for val in container.values():
            hreff.append(base.format(val['slug']))
        params['pagenumber'] += 1
        
        for product_url in hreff:
            try:
                r = s.get(product_url, timeout=10)
                if r.status_code != 200:
                    time.sleep(2)
                    r = s.get(product_url, timeout=10)
                soup = BeautifulSoup(r.content, "html.parser")
                
                # 兼容多模板定位产品名
                pro_name = None
                name_tag = soup.find('h1')
                if name_tag:
                    pro_name = name_tag.text.strip()
                
                # 兼容新旧模板定位价格
                price = None
                price_tag = soup.find('td', class_='price')
                if not price_tag:
                    price_tag = soup.find('div', class_=lambda x: x and 'price' in x.lower())
                if price_tag:
                    price = price_tag.text.strip()
                
                if not all([pro_name, price]):
                    print(f"跳过解析失败页面:{product_url}")
                    time.sleep(1)
                    continue
                
                Prod_list.append({
                    'Pro_Name': pro_name,
                    'Price': price,
                    'Product_link': product_url,
                })
                print(f"已爬取:{pro_name}")
                time.sleep(0.5)
            except Exception as e:
                print(f"请求{product_url}出错:{str(e)}")
                continue
        print(f"第{params['pagenumber']-1}页爬取完成,累计获取{len(Prod_list)}条有效数据")

df = pd.DataFrame(Prod_list)
df.to_csv('Output.csv', index=False, encoding='utf-8-sig')

关键改动说明:

  • 元素定位不再依赖带随机哈希的完整class名,用标签+模糊class匹配兼容多套页面模板
  • 所有取text的操作前先判断标签是否存在,从根源避免NoneType报错
  • 复用Session保持会话,增加超时、重试、请求延时,降低被反爬拦截的概率
  • 修正了结果列表重置、产品链接赋值错误、DataFrame重复创建的逻辑bug
  • 增加单条请求/解析的异常捕获,单个页面失败不会中断整个爬取流程
  • 导出csv时指定utf-8-sig编码,避免中文乱码

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 04:27:20