爬虫——playwright获取亚马逊数据

news2025/3/22 3:01:22

目录

  • playwright简介
  • 使用playwright初窥亚马逊
    • 安装playwright
    • 打开亚马逊页面
  • 搞数据
    • 搜索
    • 修改bug
    • 数据获取
    • 翻页
      • 优化结构
    • 简单保存

playwright简介

playwright是微软新出的一个测试工具,与selenium类似,不过与selenium比起来还是有其自身的优势的(除了教程少是弱项)。

  • 任何浏览器 • 任何平台 • 一个 API

    • 跨浏览器。 Playwright 支持所有现代渲染引擎,包括 Chromium、WebKit 和 Firefox。
    • 跨平台。 在 Windows、Linux 和 macOS 上进行本地或 CI 测试,无头或有头。
    • 跨语言。 在 TypeScript、JavaScript、Python、.NET、Java 中使用 Playwright API。
    • 测试移动网络。 适用于 Android 的 Google Chrome 和 Mobile Safari 的原生移动模拟。 相同的渲染引擎可以在桌面和云端运行。
      (上面是抄官网的, 下面才是个人的使用体验)
  • 方便

    • 配置方便。与selenium的配置相比较的话,不需要下载额外的驱动,也不需要下载对应版本的浏览器。(就是配置地址不能修改)。
    • 可以异步selenium是只能阻塞式的执行,而playwright可以执行异步。
    • 内存占用少。好像确实是比较少一点。

使用playwright初窥亚马逊

通常情况,每家电商平台都有自己的反爬措施,亚马逊也不例外,所以要尝试一下,当然如果是scrapy这个爬虫框架的话,似乎可以越过反爬措施,内部的逻辑代码是什么没有深究,现在先拿过来用用。

安装playwright

同样的,这个第三方库也要安装,直接使用pip安装就行

pip install playwright

安装完毕之后,还需要安装一些依赖,只要执行一句话即可。这样就能安装了。

playwright install

如果不能安装,或者安装卡进度条了,可以查看这个教程

打开亚马逊页面

小试牛刀一把,看看这个库怎么样

import asyncio
import time
import traceback
from playwright.async_api import async_playwright

class AmazonBrowser:
    def __init__(self, headless=True):
        self.headless = headless
        self.browser = None
        self.page = None
        self.playwright = None

    async def start(self):
        self.playwright = await async_playwright().start()
        self.browser = await self.playwright.chromium.launch(headless=False)
        self.page = await self.browser.new_page()
        await self.page.goto("https://www.amazon.com/")
        time.sleep(60)
        await self.browser.close()

if __name__ == "__main__":
    asyncio.run(AmazonBrowser().start())

在这里插入图片描述
what!!! 不愧是美国注明的电商平台,上来就是验证码=。=还有点不好搞定。

那试试添加headers,应该可以

class AmazonBrowser:
    def __init__(self, headless=True):
        self.headless = headless
        self.browser = None
        self.page = None
        self.playwright = None
        self.headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36",
            "Accept-Language": "en-US,en;q=0.9",
            "Accept-Encoding": "gzip, deflate, br",
            "Referer": "https://www.google.com/", # 伪造,告诉亚马逊网站,说我是从Google搜索页面点击进来的。
        }

在这里插入图片描述
诶嘿! 来了!

搞数据

在第一个页面里面,没有我们想要的数据,所以我们需要输入内容,然后从新的页面中搞到要的数据。
获取元素 → 搜索 → 搞数据 应该是这个思路。

搜索

我们需要获取2个元素,一个元素是搜索框,另一个元素是搜索按钮(当然搞回车按键也行),从F12里面可以得知,搜索框是下面的内容:
在这里插入图片描述
搜索按钮是下面的:
在这里插入图片描述
先搞定输入框:

import random # 引入random库
class AmazonBrowser:
    async def start(self):
        self.playwright = await async_playwright().start()
        self.browser = await self.playwright.chromium.launch(headless=False)
        self.page = await self.browser.new_page()
        await self.page.set_extra_http_headers(self.headers)
        await self.page.goto("https://www.amazon.com/")
		search_box = self.page.locator("input#twotabsearchtextbox")# 这里的input有个id,就是twotabsearchtextbox,这个id应该是独立的,所以直接用它。
        await search_box.wait_for(state="visible")
        await search_box.type('键盘', delay=random.uniform(50, 200)) 
        time.sleep(60)

【细节讲解】

  • locator:在Playwright中,locator的作用是用于定位页面上的元素,语法有很多:
    • "text=登录"是通过文本匹配,
    • "#username"是通过ID匹配,
    • "//button[@type='submit']"是通过xpath匹配,
    • "a.s-pagination-next.s-pagination-separator"通过css匹配,
    • "a.s-pagination-next.s-pagination-separator:not([aria-disabled="true"])",这个则是排除具有aria-disabled="true"属性的元素。
  • type:在playwright中,type的作用时将文字打入输入框中,与之类似的方法是fill,只不过前者是将文字挨个键入,而后者则是将文字一次性输入,在严格监听页面的网页中,type的的功能用的会比较多,因为可以模拟人的操作,而fill则不行。

再执行看看~
在这里插入图片描述
芜湖~
在这里插入图片描述
同样的,找到搜索按钮并点击就能跳转过去了。

class AmazonBrowser:
    async def start(self):
    # ...
        await search_box.type("键盘", delay=random.uniform(50, 200))
        await self.page.locator("input#nav-search-submit-button").click()

在这里插入图片描述

修改bug

有的人可能会遇到另外一种情况:
在这里插入图片描述
这个时候搜索输入框和搜索按钮的id就已经不一样了,这种情况的搜索输入框是id="nav-bb-search",搜索按钮是没有id的只有class="nav-bb-button",所以要修改上面的代码

class AmazonBrowser:
    async def start(self):
		#...
		# 同时检测两种搜索框的存在
        twotab_exists = await self.page.locator("input#twotabsearchtextbox").count()
        navbb_exists = await self.page.locator("input#nav-bb-search").count()
        if twotab_exists:
            search_box = self.page.locator("input#twotabsearchtextbox")
            search_btn = self.page.locator("input#nav-search-submit-button")
        elif navbb_exists:
            search_box = self.page.locator("input#nav-bb-search")
            search_btn = self.page.locator("input.nav-bb-button")
        else:
            raise Exception("No search box found")
        await search_box.wait_for(state="visible")
        await search_box.type("键盘", delay=random.uniform(50, 200))
        await search_btn.click()

数据获取

我们先来看看要搞哪些数据:
在这里插入图片描述
从这个截图上看,有图片,标题,评分,价格。不过有一点是:第二个图片里面有2个价格,到底那个是真实的价格呢?点进去发现,第一个价格是原价,第二个价格好像是二手价格。
在这里插入图片描述
那就弄原价吧,不然太麻烦了。可是他的标题有了,要是标题重复了怎么办?从F12里面可以发现data-asin应该是唯一的,那我们就把这个ASIN弄到手,当然后面也有一个uuid,弄那个也行。
在这里插入图片描述

# 新增依赖库
from urllib.parse import urljoin

class AmazonBrowser:
    async def start(self):
    	#...
    	await self.page.wait_for_selector('div[role="listitem"][data-asin]', timeout=15000)
        items = await self.page.locator('div[role="listitem"][data-asin]').all()
        batch_data = []
        for index, item in enumerate(items):
        	asin = await item.get_attribute("data-asin")
        	uuid = await item.get_attribute("data-uuid")
        	img = item.locator('img.s-image').first
        	await img.scroll_into_view_if_needed()
        	await self.page.wait_for_timeout(500)
        	src = await img.get_attribute('src')
			href = await item.locator('a.a-link-normal.s-line-clamp-2').get_attribute('href')
			product = await item.locator('h2.a-size-medium > span').first.inner_text()
			price_section = item.locator('span.a-price[data-a-color="base"]')
			if await price_section.count() > 0:
				price = await price_section.locator('span.a-offscreen').first.inner_text()
			else:
				price_section_secondary = item.locator('div.a-row.a-size-base.a-color-secondary')
                if await price_section_secondary.count() > 0:
            		price = await price_section_secondary.locator('span.a-color-base').first.inner_text()
            	else:
            		price = '暂无价格'
            batch_data.append({
                        'Product': product,
                        'UUID': uuid,
                        'ASIN': asin,
                        'ImageURL': src,
                        'URL': urljoin(self.target_url, href) if href else None,
                        'Price': price,
                    })

【细节讲解】

  • wait_for_selector:是等待页面上符合选择器的元素出现,最长等待15秒。
    • div[role="listitem"][data-asin]:是选择<div>元素,要求这个元素里面有[role="listitem"]以及[data-asin]这两个东西。
  • await,异步标志,有些情况下需要使用,有些情况下则不需要使用:
    • 需要使用的情况:
      • 涉及网络请求:如 goto()fetch()
      • 获取异步返回的内容:如 text_content()inner_text()
      • 涉及页面交互的操作:如点击、输入、等待
      • 需要时间完成的操作:如 wait_for_selector()
    • 不需要使用的情况:
      • locator()对象
      • 只定义选择器,不交互
      • 直接获取属性,如browser.name

翻页

一页当然是不行的,一页才16条数据,所以肯定要翻页的。同理从F12里面找到翻页标签,那就是
在这里插入图片描述
然后仅有这个也不够,我们还要知道终止,也就是不能点击的情况下,是什么情况的,所以翻到20页得到
在这里插入图片描述
所以需要设计选择器,来判断下一页按钮能不能按下去,或者是能不能检测到终止的<span>

class AmazonBrowser:
	async def start(self):
		#...
		disabled_selector = 'span.s-pagination-next.s-pagination-disabled'
		enabled_selector = 'a.s-pagination-next:not([aria-disabled="true"])'
		# 当检测到disable_selector时就继续
		while True:
			if await self.page.locator(disabled_selector).count() > 0:
				break
			next_btn = self.page.locator(enabled_selector)
			await next_btn.scroll_into_view_if_needed()
			        # 点击前确保元素可交互
        	await next_btn.wait_for(state="visible")
        	await next_btn.click()
        	await self.page.wait_for_timeout(2000)  # 基础等待

在这里插入图片描述

优化结构

但是仅有循环,没有获取数据,这也不是我们想要的,所以接下来是优化结构。将数据获取也翻页分开。

class AmazonBrowser:
	# ...
	async def data_collection(self):
        await self.page.wait_for_selector('div[role="listitem"][data-asin]', timeout=15000)
        items = await self.page.locator('div[role="listitem"][data-asin]').all()
        for index, item in enumerate(items):
            asin = await item.get_attribute("data-asin")
            uuid = await item.get_attribute("data-uuid")
            img = item.locator('img.s-image').first
            await img.scroll_into_view_if_needed()
            await self.page.wait_for_timeout(500)
            src = await img.get_attribute('src')
            href = await item.locator('a.a-link-normal.s-line-clamp-2').get_attribute('href')
            product = await item.locator('h2.a-size-medium > span').first.inner_text()
            price_section = item.locator('span.a-price[data-a-color="base"]')
            if await price_section.count() > 0:
                price = await price_section.locator('span.a-offscreen').first.inner_text()
            else:
                price_section_secondary = item.locator('div.a-row.a-size-base.a-color-secondary')
                if await price_section_secondary.count() > 0:
                    price = await price_section_secondary.locator('span.a-color-base').first.inner_text()
                else:
                    price = '暂无价格'
			# self.batch_data要提前声明哦
            self.batch_data.append({
                'Product': product,
                'UUID': uuid,
                'ASIN': asin,
                'ImageURL': src,
                'URL': urljoin(self.target_url, href) if href else None,
                'Price': price,
            })
	async def start(self):
		#...
		disabled_selector = 'span.s-pagination-next.s-pagination-disabled'
		enabled_selector = 'a.s-pagination-next:not([aria-disabled="true"])'
		# 当检测到disable_selector时就继续
		while True:
			if await self.page.locator(disabled_selector).count() > 0:
				break
			# 在这里添加
			await self.data_collection()
			next_btn = self.page.locator(enabled_selector)
			await next_btn.scroll_into_view_if_needed()
			        # 点击前确保元素可交互
        	await next_btn.wait_for(state="visible")
        	await next_btn.click()
        	await self.page.wait_for_timeout(2000)  # 基础等待

这样就搞定啦,但是数据要怎么保存呢?可以有两种方式,一种方式是保存在数据库里面,比如mongodb,mysql等等,还可以保存在csv文件里面。

简单保存

在这里就简单的保存成csv文件的样子吧,也就是直接使用pandas保存就行了,下一篇章就搞一下mongodb

# 导入依赖库
import pandas as pd
class AmazonBrowser:
	def __init__(self):
		self.df = pd.DataFrame()
	#... 
	async def start(self):
		while True:
			#...while循环内容
		new_df = pd.DataFrame(self.batch_data)
        self.df = pd.concat([self.df, new_df], ignore_index=True)
        self.df.to_csv(path)

就酱~
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2319298.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大数据学习(77)-Hive详解

&#x1f34b;&#x1f34b;大数据学习&#x1f34b;&#x1f34b; &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 用力所能及&#xff0c;改变世界。 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4dd;支持一…

汽车一键启动PKE无钥匙系统

移动管家汽车一键启动PKE舒适无钥匙遥控远程系统是一种集成了多项先进功能的汽车电子系统&#xff0c;主要目的是提高驾驶便利性和安全性。 以下是该系统的具体功能&#xff1a; 功能类别 功能描述 无钥匙进入 感应无钥匙进入&#xff08;自动感应开关门&#xff09; 一…

Postman 新手入门指南:从零开始掌握 API 测试

Postman 新手入门指南&#xff1a;从零开始掌握 API 测试 一、Postman 是什么&#xff1f; Postman 是一款功能强大的 API 开发与测试工具&#xff0c;支持 HTTP 请求调试、自动化测试、团队协作等功能。无论是开发人员还是测试工程师&#xff0c;都可以用它快速验证接口的正确…

猿大师中间件:如何在最新Chrome浏览器Web网页内嵌本地OCX控件?

OCX控件是ActiveX控件的一种&#xff0c;主要用于在网页中嵌入复杂的功能&#xff0c;如图形渲染、多媒体播放等&#xff0c;可是随着谷歌Chrome等主流浏览器升级&#xff0c;目前已经不支持微软调用ActiveX控件了&#xff0c;如果想调用OCX控件用IE浏览器或者国产双擎浏览器&a…

[数据结构]排序之 归并排序(有详细的递归图解)

一、非递归 基本思想&#xff1a; 归并排序&#xff08; MERGE-SORT &#xff09;是建立在归并操作上的一种有效的排序算法 , 该算法是采用分治法&#xff08; Divide andConquer&#xff09;的一个非常典型的应用。将已有序的子序列合并&#xff0c;得到完全有序的序列&#x…

构建第二个Django的应用程序

构建第二个应用程序 文章目录 构建第二个应用程序1.打开Visual Studio code 左上角 点击fike 点击open folder2.打开上次的Django项目 并按图示点击进入终端3.在下方终端输入创建app01项目的命令 接着在左上方会出现一个app01的项目4.接着在Hellodjango的项目里settings.py中定…

图像分割的mask有空洞怎么修补

分享一个对实例分割mask修补的方法&#xff0c;希望对大家有所帮助。 1. 这是我准备分割的图片 2 分割结果 可以看到衣服部分有一些没分割出来&#xff0c;二值化图片能清晰看到衣服部分有些黑色未分出的地方。 3 补全mask区域 import cv2 import numpy as npdef fill_mask_h…

HarmonyOS NEXT 组件状态管理的对比

在HarmonyOS NEXT开发中&#xff0c;组件状态管理是构建动态用户界面的核心。本文将深入探讨State、Prop、Link和ObjectLink这四种常见的状态管理装饰器&#xff0c;并通过示例代码进行对比分析&#xff0c;以帮助同学们更好地理解和选择合适的状态管理方式。 一、装饰器概述 …

C#通过API接口返回流式响应内容---SignalR方式

1、背景 在上两篇《C#通过API接口返回流式响应内容—分块编码方式》和《C#通过API接口返回流式响应内容—SSE方式》实现了流式响应的内容。 上面的这两个主要是通过HTTP的一些功能&#xff0c;除了这些之外&#xff0c;还有WebSocket的方式。C#中的WebSocket的有比较多的方案&…

vulhub靶机----基于docker的初探索,环境搭建

环境搭建 首先就是搭建docker环境&#xff0c;这里暂且写一下 #在kali apt update apt install docker.io配置docker源&#xff0c;位置在/etc/docker/daemon.json {"registry-mirrors": ["https://5tqw56kt.mirror.aliyuncs.com","https://docker…

AI对话框实现

请注意&#xff0c;功能正在开发中&#xff0c;代码和注释不全 场景&#xff1a;AI对话框实现&#xff0c;后端调用AI大模型。前端发送请求后端返回流式数据&#xff0c;进行一问一答的对话功能&#xff08;场景和现在市面上多个AI模型差不多&#xff0c;但是没人家功能健全&a…

可视化图解算法:删除链表中倒数第n个节点

1. 题目 描述 给定一个链表&#xff0c;删除链表的倒数第 n 个节点并返回链表的头指针 例如&#xff0c; 给出的链表为: 1→2→3→4→5, n 2. 删除了链表的倒数第 n 个节点之后,链表变为1→2→3→5. 数据范围&#xff1a; 链表长度 0≤n≤1000&#xff0c;链表中任意节点的…

智能汽车图像及视频处理方案,支持视频智能拍摄能力

美摄科技&#xff0c;作为智能汽车图像及视频处理领域的先行者&#xff0c;凭借其卓越的技术实力和前瞻性的设计理念&#xff0c;为全球智能汽车制造商带来了一场视觉盛宴的革新。我们自豪地推出——美摄科技智能汽车图像及视频处理方案&#xff0c;一个集高效性、智能化、画质…

微信小程序的业务域名配置(通过ingress网关的注解)

一、背景 微信小程序的业务域名配置&#xff08;通过kong网关的pre-function配置&#xff09;是依靠kong实现&#xff0c;本文将通过ingress网关实现。 而我们的服务是部署于阿里云K8S容器&#xff0c;当然内核与ingress无异。 找到k8s–>网络–>路由 二、ingress注解 …

Matlab 舰载机自动着舰控制系统研究

1、内容简介 Matlab 188-舰载机自动着舰控制系统研究 可以交流、咨询、答疑 2、内容说明 略 3、仿真分析 略 4、参考论文 略

WindowsAD域服务权限提升漏洞

WindowsAD 域服务权限提升漏洞&#xff08;CVE-2021-42287, CVE-2021-42278&#xff09; 1.漏洞描述 Windows域服务权限提升漏洞&#xff08;CVE-2021-42287, CVE-2021-42278&#xff09;是由于Active Directory 域服务没有进行适当的安全限制&#xff0c;导致可绕过安…

Flutter 学习之旅 之 flutter 使用 SQLite(sqflite) 实现简单的数据本地化 保存/获取/移除/判断是否存在 的简单封装

Flutter 学习之旅 之 flutter 使用 SQLite&#xff08;sqflite&#xff09; 实现简单的数据本地化 保存/获取/移除/判断是否存在 的简单封装 目录 Flutter 学习之旅 之 flutter 使用 SQLite&#xff08;sqflite&#xff09; 实现简单的数据本地化 保存/获取/移除/判断是否存在…

【leetcode hot 100 208】实现Trie(前缀树)

解法一&#xff1a;字典树 Trie&#xff0c;又称前缀树或字典树&#xff0c;是一棵有根树&#xff0c;其每个节点包含以下字段&#xff1a; 指向子节点的指针数组 children。对于本题而言&#xff0c;数组长度为 26&#xff0c;即小写英文字母的数量。此时 children[0] 对应小…

鸿蒙 元服务摘要

元服务&#xff08;原名原子化服务&#xff09;&#xff0c;是HarmonyOS提供的一种面向未来的服务提供方式&#xff0c;是有独立入口的&#xff08;用户可通过点击方式直接触发&#xff09;、免安装的&#xff08;无需显式安装&#xff0c;由系统程序框架后台安装后即可使用&am…

【css酷炫效果】纯CSS实现粒子旋转动画

【css酷炫效果】纯CSS实现粒子旋转动画 缘创作背景html结构css样式完整代码效果图 想直接拿走的老板&#xff0c;链接放在这里&#xff1a;https://download.csdn.net/download/u011561335/90492008 缘 创作随缘&#xff0c;不定时更新。 创作背景 刚看到csdn出活动了&…