网页爬取技术求助:如何实现单条商品信息与对应价格的关联输出?
解决商品价格与对应信息匹配的问题
看起来你遇到的核心问题是价格选择器没有绑定到当前遍历的商品节点,而是全局查找所有价格,所以每次循环都会输出所有商品的价格。另外你混合使用了requests和Selenium两种页面获取方式,这也容易导致数据不匹配(比如requests拿到的是初始静态页面,而Selenium是浏览器渲染后的页面)。
问题根源
你当前的价格代码:
spans = browser.find_elements_by_css_selector("div.GC20.ProductPrice span") for i in range(0,len(spans),2): span = spans[i].text print(span)
这段代码是在整个页面范围内查找所有价格span,而不是在当前的product节点下查找,所以每次遍历单个商品时,都会把所有商品的价格打印一遍。
解决方案:统一页面获取方式,绑定价格到单个商品
我们可以选择两种方式之一来修复,推荐优先用BeautifulSoup(如果价格是静态渲染的),如果页面价格是JS动态加载的,再切换到纯Selenium方案。
方案1:纯BeautifulSoup实现(静态内容)
修改价格部分的代码,在当前product节点内部查找价格元素,而不是全局查找:
from bs4 import BeautifulSoup import requests import csv import json import os os.environ["PYTHONIOENCODING"] = "utf-8" URL = 'https://www.mcavoyguns.co.uk/contents/en-uk/d130_Beretta_Over___Under_Competeition_shotguns.html' page = requests.get(URL) soup = BeautifulSoup(page.content, 'html.parser') products = soup.find_all("div", "GC62 Product") # 存储所有商品数据的列表 product_data = [] for product in products: # 商品标题 title = product.find("h3") titleText = title.text.strip() if title else '' # 厂商名称 manufacturer = product.find("div", "GC5 ProductManufacturer") manuText = manufacturer.text.strip() if manufacturer else '' # 图片链接 img = product.find("div", "ProductImage") imglinks = img.find("a") if img else None imglinkhref = imglinks.get('href') if imglinks else '' imgurl = 'https://www.mcavoyguns.co.uk/contents' + imglinkhref.replace('..', '') # 描述 description = product.find("div", "GC12 ProductDescription") descText = description.text.strip() if description else '' # 详细描述 more = product.find("div", "GC12 ProductDetailedDescription") moreText = more.text.strip() if more else '' # 价格:在当前product节点内查找价格元素 price_div = product.find("div", "GC20 ProductPrice") if price_div: # 根据页面结构,取第一个有效的价格span(你之前步长为2,可根据实际调整索引) price_spans = price_div.find_all("span") price = price_spans[0].text.strip() if len(price_spans) > 0 else '' else: price = '' # 打印当前商品的所有信息 print(f"价格: {price}") print(f"标题: {titleText}") print(f"厂商: {manuText}") print(f"描述: {descText}") print(f"详细描述: {moreText}") print(f"图片链接: {imgurl}") print("\n") # 将数据存入列表,方便后续导出 product_data.append({ 'title': titleText, 'manufacturer': manuText, 'price': price, 'description': descText, 'detailed_description': moreText, 'image_url': imgurl }) # 导出为JSON文件 with open('beretta_shotguns.json', 'w', encoding='utf-8') as f: json.dump(product_data, f, ensure_ascii=False, indent=4) # 导出为CSV文件 with open('beretta_shotguns.csv', 'w', newline='', encoding='utf-8') as f: writer = csv.DictWriter(f, fieldnames=product_data[0].keys()) writer.writeheader() writer.writerows(product_data)
方案2:纯Selenium实现(动态加载内容)
如果页面价格是JS动态渲染的,requests无法获取到,就统一用Selenium来遍历每个商品节点:
from selenium import webdriver from selenium.webdriver.common.by import By import csv import json import os os.environ["PYTHONIOENCODING"] = "utf-8" browser = webdriver.Chrome(executable_path='C:/Users/andrew.glass/chromedriver.exe') browser.get("https://www.mcavoyguns.co.uk/contents/en-uk/d130_Beretta_Over___Under_Competeition_shotguns.html") products = browser.find_elements(By.CSS_SELECTOR, "div.GC62.Product") product_data = [] for product in products: # 标题 try: title = product.find_element(By.TAG_NAME, "h3") titleText = title.text.strip() except: titleText = '' # 厂商 try: manufacturer = product.find_element(By.CSS_SELECTOR, "div.GC5.ProductManufacturer") manuText = manufacturer.text.strip() except: manuText = '' # 图片链接 try: img_a = product.find_element(By.CSS_SELECTOR, "div.ProductImage a") imglinkhref = img_a.get_attribute('href') imgurl = imglinkhref.replace('..', '') except: imgurl = '' # 描述 try: description = product.find_element(By.CSS_SELECTOR, "div.GC12.ProductDescription") descText = description.text.strip() except: descText = '' # 详细描述 try: more = product.find_element(By.CSS_SELECTOR, "div.GC12.ProductDetailedDescription") moreText = more.text.strip() except: moreText = '' # 价格:在当前product节点内查找 try: price_div = product.find_element(By.CSS_SELECTOR, "div.GC20.ProductPrice") price_spans = price_div.find_elements(By.TAG_NAME, "span") price = price_spans[0].text.strip() if len(price_spans) > 0 else '' except: price = '' # 打印信息 print(f"价格: {price}") print(f"标题: {titleText}") print(f"厂商: {manuText}") print(f"描述: {descText}") print(f"详细描述: {moreText}") print(f"图片链接: {imgurl}") print("\n") product_data.append({ 'title': titleText, 'manufacturer': manuText, 'price': price, 'description': descText, 'detailed_description': moreText, 'image_url': imgurl }) # 导出JSON和CSV with open('beretta_shotguns_selenium.json', 'w', encoding='utf-8') as f: json.dump(product_data, f, ensure_ascii=False, indent=4) with open('beretta_shotguns_selenium.csv', 'w', newline='', encoding='utf-8') as f: writer = csv.DictWriter(f, fieldnames=product_data[0].keys()) writer.writeheader() writer.writerows(product_data) browser.quit()
关键修改点说明
- 绑定价格到当前商品:无论是用BeautifulSoup还是Selenium,都在当前遍历的
product节点内部查找价格元素,而不是全局查找。 - 统一页面获取方式:避免混合使用
requests和Selenium,防止数据来源不一致。 - 添加数据存储逻辑:将每个商品的信息存入字典,再添加到列表,最后可以轻松导出为JSON或CSV。
注意事项
- 如果你用的是较新版本的Selenium,
find_elements_by_css_selector已经被弃用,建议用find_elements(By.CSS_SELECTOR, ...)的方式(如方案2所示)。 - 页面结构可能会变化,需要根据实际页面的HTML结构调整选择器,比如价格span的索引是否正确。
内容的提问来源于stack exchange,提问作者Andrew Glass
相关产品推荐
相关产品推荐

