特定URL网页爬取失效:无输出问题排查求助
问题诊断与修复方案
核心问题分析
- 反爬拦截:目标网站会检测请求来源,直接用
requests.get()发送请求会被识别为爬虫,返回空内容或403状态码,导致后续解析不到任何元素。 - 脆弱的选择器:代码中依赖的哈希化class(如
Product-module--container--BMAkS)是前端框架生成的动态类名,会随时变化,导致元素选择失败。 - 未处理空元素:多处直接调用
.text.strip()但未判断元素是否存在,一旦某个元素找不到会直接抛出异常终止程序。
修复步骤
1. 添加请求头模拟浏览器
给requests.get()添加User-Agent等头部信息,绕过基础反爬:
headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36' } r = requests.get(link, headers=headers)
2. 替换为稳定的元素选择器
放弃依赖动态class,改用元素结构、标签属性等更稳定的方式定位元素:
- 产品容器:用
div[data-testid="product-card"](基于页面源码的data属性) - 品牌/型号:从产品标题的文本结构中提取,避免绑定动态类
- 价格:结合价格父容器的特征标签定位,不依赖哈希类名
3. 增加空元素判断,避免崩溃
所有.find()/.select_one()的结果都要先判断是否为None,再调用.text或属性。
修改后的完整代码
import requests from bs4 import BeautifulSoup import pandas as pd link = 'https://store.wom.cl/equipos/portabilidad' headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36', 'Accept-Language': 'es-CL,es;q=0.9' } # 初始请求,主动抛出请求错误 r = requests.get(link, headers=headers) r.raise_for_status() soup = BeautifulSoup(r.content, 'html.parser') data = [] pagina_actual = 1 while True: # 用稳定的data属性定位产品卡片 for e in soup.select('div[data-testid="product-card"]'): # 处理品牌和型号 title_container = e.find('div', class_=lambda c: c and 'PhoneTitle-module--Title' in c) brand = title_container.find('strong').text.strip() if title_container else 'Sin marca' model = title_container.find_all('strong')[-1].text.strip() if title_container and len(title_container.find_all('strong'))>1 else 'Sin modelo' # 处理价格 price_container = e.find('div', class_=lambda c: c and 'PhonePrice-module--Pricing' in c) prev_price = price_container.find('s').text.strip() if price_container and price_container.find('s') else 'Precio no encontrado' current_price = price_container.find('h1').text.strip() if price_container and price_container.find('h1') else 'Precio no encontrado' # 处理产品特性,避免依赖固定索引 features = {} feature_list = e.select('li[class*="PhoneFeatures-module--Features__Item"]') for item in feature_list: key = item.find('span', class_=lambda c: c and 'KeyValue' not in c).text.strip() if item else '' value = item.find('span', class_=lambda c: c and 'KeyValue' in c).text.strip() if item else '' features[key] = value # 处理产品URL cta_button = e.find('button', class_=lambda c: c and 'PhoneCTA-module--ContainerCTA__CTA' in c) product_url = 'https://store.wom.cl' + cta_button.get('data-url', '') if cta_button else 'URL no disponible' d = { 'Marca': brand, 'Modelo': model, 'Capacidad': features.get('Capacidad', 'Sin datos'), 'RAM': features.get('Memoria RAM', 'Sin datos'), 'Cámara': features.get('Cámara principal', 'Sin datos'), 'Pantalla': features.get('Tamaño de pantalla', 'Sin datos'), 'Precio anterior': prev_price, 'Precio actual': current_price, 'URL': product_url } data.append(d) print(f'Página {pagina_actual} procesada.') pagina_actual += 1 # 处理分页 next_page = soup.find('a', class_='next') if next_page and next_page.get('href'): next_url = 'https://store.wom.cl' + next_page.get('href') r = requests.get(next_url, headers=headers) r.raise_for_status() soup = BeautifulSoup(r.content, 'html.parser') else: break # 保存数据 pd.DataFrame(data).to_csv('wom.csv', index=False) print(f'爬取完成,共获取{len(data)}条数据,已保存到wom.csv')
额外说明
r.raise_for_status()会在请求返回4xx/5xx状态码时直接抛出异常,方便快速排查请求问题- 使用
class_=lambda c: c and 'xxx' in c的方式匹配包含特定字符串的class,避免动态哈希值的影响 - 通过遍历特性列表获取键值对,避免依赖固定的
nth-child索引(特性顺序可能变化)
内容的提问来源于stack exchange,提问作者JTB
相关产品推荐
相关产品推荐

