logo

Web 抓取亚马逊:Python 分步教程

2024-06-30 11:58
本文详细介绍了如何抓取亚马逊,并附带了一个详实的例子。

网络抓取亚马逊对电子商务企业至关重要,因为了解有关竞争对手和最新趋势的信息至关重要。

什么是亚马逊抓取?

网络抓取是从网站收集数据,亚马逊是最大的在线购物平台。那么,如何使用网络抓取来比竞争对手更具优势呢?

这个实用教程将展示如何使用 Python 从亚马逊抓取产品信息!

亚马逊允许网页抓取吗?

**绝对允许!但有一点需要注意:亚马逊使用速率限制,如果您使网站负担过重,可以阻止您的 IP 地址。**他们还会检查 HTTP 标头,如果您的活动看起来可疑,他们会阻止您。

如果您尝试同时抓取多个页面,则可能会在没有代理轮换的情况下被阻止。此外,亚马逊的网页具有不同的结构。甚至不同的产品页面也具有不同的 HTML 结构。构建强大的网络爬虫应用程序是很困难的。

然而,抓取产品价格、评论和列表是合法的。

为什么从亚马逊抓取网页?

**特别是在电子商务中,拥有尽可能多的信息是必不可少的。**如果您可以自动化提取过程,则可以将更多精力集中在竞争对手和业务上。

以下是一些好处:

监控产品

您可以查看您所在类别中最畅销的产品。这将使您能够识别市场的当前趋势。因此**,您可以更好地决定您的产品**。您还可以发现正在失去顶级销售位置的产品。

监控竞争对手

赢得比赛的唯一方法是监控竞争对手的举动。例如,抓取亚马逊产品价格将有助于现货价格趋势。这将使您确定更好的定价策略。因此,您可以跟踪更改并进行竞争对手的产品分析。

如何从亚马逊抓取数据?

用 BeautifulSoup 抓取网页

本文不需要高级 Python 技能。

对于 Python 中的网络抓取,我们有几个注意事项:

可以仅生成基于请求的脚本。我们还可以使用浏览器自动化工具(例如 Selenium)来抓取亚马逊。但是亚马逊很容易检测到无头浏览器。尤其是当您不自定义它们时。

使用像 Selenium 这样的框架也是低效的,因为如果你扩展你的应用程序,它们很容易使系统过载。

因此,我们将使用 Python 中的 and 模块来抓取亚马逊产品的数据。requests``BeautifulSoup

让我们从安装必要的 Python 包开始!我们将使用 和 模块。requests``BeautifulSoup

您可以使用以下方式安装它们:pip

终端

pip install requests beautifulsoup4

避免在网页抓取时被阻止

正如我们之前提到的,**亚马逊确实允许网络抓取。但是,如果执行许多请求,它会阻止网络爬虫。**他们检查 HTTP 标头并应用速率限制来阻止恶意机器人。

从 HTTP 标头中检测客户端是否是机器人相当容易,因此如果您不自定义固定的浏览器设置,则使用 Selenium 等浏览器自动化工具将不起作用。

我们将使用真正的浏览器,由于我们不会发送太频繁的请求,因此我们不会受到速率限制。您应该使用代理服务器来大规模抓取数据。user-agent,

从亚马逊抓取产品数据

在本文中,我们将从这个午餐盒产品中抓取数据:

[Amazon Product

我们将提取以下内容:

  • 产品标题。
  • 额定值。
  • 价格。
  • 折扣(如果有的话)。
  • 全价(如果有折扣,将是折扣价)。
  • 库存状态(缺货与否)。
  • 产品描述。
  • 相关项目。

如前所述,亚马逊会检查固定设置,因此使用标准设置发送 HTTP 请求将不起作用。您可以通过使用 Python 发送一个简单的请求来检查这一点:

scraper.py

import requests 
 
response = requests.get("https://www.amazon.com/Sabrent-4-Port-Individual-Switches-HB-UM43/dp/B00JX1ZS5O") 
print(response.status_code) # prints 503

响应的状态代码为“503 服务不可用”。响应的 HTML 中也有以下消息:

输出

To discuss automated access to Amazon data please contact api-services-support@amazon.com. 
For information about migrating to our APIs refer to our Marketplace APIs at https://developer.amazonservices.com/ref=rm_5_sv, or our Product Advertising API at https://affiliate-program.amazon.com/gp/advertising/api/detail/main.html/ref=rm_5_ac for advertising use cases.

那么,我们能做些什么来绕过亚马逊的保护系统呢?

**在任何网络抓取项目中,模仿真实用户都至关重要。**因此,我们可以使用标准的 HTTP 标头并删除不必要的标头:

[Browser Request Headers

我们需要accept,accept-encoding,accept-languageuser-angent请求头。亚马逊会检查请求头,检测诸如user-angent字段,来决定要不要拒绝访问。

他们还使用速率限制,因此如果您频繁发送请求,您的 IP 可能会被阻止。

首先,我们将为抓取工具定义一个类:

#scraper.py

from bs4 import BeautifulSoup 
from requests import Session 
 
class Amazon: 
	def __init__(self): 
		self.sess = Session() 
		self.headers = { 
			"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", 
			"accept-encoding": "gzip, deflate, br", 
			"accept-language": "en", 
			"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36", 
		} 
		self.sess.headers = self.headers

Amazonclass 定义了一个Session对象,它跟踪我们的连接记录。我们还可以看到,自定义的user-agent和其他标头被用作Session的请求头。由于我们需要获取网页,因此让我们定义一个get方法

# scraper.py
class Amazon: 
	#.... 
	def get(self, url): 
		response = self.sess.get(url) 
 
		assert response.status_code == 200, f"Response status code: f{response.status_code}" 
 
		splitted_url = url.split("/") 
		self.id = splitted_url[-1].split("?")[0] 
		self.product_page = BeautifulSoup(response.text, "html.parser") 
 
		return response

此方法使用上面的会话连接到网站。如果返回的状态代码不是 200,则表示存在错误,因此我们引发 AssertionError

如果请求成功,我们将拆分请求 URL 并提取产品 ID。BeautifulSoup对象定义了产品页面。它将允许我们搜索 HTML 元素并从中提取数据。

现在,我们将定义data_from_product_page方法。这将从产品页面中提取相关信息。我们可以使用find方法并指定元素属性来搜索 HTML 元素。

但是,我们怎么知道要搜索什么呢?

通过使用开发者控制台!我们可以使用开发者控制台来找出我们需要哪些元素和属性。

我们可以右键单击并检查元素:

[Product Title Selector

正如我们所看到的,产品标题写在一个span元素中,属性中有一个productTitle值。

# scraper.py
# As the search result returns another BeautifulSoup object, we use "text" to 
# extract data inside of the element. 
# we will also use strip to remove whitespace at the start and end of the words 
title = self.product_page.find("span", attrs={"id": "productTitle"}).text.strip()

要提取评级,我们可以使用相同的方法!当您检查平均额定值部分时,您将首先看到一个i元素。取而代之的是,我们将使用span元素(由绿色矩形表示)。因为它的title属性已经具有平均评级文本和class值。

我们将搜索具有reviewCountTextLinkedHistogram类的span元素。与其提取元素内的文本,不如使用 title 属性:

[Product Rating Selector

让我们将代码添加到脚本中:

#web-scraping-amazon
# The elements attributes are read as a dictionary, so we can get the title by passing its key 
# of course, we will also use strip here 
rating = self.product_page.find("span", attrs={"class": "reviewCountTextLinkedHistogram"})["title"].strip()

为了打折,有很多classes

[Product Discount Selector reinventPriceSavingsPercentageMarginsavingsPercentage 类是折扣元素独有的,因此我们将使用它们来搜索折扣。当有折扣时,上市价格下方还会写有总价:

[Product Discount List Price

我们找不到其他具有 a-price a-text-price 类的元素。因此,我们将使用它们来查找实际的上市价格。当然,由于尚不确定是否有折扣,我们只有在有折扣时才提取该价格:

# scraper.py
# get the element, "find" returns None if the element could not be found 
discount = self.product_page.find("span", attrs={"class": "reinventPriceSavingsPercentageMargin savingsPercentage"}) 
 
# if the discount is found, extract the total price 
# else, just set the total price as the price found above and set discount = False 
if discount: 
	discount = discount.text.strip() 
	price_without_discount = self.product_page.find("span", attrs={"class": "a-price a-text-price"}).text.strip() 
else: 
	price_without_discount = price 
	discount = False

为了检查产品是否缺货,我们可以检查矩形中的部分是否在页面上。

[Out of Stock Product

让我们检查一下盒子:

[Out of Stock Selector

我们需要检查一个具有id=outOfStockdiv元素是否存在。让我们将此代码片段添加到我们的脚本中:

# scraper.py
# simply check if the item is out of stock or not 
out_of_stock = self.product_page.find("div", {"id": "outOfStock"}) 
if out_of_stock: 
	out_of_stock=True 
else: 
	out_of_stock=False

好吧!我们做到了这一步,唯一剩下的就是产品描述,然后我们就完成了!

产品描述存储在元素中,该元素具有是一个具有id="productDescription"div元素。

[Product Description Selector

我们可以很容易地提取描述:

# scraper.py
description = self.product_page.find("div", {"id": "productDescription"}).text

大多数时候,您必须爬取相关项目。您的抓取工具还应该收集有关其他产品的数据,因为您需要进行适当的分析。您可以存储相关项目的链接,稍后从中提取信息。

如下所示,相关项目存储在一个轮播滑块的 div 元素中。我们可以使用该 div 元素的 a-carousel-viewport 类。我们将获取 li 元素,然后收集 ASIN 值。ASIN 值是 Amazon 的标准识别号码,我们可以用它来构建产品 URL。

[Product Related Items Selector

现在,将代码添加到我们的脚本中:

# scraper.py
# extract the related items carousel's first page 
carousel = self.product_page.find("div", {"class": "a-carousel-viewport"}) 
related_items = carousel.find_all("li") 
 
related_item_asins = [item.find("div")["data-asin"] for item in related_items] 
# of course, we need to get item links 
related_item_links = [] 
for asin in related_item_asins: 
	link = "www.amazon.com/dp/" + asin 
	related_item_links.append(link)

真是太棒了!现在让我们完成到目前为止准备的脚本:

# scraper.py
from bs4 import BeautifulSoup 
from requests import Session 
 
class Amazon: 
	def __init__(self): 
		self.sess = Session() 
		self.headers = { 
			"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", 
			"accept-encoding": "gzip, deflate, br", 
			"accept-language": "en", 
			"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36", 
		} 
		self.sess.headers = self.headers 
 
	def get(self, url): 
		response = self.sess.get(url) 
		 
		assert response.status_code == 200, f"Response status code: f{response.status_code}" 
 
		splitted_url = url.split("/") 
		self.product_page = BeautifulSoup(response.text, "html.parser") 
		self.id = splitted_url[-1].split("?")[0] 
		 
		return response 
 
	def data_from_product_page(self): 
		 
		# As the search result returns another BeautifulSoup object, we use "text" to 
		# extract data inside of the element. 
		# we will also use strip to remove whitespace at the start and end of the words 
		title = self.product_page.find("span", attrs={"id": "productTitle"}).text.strip() 
 
		# The elements attributes are read as a dictionary, so we can get the title by passing its key 
		# of course, we will also use strip here 
		rating = self.product_page.find("span", attrs={"class": "reviewCountTextLinkedHistogram"})["title"].strip() 
 
		# First, find the element by specifiyng a selector with two options in this case 
		price_span = self.product_page.select_one("span.a-price.reinventPricePriceToPayMargin.priceToPay, span.a-price.apexPriceToPay") 
		# Then, extract the pricing from the span inside of it 
		price = price_span.find("span", {"class": "a-offscreen"}).text.strip() 
 
		# Get the element, "find" returns None if the element could not be found 
		discount = self.product_page.find("span", attrs={"class": "reinventPriceSavingsPercentageMargin savingsPercentage"}) 
		# If the discount is found, extract the total price 
		# Else, just set the total price as the price found above and set discount = False 
		if discount: 
			discount = discount.text.strip() 
			price_without_discount = self.product_page.find("span", attrs={"class": "a-price a-text-price"}).text.strip() 
		else: 
			price_without_discount = price 
			discount = False 
 
		# Simply check if the item is out of stock or not 
		out_of_stock = self.product_page.find("div", {"id": "outOfStock"}) 
		if out_of_stock: 
			out_of_stock=True 
		else: 
			out_of_stock=False 
		 
		# Get the description 
		description = self.product_page.find("div", {"id": "productDescription"}).text 
 
		# Extract the related items carousel's first page 
		carousel = self.product_page.find("div", {"class": "a-carousel-viewport"}) 
		related_items = carousel.find_all("li") 
 
		related_item_asins = [item.find("div")["data-asin"] for item in related_items] 
		# Of course, we need to return the product URLs 
		# So let's construct them! 
		related_item_links = [] 
		for asin in related_item_asins: 
			link = "www.amazon.com/dp/" + asin 
			related_item_links.append(link) 
 
		extracted_data = { 
			"title": title, 
			"rating": rating, 
			"price": price, 
			"discount": discount, 
			"price without discount": price_without_discount, 
			"out of stock": out_of_stock, 
			"description": description, 
			"related items": related_item_links 
		} 
		 
		return extracted_data

让我们使用产品的链接尝试一下:

# scraper.py
scraper = Amazon() 
scraper.get("https://www.amazon.com/Crockpot-Electric-Portable-20-Ounce-Licorice/dp/B09BDGFSWS") 
data = scraper.data_from_product_page() 
 
for k,v in data.items(): 
	print(f"{k}:{v}")

最终输出:

输出

title:Crockpot Electric Lunch Box, Portable Food Warmer for On-the-Go, 20-Ounce, Black Licorice 
rating:4.7 out of 5 stars 
price:$29.99 
discount:False 
price without discount:$29.99 
out of stock:False 
description: 
 Take your favorite meals with you wherever you go! The Crockpot Lunch Crock Food Warmer is a convenient, easy-to-carry, electric lunch box. Plus, with its modern-vintage aesthetic and elegant Black Licorice color, it's stylish, too. It is perfectly sized for one person, and is ideal for carrying and warming meals while you’re on the go. With its 20-ounce capacity, this heated lunch box is perfect whether you're in the office, working from home, or on a road trip. Take your leftovers, soup, oatmeal, and more with you, then enjoy it at the perfect temperature! This portable food warmer features a tight-closing outer lid to help reduce spills, as well as an easy-carry handle, soft-touch coating, and detachable cord. The container is removable for effortless filling, carrying, and storage. Cleanup is easy, too: the inner container and lid are dishwasher-safe. 
related items:['www.amazon.com/dp/B09YXSNCTM', 'www.amazon.com/dp/B099PNWYRH', 'www.amazon.com/dp/B09B14821T', 'www.amazon.com/dp/B074TZKCCV', 'www.amazon.com/dp/B0937KMYT8', 'www.amazon.com/dp/B07T7F5GHX', 'www.amazon.com/dp/B07YJFB8GY']

当然,亚马逊的页面结构相当复杂,所以不同的产品页面可能有不同的结构。因此,应该重复此过程以构建坚固的网络爬虫。

祝贺!如果您遵循,您就建立了自己的亚马逊产品抓取工具!

结论

亚马逊的网页结构很复杂,您可能会看到不同的结构化页面。您应该找出差异并随之更新您的应用程序。

在纵向扩展时,您还需要随机化 HTTP 标头并使用高级代理服务器。否则,你很容易被发现。

在本文中,你已了解

  1. 从亚马逊抓取数据的重要性。
  2. 亚马逊用来阻止网络爬虫的方法。
  3. 从亚马逊抓取产品价格、描述和更多数据。
导航目录