使用BeautifulSoup/Selenium无法爬取Canadian Tire等站点商品数据求助
问题根因分析
你遇到的是当前主流电商站点爬取的典型问题,核心原因有3个:
- Canadian Tire、沃尔玛这类站点均采用前端客户端渲染(CSR),商品数据是页面加载完成后由JS异步请求后端接口拉取并渲染到页面的,直接用requests请求初始HTML文档时,返回内容里根本没有商品相关节点,BeautifulSoup自然定位不到元素
- 现有Selenium代码存在两处明显错误:一是没有加等待逻辑,页面还没完成异步加载就执行节点查找,必然返回空;二是选择器语法错误,多类名选择器需要用
.分隔而非空格,你写的h3.product-tile-srp__title grid--grid-view__item会被识别为找h3节点的后代grid--grid-view__item节点,完全匹配不到目标元素 - BeautifulSoup定位价格的代码写法错误,
find_all('price__now--value-srp')没有指定属性类型,系统会将这段值识别为标签名而非class属性,当然找不到对应节点
可落地解决方案
方案1:直接调用后端数据接口(首选,效率最高)
所有动态渲染的电商站点,商品数据都是通过公开的后端接口返回JSON格式数据的,你不需要解析HTML,直接抓接口请求即可:
打开浏览器F12开发者工具,切换到「网络」面板,筛选「XHR/提取」分类,刷新页面后就能找到带商品列表的接口,复制对应的请求头、请求参数用requests发起请求,直接从返回的JSON里提取商品名、价格字段即可,比解析HTML效率高10倍以上,也不容易触发反爬。
方案2:修正Selenium代码(适合不想抓接口的场景)
不需要写复杂的JS计算样式,直接修正等待逻辑和选择器即可正常取数,改好的Canadian Tire站点代码参考如下:
def check_price_ct(): options = webdriver.ChromeOptions() options.add_argument("start-maximized") options.add_experimental_option("excludeSwitches", ["enable-automation"]) options.add_experimental_option('useAutomationExtension', False) # 无需可视化的话可以开启无头模式,不弹出浏览器窗口 # options.add_argument("--headless=new") driver = webdriver.Chrome(options=options) driver.get('https://www.canadiantire.ca/en/search-results.html?index=product;lang=en;q=*;m_ct_sort=sort-rating-desc;x1=s.regional-promotion;q1=T;x2=HIDECROSSMERCH;q2=T;x3=s.save-percentage;q3=0.4-1;x4=s.store-list.instock;q4=true;x5=s.regional-price-range;q5=25-99.99%7C25-49.99%7C50-99.99%7C0-24.99;page=3') Product_Name = [] Product_Current_Price = [] Product_Regular_Price = [] try: # 显式等待最多10秒,直到商品节点完成加载 WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.CSS_SELECTOR, 'h3.product-tile-srp__title.grid--grid-view__item')) ) # 提取商品名称 name_nodes = driver.find_elements(By.CSS_SELECTOR, 'h3.product-tile-srp__title.grid--grid-view__item') for node in name_nodes: Product_Name.append(node.text.strip()) # 提取当前售价 price_nodes = driver.find_elements(By.CSS_SELECTOR, 'span.price__total-value.price__total--on-sale') for node in price_nodes: Product_Current_Price.append(node.text.strip()) # 提取原价 regular_price_nodes = driver.find_elements(By.CSS_SELECTOR, 'span.product-tile__price-total-value-from.product-tile__regular-price--on-sale') for node in regular_price_nodes: Product_Regular_Price.append(node.text.strip()) # 补全店铺字段 From_Which_Store = ["Canadian Tire"] * len(Product_Name) finally: driver.quit() return np.transpose([Product_Name, Product_Current_Price, Product_Regular_Price, From_Which_Store])
沃尔玛站点适配说明
沃尔玛带data-automation属性的节点直接用属性选择器定位即可,比如商品名选择器写[data-automation="product-title"],价格选择器写[data-automation="product-price"],不管是Selenium还是渲染后的BeautifulSoup对象都可以直接匹配到。
反爬规避提示
- 多站点爬取时添加随机延迟,避免短时间发起大量请求触发封禁
- 可定期轮换User-Agent,访问量大的场景建议搭配代理IP池使用
- 爬取前确认站点robots.txt规则,不要爬取站点明确禁止抓取的内容
内容的提问来源于stack exchange,提问作者JWinkelm
相关产品推荐
相关产品推荐

