加拿大药房药品爬取问题:Strength/Quantity字段重复及格式需求
解决方案:解决药品规格/数量爬取后的DataFrame重复与宽表转换问题
问题根源
你遇到的药品名称重复问题,本质是把每条规格-数量的价格条目都和基础药品信息做了拼接,导致DataFrame中每个变体对应一行重复的药品名。要实现目标宽表(以2mg、5mg、30片等为列),需要先收集所有变体数据,再通过透视转换为宽格式,最后合并基础信息。
具体实现步骤与代码
假设你已经通过Selenium获取了目标页面的驱动实例或BeautifulSoup解析后的页面对象,以下是修正后的完整逻辑:
1. 爬取药品基础信息
先一次性获取药品名称、通用名等基础信息,避免重复拼接:
from bs4 import BeautifulSoup import pandas as pd from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By # --- Selenium 页面加载(确保变体元素加载完成)--- # 假设driver是你的Selenium驱动实例 wait = WebDriverWait(driver, 10) wait.until(EC.presence_of_all_elements_located((By.CLASS_NAME, "product-variant"))) page_source = driver.page_source soup = BeautifulSoup(page_source, "html.parser") # --- 提取基础信息 --- drug_name = soup.find("h1", class_="product-name").text.strip() generic_name = soup.find("div", class_="generic-name").text.strip() base_info = {"药品名称": drug_name, "通用名": generic_name}
2. 收集所有规格-数量-价格组合
批量提取页面上所有变体的规格、数量和价格,存储为列表字典:
variants = [] variant_elements = soup.find_all("div", class_="product-variant") for elem in variant_elements: strength = elem.find("span", class_="strength").text.strip() quantity = elem.find("span", class_="quantity").text.strip() # 处理价格,去掉$符号并转换为数值 price_text = elem.find("span", class_="price").text.strip().replace("$", "") price = float(price_text) if price_text else None variants.append({ "规格": strength, "数量": quantity, "价格": price })
3. 转换为目标宽表
根据你的需求,有两种宽表形式可选:
形式一:以数量为行,规格为列
适合查看同一规格下不同数量的价格对比:
# 转换为DataFrame并透视 variants_df = pd.DataFrame(variants) pivot_df = variants_df.pivot(index="数量", columns="规格", values="价格").reset_index() # 合并基础信息,确保药品信息不重复 pivot_df = pivot_df.assign(**base_info) # 调整列顺序,把药品信息放在最前面 cols = ["药品名称", "通用名", "数量"] + [col for col in pivot_df.columns if col not in ["药品名称", "通用名", "数量"]] final_df = pivot_df[cols]
形式二:以药品为单行,规格+数量为列
适合把所有价格选项整合为一行,避免药品名重复:
variants_df = pd.DataFrame(variants) # 合并规格和数量作为列名 variants_df["规格-数量"] = variants_df["规格"] + "-" + variants_df["数量"] # 透视为单行宽表 wide_df = variants_df.pivot_table(index=[], columns="规格-数量", values="价格").reset_index(drop=True) # 合并基础信息 wide_df = wide_df.assign(**base_info) # 调整列顺序 cols = ["药品名称", "通用名"] + list(wide_df.columns[:-2]) final_df = wide_df[cols]
关键注意事项
- Selenium等待机制:必须确保所有变体元素加载完成后再提取,否则会漏爬数据
- 数据清洗:价格字段要处理特殊符号(如$),转换为数值类型方便后续分析
- 透视逻辑:根据实际需求选择透视的行和列,避免出现重复的药品名称条目
内容的提问来源于stack exchange,提问作者Lalit Joshi
相关产品推荐
相关产品推荐

