Bootstrap

如何使用 Java 来抓取电子商务产品数据?

在本教程中,我们将了解如何使用Java从任何电子商务网站中提取产品数据。 产品数据提取有很多不同的用例,例如:

  • 电子商务价格监控
  • 价格比较器
  • 可用性监控
  • 提取评论
  • 市场调查
  • 违反MAP

我们将从以下产品页面中提取以下不同字段:价格、产品名称、图像URL、SKU和货币:

Https://www.asos.com/the-north-face/the-north-face-vault-backpack-28-litres-in-black/prd/10253008

 

您需要什么

我们将使用HtmlUnit执行HTTP请求并解析DOM,并将此依赖项添加到pom.xml中。

<dependency>
   <groupId>net.sourceforge.htmlunit</groupId>
   <artifactId>htmlunit</artifactId>
   <version>2.19</version>
</dependency>

我们还将使用Jackson库:

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.9.8</version>
</dependency>

Schema.org

为了提取我们感兴趣的字段,我们将解析Html标记中的https://schema.org元数据。

模式是可以添加到任何网页的语义词汇表。实现模式有很多好处。大多数搜索引擎都使用它来了解页面的含义(产品、文章、评论等等

根据schema.org的数据,全球大约有1000万个网站在使用它。太好了!
模式有不同的类型,今天我们将研究产品类型

 

这真的很方便,因为一旦您编写了一个提取特定模式数据的抓取器,它就会在使用相同模式的任何其他网站上运行。 不再需要编写特定的XPath / CSS选择器!

根据我在PricingBot(我以前的公司)中的经验,大约40%的电子商务网站在其DOM中使用schema.org元数据。

有三种主要的架构标记:

JSON-LD

<script type="application/ld+json">
{
    "@context": "http://schema.org",
    "@type": "ItemList",
    "url": "http://multivarki.ru?filters%5Bprice%5D%5BLTE%5D=39600",
    "numberOfItems": "315",
    "itemListElement": [
        {
            "@type": "Product",
            "image": "http://img01.multivarki.ru.ru/c9/f1/a5fe6642-18d0-47ad-b038-6fca20f1c923.jpeg",
            "url": "http://multivarki.ru/brand_502/",
            "name": "Brand 502",
            "offers": {
                "@type": "Offer",
                "price": "4399 p."
            }
        },
        {
            "@type": "Product",
            "name": "..."
        }
    ]
}
</script>

RDF-A


<div vocab="http://schema.org/" typeof="ItemList">
    <link property="url" href="http://multivarki.ru?filters%5Bprice%5D%5BLTE%5D=39600"><span property="numberOfItems">315</span>
    <div property="itemListElement" typeof="Product">
        <img property="image" alt="Photo of product" src="http://img01.multivarki.ru.ru/c9/f1/a5fe6642-18d0-47ad-b038-6fca20f1c923.jpeg"> <a property="url" href="http://multivarki.ru/brand_502/"><span property="name">BRAND 502</span></a>
        <div property="offers" typeof="http://schema.org/Offer">
            <meta property="schema:priceCurrency" content="RUB">руб
            <meta property="schema:price" content="4399.00">4 399,00
            <link property="schema:itemCondition" href="http://schema.org/NewCondition">
        </div>...
        <div property="itemListElement" typeof="Product">
          ...
        </div>
    </div>
</div>

在我们的例子中使用的是微数据:


<div class="schema-org">


<div itemscope="" itemtype="https://schema.org/Product">
    <img itemprop="image" src="https://images.asos-media.com/products/the-north-face-vault-backpack-28-litres-in-black/10253008-1-black" alt="Image 1 of The North Face Vault Backpack 28 Litres in Black">
    <link itemprop="itemCondition" href="https://schema.org/NewCondition">
    <span itemprop="productID">10253008</span>
    <span itemprop="sku">10253008</span>
    <span itemprop="brand" itemscope="" itemtype="https://schema.org/Brand">
        <span itemprop="name">The North Face</span>
    </span>
    <span itemprop="name">The North Face Vault Backpack 28 Litres in Black</span>
    <span itemprop="description">Shop The North Face Vault Backpack 28 Litres in Black at ASOS. Discover fashion online.</span>
    <span itemprop="offers" itemscope="" itemtype="https://schema.org/Offer">
        <link itemprop="availability" href="https://schema.org/InStock">
        <meta itemprop="priceCurrency" content="GBP">
        <span itemprop="price">60</span>
        <span itemprop="eligibleRegion">GB</span>
        <span itemprop="seller" itemscope="" itemtype="https://schema.org/Organization">
            <span itemprop="name">ASOS</span>
        </span>
    </span>  
</div>

  </div>

请注意,您可以在一个页面中包含多个优惠。

提取数据

首先是创建产品的基本POJO:


public class Product {

    private BigDecimal price;
    private String name;
    private String sku;
    private URL imageUrl;
    private String currency;
        // ...getters & setters

然后,我们需要转到目标URL并创建一个基本的微数据解析器来提取我们感兴趣的字段。为此,我正在使用HtmlUnit,这是一个纯Java无头浏览器。 我本可以使用许多不同的库,例如Jsoup或Selenium + Headless Chrome。

但是在大多数情况下,HtmlUnit是一个不错的解决方案,因为它比Selenium + Headless Chrome轻,但比原始HTTP客户端+ JSoup(仅处理HTML解析)提供更多功能。

对于依赖Java的网站,依靠React / Vue.js之类的前端框架,Headless Chrome是必经之路!



WebClient client = new WebClient();
client.getOptions().setCssEnabled(false);
client.getOptions().setJavaScriptEnabled(false);
String productUrl = "https://www.asos.com/the-north-face/the-north-face-vault-backpack-28-litres-in-black/prd/10253008";

HtmlPage page = client.getPage(productUrl);
HtmlElement productNode = ((HtmlElement) page
                .getFirstByXPath("//*[@itemtype='https://schema.org/Product']"));
URL imageUrl = new URL((((HtmlElement) productNode.getFirstByXPath("./img")))
                .getAttribute("src"));
HtmlElement offers = ((HtmlElement) productNode.getFirstByXPath("./span[@itemprop='offers']"));

BigDecimal price = new BigDecimal(((HtmlElement) offers.getFirstByXPath("./span[@itemprop='price']")).asText());
String productName = (((HtmlElement) productNode.getFirstByXPath("./span[@itemprop='name']")).asText());
String currency = (((HtmlElement) offers.getFirstByXPath("./*[@itemprop='priceCurrency']")).getAttribute("content"));
String productSKU = (((HtmlElement) productNode.getFirstByXPath("./span[@itemprop='sku']")).asText());

在第一行中,我创建了HtmlUnit HTTP客户端并禁用了Javascript,因为我们不需要它来获取Schema标记。

然后,只是基本的XPath表达式即可选择我们想要的有趣的DOM节点。

该解析器远非完美,它不能提取所有内容,也不能处理多个要约。 但是,这将为您提供有关如何提取模式数据的想法。

然后,我们可以创建Product对象,并将其打印为JSON字符串:


Product product = new Product(price, productName, productSKU, imageUrl, currency);
ObjectMapper mapper = new ObjectMapper();
String jsonString = mapper.writeValueAsString(product) ;
System.out.println(jsonString);

避免阻塞

现在我们已经能够提取出我们想要的产品数据,我们必须小心不要被阻塞。

由于各种原因,有时会在网站上实施反机器人机制。 保护网站免受僵尸程序侵害的最明显的原因是,防止大量的自动流量影响网站的性能(并且您必须小心并发请求,因为它会增加延迟...)。 另一个原因是阻止垃圾邮件等僵尸程序的不良行为。

如今有各种各样的保护机制。有时你的机器人会被阻塞,如果它每秒钟/每小时/每天做太多的请求。有时每个IP地址的请求数是有速率限制的。最困难的保护是用户行为分析。例如,如果同一IP同时发出请求,则该网站可以分析请求之间的时间间隔。

隐藏我们的刮板最简单的解决方案是使用代理。 与随机用户代理程序结合使用时,使用代理服务器是一种强大的方法,可以隐藏我们的抓取工具,并抓取受速率限制的网页。 当然,最好不要一开始就阻止它,但有时网站每天/小时只允许一定数量的请求。

在这种情况下,您应该使用代理。 免费代理列表很多,我不建议您使用这些代理列表,因为它们通常速度慢,不可靠,而且提供这些列表的网站对于这些代理的位置并不总是透明的。 有时,公共代理人名单是由一家合法公司运营的,提供高级代理,有时则不...

我建议您使用付费代理服务,或者您可以自己构建。

为HtmlUnit设置代理很容易:


ProxyConfig proxyConfig = new ProxyConfig("host", myPort);
client.getOptions().setProxyConfig(proxyConfig);

进一步来说

如您所见,由于有了Schema.org数据,所以现在提取产品数据比十年前要容易得多。

但是仍然存在一些挑战,比如处理没有实现模式的网站、处理IP阻塞和速率限制、呈现Javascript……

这就是为什么我们一直与我的合作伙伴Pierre合作开发Web Scraping API的原因

ScrapingBee是一种API,可从任何网站提取任何HTML,而无需处理代理、验证码和无头浏览器。 单个API调用,仅包含您要从中提取数据的产品URL。

我希望你喜欢这篇文章,因为你总是可以在这个Github知识库中找到完整的代码:https://github.com/ksahin/introweb

原文链接: https://dev.to//scrapingbee/scraping-e-commerce-product-data-2aif

;