Python使用requests-html爬取网页提取数据随机出现AttributeError怎么办
错误原因
你遇到的报错本质是find方法未匹配到对应元素时返回了None,直接调用.text属性触发空对象属性异常。随机报错的核心诱因有3个:
- Google Shopping页面为动态渲染,默认渲染时长不足会导致部分节点未加载完成
- 部分商品报价行本身无对应价格节点
- 不同商品页的价格标签类名存在动态调整的情况,你加的全局延迟没有作用在渲染等待环节,所以无法解决问题
修复方案
1. 调整渲染参数,确保动态节点加载完整
给render方法添加sleep参数指定渲染后等待时长,同时拉长超时阈值避免渲染中断:
r.html.render(sleep=2, timeout=20)
2. 节点提取前添加非空校验
提取价格节点时先判断是否匹配成功,匹配失败可以赋值默认值或者直接跳过当前异常行:
preis_elem = article.find('div.drzWO', first=True) # 匹配失败跳过当前行 if not preis_elem: continue preis = preis_elem.text
如果需要保留无价格的行,可以替换为:
preis = preis_elem.text if preis_elem else '价格未公示'
3. 添加备选选择器提升兼容性
可以补充多个价格相关的选择器做兜底,避免类名动态变化导致匹配失败:
preis_elem = article.find('div.drzWO', first=True) or article.find('span.sh-price__current', first=True)
4. 添加请求头规避反爬
Google Shopping会拦截无标识的爬虫请求,返回异常页面导致节点匹配失败,请求时添加浏览器UA即可:
headers = { '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' } r = session.get(url, headers=headers)
修复后完整代码
from requests_html import HTMLSession import csv import time # csv_file = open('beoscrape.csv', 'w', encoding='utf-8-sig') # csv_writer = csv.writer(csv_file) # csv_writer.writerow(['Produkt', 'Retailer', 'Preis']) session = HTMLSession() headers = { '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' } url = 'https://www.google.com/shopping/product/16302210309954970571/offers?q=OLED+65+G19+LA&newwindow=1&prds=cid:16302210309954970571,eto:856723695612861771_0,scoring:tp' r = session.get(url, headers=headers) # 渲染后等待2秒,超时时间设为20秒 r.html.render(sleep=2, timeout=20) produktscan = r.html.find('title') produkt = produktscan[0].text produkt = produkt.replace(' | Google Shopping', '') for article in r.html.find('tr.sh-osd__offer-row'): retailer_elem = article.find('div.kPMwsc', first=True) if not retailer_elem: continue retailer = retailer_elem.full_text retailer = retailer.replace('Wird in einem neuen Fenster geöffnet', '').strip() # 价格节点非空校验+兜底选择器 preis_elem = article.find('div.drzWO', first=True) or article.find('span[class*="price"]', first=True) if not preis_elem: continue preis = preis_elem.text.strip() print(produkt) print(retailer) print(preis) print('-'*30) # csv_writer.writerow([produkt, retailer, preis]) # csv_file.close()
内容的提问来源于stack exchange,提问作者Kattamaran
相关产品推荐
相关产品推荐

