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地址,不是当前遍历的产品详情页URLProd_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
相关产品推荐
相关产品推荐

