如何大规模抓取 eBay 数据

如何大规模抓取 eBay 数据:Massive 的完整代理解决方案

Jason Grad
创始人
February 18, 2025

準備好測試高級代理的效能了嗎?

如何大规模抓取 eBay 数据

如何大规模抓取 eBay 数据:Massive 的完整代理解决方案

Jason Grad
创始人
February 18, 2025

eBay是全球最大的电子商务市场之一,拥有数十亿的eBay列表,每天吸引数百万访客。对于企业而言,eBay 产品数据提供了大量有价值的数据,这些数据对于商业智能、市场研究和竞争分析可能非常宝贵。但是,由于该平台具有先进的防抓取机制,从eBay大规模提取数据的网络抓取过程构成了重大的技术挑战。

本分步指南解释了如何使用Massive的代理网络构建eBay网络抓取工具,以有效地提取eBay列表数据,同时最大限度地降低被封锁的风险。

事不宜迟,让我们开始吧!

为什么要抓取 eBay 数据?

来自eBay网站的原始数据为企业提供了宝贵的见解,从而推动了明智的决策和竞争优势。以下是来自eBay的公开数据如何改变业务战略:

  1. 市场研究: 通过实时跟踪竞争对手的定价、促销和客户偏好,您可以识别市场缺口并调整策略以超越竞争对手。
  2. 智能定价: 在eBay上监控价格波动使您可以调整价格以保持竞争力,同时保持可观的利润率。这在价格频繁变动的快速市场或季节性高峰期特别有用。
  3. 产品决策: 在投资新库存之前,利用 eBay 的销售和反馈数据来验证您的产品选择。通过分析畅销产品并了解客户反馈,您可以完善产品供应并安排发布时间,以最大限度地发挥影响力。
  4. 库存管理: eBay 数据显示了明确的需求模式,使您能够保持最佳库存水平。这可以帮助您优化库存水平,避免库存积压并防止缺货。

避免在抓取 eBay 时被屏蔽

构建 eBay 抓取工具并不像看起来那么容易。由于基于IP的速率限制、验证码和严格的反抓取措施,大规模抓取eBay带来了重大挑战。当你超过eBay的请求限制时,你的IP会被封锁或面临验证码。

为什么你需要代理来进行eBay抓取?

在构建用于大规模抓取 eBay 数据的 eBay 抓取工具时,代理不仅有用,而且是必不可少的。使用代理可以将请求分配到多个 IP 地址,从而帮助您:

  • 避免被封锁或节流
  • 保持稳定的刮擦速度
  • 防止 IP 黑名单(这可能是一个非常棘手的问题)
  • 可靠地扩展您的数据收集

为什么选择大规模代理来抓取 eBay?

正如我们在上面已经讨论的那样,从eBay抓取数据并不简单。你必须考虑使用某种代理,而且 住宅代理 是最受欢迎的。我们的 住宅代理的使用 来自真实台式机和移动设备的IP,使其在绕过eBay的反抓取措施方面非常有效。以下是我们提供的服务:

  1. 成功率高:我们的住宅 IP 可显著降低封锁风险,从而实现可靠的大规模数据收集。
  2. 全球接入:使用特定地区的代理从全球任何 eBay 市场无缝收集数据。
  3. 精确的本地数据:定位特定的城市或国家,以获得准确的市场见解和定价数据。
  4. 性能保障:通过快速响应时间和全天候正常运行时间监控,享受 99% 的成功率。
  5. 灵活使用:从各种带宽选项中进行选择,以满足您的抓取需求,无论是小型还是企业级。

💡 专业提示: 在抓取不同的eBay市场时,请务必使用目标国家/地区的代理——这样可以确保您获得实际的本地定价和可用性数据。Massive Proxies在所有主要的eBay市场上提供特定位置的IP,以获得一致的结果。

大规模代理入门

如果你是 Massive 的新手, 注册一个账号。根据您的需求选择套餐。

注意: 我们提供 2 GB 免费试用 对于公司来说。首先, 填写这张表格。如果你需要更多的带宽, 联系我们的销售团队,我们将为您提供帮助。

注册后,前往 大型仪表板 检索您的代理凭证(用户名和密码)。

海量代理凭证

配置步骤:

请访问 快速入门 用于自定义代理设置的部分:

  • 选择您的首选协议(HTTP、HTTPS 或 SOCKS5)
  • 在两者之间选择 旋转或粘性代理
  • 设置地理定位偏好(国家、州、城市或邮政编码)

配置完成后,您将获得适用于特定用例的即用型 cURL 命令。

庞大的快速入门仪表板

有关基于位置的定位和粘性会话等高级功能,请参阅 海量文档。这些文档提供了充分利用大规模住宅代理的分步说明。

通过这种设置,你可以使用Massive Proxies从包括美国、英国、德国和澳大利亚在内的主要市场抓取eBay数据。

您可以从eBay提取哪些产品数据?

抓取 eBay 可以为您提供丰富的产品信息。以下是可用数据的全面明细:

  • 产品网址: 指向 eBay 产品页面的链接
  • 标题: 物品的名称
  • 字幕: 其他描述性文本
  • 当前价格: 当前的销售价格
  • 原价为: 先前的价格(如果有)
  • 折扣: 折扣的百分比或金额
  • 可用性: 可用数量和库存状态
  • 已售数量: 已售商品数量
  • 配送详情: 成本和预计交货时间
  • 地点: 发货来源
  • 退货: 退货政策详情
  • 状况: 商品是新品、二手还是翻新商品
  • 品牌: 制造商或品牌名称
  • 类型: 类别或商品类型
  • 卖家信息:
    • 卖家/商店名称
    • 客户反馈百分比
    • 卖家的总销售额

所需的用户输入

要开始抓取 eBay,你需要指定两个关键参数:

  1. 目标国家: 您可以从 10 个地区 eBay 域名中提取数据:
"US": "https://www.ebay.com",
"GB": "https://www.ebay.co.uk",
"DE": "https://www.ebay.de",
"ES": "https://www.ebay.es",
"FR": "https://www.ebay.fr",
"IT": "https://www.ebay.it",
"CA": "https://www.ebay.ca",
"MX": "https://www.mx.ebay.com",
"NL": "https://www.ebay.nl",
"AU": "https://www.ebay.com.au"
  1. 搜索词: 输入要刮掉的内容(例如,“躺椅”、“无人机相机”)。您可以使用逗号输入多个术语。
  1. 物品限制: (可选)指定要刮掉的项目数量。跳过此步骤即可收集所有页面上的所有可用数据。

提取的数据将保存在结构化的 JSON 文件中。

使用海量代理构建 eBay 数据抓取工具

本指南逐步探讨了如何大规模收购eBay。当我们专注于刮刮时 eBay.com (美国网站),同样的原则适用于其他国家/地区的eBay网站,但对选择者进行了细微的调整。

eBay 产品搜索页面

步骤 #1:项目设置

首先,确保你的系统上安装了 Python 3。如果不是, 下载并安装它

现在,为你的项目创建一个目录:

mkdir ebay_scraper

在首选 IDE(如 VS Code)中打开项目文件夹,然后创建一个名为 usa_ 的文件ebay.py。该文件将包含我们抓取 eBay 数据的抓取逻辑。

你还需要创建一个 .env 文件来存储你的大规模代理证书:

PROXY_USERNAME=your_username
PROXY_PASSWORD=your_password

现在,你的项目结构应该是这样的:

ebay_scraper/
├── .env
└── usa_ebay.py

步骤 #2:安装依赖关系

为了高效地抓取 eBay 数据,你需要使用几个密钥库:

现在,你可以使用 pip 安装这些依赖项,如下所示:

pip install curl-cffi beautifulsoup4 python-dotenv aiofiles

步骤 #3:配置大规模代理

此步骤设置代理以启用地理定位,确保请求通过特定国家/地区转发,以准确提取 eBay 数据:

def setup_proxy(self):
    """Configure proxy settings for geotargeted requests"""
    self.proxy_host = "network.joinmassive.com:65534"
    self.username = os.getenv("PROXY_USERNAME")
    self.password = os.getenv("PROXY_PASSWORD")
    self.proxy_auth = f"{self.username}-country-{self.domain}:{self.password}"

步骤 #4:请求配置

使用配置 HTTP 请求 curl_cfi 图书馆。该设置涉及两种方法:

  1. _get_proxy_config: 格式化代理身份验证凭据和主机详细信息
  2. _make_request: 使用速率限制和浏览器仿真等功能处理 HTTP 请求的执行
def _get_proxy_config(self) -> Dict[str, str]:
    """Generate proxy configuration dictionary"""
    return {"https": f"http://{self.proxy_auth}@{self.proxy_host}"}


async def _make_request(self, session: AsyncSession, url: str, page_type: str):
    """Make HTTP request with proxy and browser emulation"""
    async with self.semaphore:
        response = await session.get(
            url,
            proxies=self._get_proxy_config(),
            impersonate="chrome124",
            timeout=self.page_timeout,
        )

步骤 #5:处理搜索页面

这个方法 _流程搜索页面 管理单个搜索结果页面的处理。它使用异步会话、页码和搜索词作为输入。以下是它的工作原理:

该函数通过构建查询参数来构造搜索 URL,这些参数包括:

  • 搜索关键字 (_nkw)
  • 页码 (_pgn)
  • 每页项目设置 (_ipg) 已优化至 240 个项目

然后,它使用先前配置的请求方法发出异步请求。如果成功检索到内容,则使用以下方法对其进行解析 漂亮的汤lxml 解析器。然后,它从解析的 HTML 中提取产品 URL 并批量处理提取的产品 URL。

async def _process_search_page(
    self, session: AsyncSession, page_num: int, search_term: str
):
    """Process a single search results page"""
    try:
        params = {
            "_nkw": search_term,
            "_pgn": page_num,
            "_ipg": 240,  # Maximum items per page
        }
        url = self.base_url + urlencode(params)

        status_code, html_content = await self._make_request(session, url, "search")
        if html_content:
            soup = BeautifulSoup(html_content, "lxml")
            urls = self._extract_product_urls(soup)

            logger.info(f"Found {len(urls)} products on page {page_num}")
            return await self._process_product_batch(session, urls)
    except Exception as e:
        logger.error(f"Error processing page {page_num}: {str(e)}")
        return False, False

步骤 #6:提取产品 URL

这种方法可以处理从搜索结果页面提取产品网址的关键任务。以下是产品网址提取的工作原理:

这个 _提取产品_网址 方法接受包含已解析的 HTML 内容的 BeautifulSoup 对象,并返回有效产品网址的列表。它实现了一种有针对性的网址提取方法:

  • 使用 CSS 选择器 a.s-item__link 查找所有产品链接元素
  • 遍历每个链接元素以提取 href 属性
  • 通过检查是否存在 URL 来验证 URL itm/ 在 URL 路径中
  • 生成仅包含有效产品 URL 的筛选列表
def _extract_product_urls(self, soup: BeautifulSoup) -> List[str]:
    """Extract product URLs from search results page"""
    urls = []
    for link in soup.select("a.s-item__link"):
        url = link.get("href", "")
        if url and "itm/" in url:
            urls.append(url)
    return urls

步骤 #7:抓取产品详情

_extract_product_details 方法系统地从 eBay 产品页面中提取产品信息。它处理 BeautifulSoup 对象并返回一个包含结构化数据的 ProductDetails 对象。

def _extract_product_details(self, soup: BeautifulSoup, url: str) -> ProductDetails:
    """Extract all product details from page"""
    details = ProductDetails(url=url)

    try:
        details.store_info = DataExtractor.extract_store_info(soup)

        # Title section
        if title_div := soup.select_one("div.x-item-title"):
            if title := title_div.select_one("h1.x-item-title__mainTitle span"):
                details.title = title.text.strip()
            if subtitle := title_div.select_one("div.x-item-title__subTitle span"):
                details.subtitle = subtitle.text.strip()

        # Price section
        if price_section := soup.select_one("div.x-price-section"):
            if current_price := price_section.select_one("div.x-price-primary span"):
                details.current_price = current_price.text.strip()
            if was_price := price_section.select_one(
                "span.ux-textspans--STRIKETHROUGH"
            ):
                details.was_price = was_price.text.strip()

            # Discount calculation
            discount = None
            if emphasis_discount := price_section.select_one(
                "span.ux-textspans--EMPHASIS"
            ):
                discount = emphasis_discount.text.strip()
            elif secondary_discount := price_section.select_one(
                "span.ux-textspans--SECONDARY"
            ):
                discount = secondary_discount.text.strip()
            if discount and (percentage_match := re.search(r"(\d+)%", discount)):
                details.discount = percentage_match.group(1) + "%"

        # Quantity section
        if quantity_div := soup.select_one("div.x-quantity__availability"):
            spans = quantity_div.select("span.ux-textspans")
            if spans:
                details.availability = spans[0].text.strip()
                if len(spans) > 1:
                    details.sold_count = spans[1].text.strip()

        # Shipping section
        if shipping_div := soup.select_one("div.d-shipping-minview"):
            if shipping_section := shipping_div.select_one(
                "div.ux-labels-values__values-content"
            ):
                details.shipping, details.location = (
                    DataExtractor.extract_shipping_info(shipping_section)
                )

        # Returns section
        if returns_div := soup.select_one("div.x-returns-minview"):
            if returns_section := returns_div.select_one(
                "div.ux-labels-values__values-content"
            ):
                details.returns = DataExtractor.extract_returns_info(returns_section)

        # Additional details
        if condition_span := soup.select_one(
            "div.x-item-condition-max-view .ux-section__item > span.ux-textspans"
        ):
            details.condition = condition_span.text.strip().split(".")[0] + "."
        if (brand_dl := soup.select_one("dl.ux-labels-values--brand")) and (
            brand_value := brand_dl.select_one("dd .ux-textspans")
        ):
            details.brand = brand_value.text.strip()
        if (type_dl := soup.select_one("dl.ux-labels-values--type")) and (
            type_value := type_dl.select_one("dd .ux-textspans")
        ):
            details.type = type_value.text.strip()
    except Exception as e:
        logger.error(f"Error extracting details from {url}: {str(e)}")
    return details

步骤 #8:处理分页

这个 _有_下一页 方法使用两种不同的方法来检查分页:

  • 首先,它通过搜索锚标签来寻找下一页链接 type= “下一步” 属性。如果此链接存在且有效 href 属性,它确认下一页的存在。
  • 作为备用机制,它还会检查下一个按钮元素。这是在找一个带有 type= “下一步” 并通过检查来验证它是否未被禁用 aria已禁用 属性。如果该按钮存在但未被禁用,则表示有更多页面可用。
def _has_next_page(self, soup: BeautifulSoup) -> bool:
    """Determine if there is a next page of results"""
    next_link = soup.select_one('a[type="next"]')
    if next_link and next_link.get("href"):
        return True
    next_button = soup.select_one('button[type="next"]')
    return not (next_button and next_button.get("aria-disabled") == "true")

步骤 #9:数据存储

最后,将提取的数据保存到 JSON 文件中:

class FileHandler:
    """Handle file operations with error handling and backups"""

    @staticmethod
    async def save_to_file(filename: str, data: Dict):
        """Save data with automatic backup creation"""
        temp_file = f"{filename}.temp"
        backup_file = f"{filename}.backup"

        try:
            # Create directory structure
            os.makedirs(os.path.dirname(filename), exist_ok=True)

            # Save to temporary file
            async with aiofiles.open(temp_file, "w", encoding="utf-8") as f:
                await f.write(json.dumps(data, indent=2, ensure_ascii=False))

            # Create backup of existing file
            if os.path.exists(filename):
                os.replace(filename, backup_file)

            # Replace with new file
            os.replace(temp_file, filename)

            logger.info(f"Data successfully saved to {filename}")
        except Exception as e:
            logger.error(f"Error saving data: {str(e)}")
            raise

步骤 #10:运行刮板

在10个市场域名上抓取eBay的完整实现方法可在以下网址获取 GitHub。抓取器提取产品数据并生成结构化的 JSON 文件,每个条目包含:

{
    "url": "https://www.ebay.com/itm/294701001393",
    "title": "Manual Recliner Armchair PU Sofa Chair w/ Adjustable Leg Rest & 135° Reclining",
    "subtitle": "Comfortable & Easy to Clean & 360° Swivel & Steel Frame",
    "current_price": "US $228.99",
    "was_price": "US $651.99",
    "discount": "65%",
    "availability": "More than 10 available",
    "sold_count": "93 sold",
    "shipping": "Free shipping - Arrives by Christmas",
    "location": "Wilsonville, Oregon, United States",
    "returns": "30 days returns Buyer pays for return shipping",
    "condition": "A brand-new, unused, unopened, undamaged item in its original packaging (where packaging is applicable).",
    "brand": "Homcom",
    "type": "Recliner Armchair",
    "store_info": {
        "name": "Aosom-Direct",
        "feedback": "97.5% positive feedback",
        "sales": "482K items sold",
    },
}

结论

本指南展示了如何构建可在不同eBay市场上运行的eBay抓取工具。通过使用住宅代理,您可以收集准确的产品数据,同时最大限度地降低封锁风险。我们所介绍的方法使可靠地从eBay的各个区域站点收集数据成为可能。

如果您需要有关代理配置或最佳实践的更多详细信息,可以在中找到所有内容 文档

准备好开始了吗? 立即注册大规模代理 🚀

作者简介
Jason Grad
创始人

我是Massive的联合创始人兼首席执行官。除了在创业公司工作外,我还是一名音乐家、运动员、导师、活动主持人和志愿者。

经常问的问题

+

+

+

+

+

+

+

+

+

+

Ready to test premium proxy performance?