Playwright使用教程【附爬取Leetcode题目URLs以及有道翻译小软件】

前言

playwright是微软设计的一款工具,可以爬取网页,还可以自动化测试自己编写的网站,而且不像bs4、request编写爬虫那么复杂,也不需要考虑反爬技术,只需要知道最基础的前端知识,就可以高效、便捷的编写爬虫代码

但是这篇文章不可能将playwright的所有功能全部讲到,但是覆盖了最基础的一些知识,如果想更系统的学习,可以参考playwright python的官方文档:https://playwright.dev/python/docs/intro

也非常推荐白月黑羽的教程:Playwright web自动化 - Python版_哔哩哔哩_bilibili

安装步骤

pip install pytest-playwright
playwright install

简单demo

使用下面命令可以开启录制

playwright codegen

在这里插入图片描述

右边窗口会自动根据左边浏览器做的操作进行记录,下面是自动生成的代码模板,定义了同步操作(不是异步)的playwright类,并输入到run函数中,browser这句代码开辟新的进程,打开了playwright自带的浏览器chromium,这个可以自己改为其他的浏览器(参考官网),headless为False时,执行过程会打开浏览器,否则将不会显示。

from playwright.sync_api import Playwright, sync_plawright, expectdef run(playwright: Playwright) -> None:browser = playwright.chromium.launch(headless=False)context = browser.new_context()page = context.new_page()# ---------------------context.close()browser.close()with sync_playwright() as playwright:run(playwright)

在左边浏览器键入www.baidu.com,右边代码就新增了代码,表示跳转到了这个界面

page.goto("https://www.baidu.com/")

然后点击输入框,并输入nihao,就会新增下面这些代码,其中locator是定位器,page.locator("#kw") 定位到的是输入的文本框,即定位到网页中的一个部件,后面的click、fill、press分别表示点击、填充、输入回车等操作,对部件的操作见Actions | Playwright Python

page.locator("#kw").click()
page.locator("#kw").fill("nihao")
page.locator("#kw").press("Enter")

这样一来就可以自动设计代码啦,同时还可以使用tracing模块来记录执行的过程

context = browser.new_context()
context.tracing.start(snapshots=True, sources=True, screenshots=True)
...
context.tracing.stop(path="trace.zip")

然后在终端执行就可以显示整个的过程,左边为playwright的各种操作,右边有Action,Before和After显示每一步的动作、先前状态和执行过后的状态

playwright show-trace trace.zip

在这里插入图片描述

这样一个简单的demo,打开baidu网站,查询nihao,就实现啦

from playwright.sync_api import Playwright, sync_playwright, expectdef run(playwright: Playwright) -> None:browser = playwright.chromium.launch(headless=False)context = browser.new_context()context.tracing.start(snapshots=True, sources=True, screenshots=True)page = context.new_page()page.goto("https://www.baidu.com/")page.locator("#kw").click()page.locator("#kw").fill("nihao")page.locator("#kw").press("Enter")context.tracing.stop(path="trace.zip")context.close()browser.close()with sync_playwright() as playwright:run(playwright)

任务描述和预备知识

我将通过一个实际应用来说明如何使用playwright,获取到leetcode上每一个题目的url网址。

进入leetcode官网,点击题库
在这里插入图片描述

然后跳到第二页
在这里插入图片描述

发现网页为:https://leetcode.cn/problemset/?page=2,其中?右边为参数,表示在第几页,没有page参数时默认第1页,我们发现每一页都有50个题目(除了第一页有51个题目,需要特殊处理)

点击F12打开开发者模式,右边选择“元素”菜单

在这里插入图片描述

点击下面的图表,然后在左侧点击控件,可以查看到第52题这块对应的源码,右边源码中有属性href=“/problems/n-queens-ii”,这就是我们想要获取的信息,但是这个网页不完整,点击这个网站后,可以看到网页变为了https://leetcode.cn/problems/n-queens-ii/description,所以还需要加上前缀:“https://leetcode.cn” 和后缀 ”/description“

在这里插入图片描述
在这里插入图片描述

我们的目标是获取到每一个题目的href信息,并保存在一个txt文件当中

选择器定位

前面使用到了page.locator方法,里面的参数就是我们去定位组件的标准,我们不能完全依靠codegen这一个方法自动化完成代码,如果需要输出一些信息,就不能指望它了,所以这一节将介绍如何定位元素以及元素的一些操作

我们首先在模板中填写下面的代码,暂时不处理最后一页的题目,遍历第1页到第72页的题目,然后goto到该网站,并等待5s,之所以等待5s是因为需要等网页加载完毕后,才能提取到相关的信息,否则会加载错误

for page_index in trange(1, 73):page.goto(f"https://leetcode.cn/problemset/?page={page_index}")page.wait_for_timeout(5000)

接下来就是定位了,例如某一个分块有class属性,如下所示,则locator里面可以写为page.locator(".truncate") ,这里的"."表示匹配的class元素

<div class='truncate'>nihao
</div>

然后可以调用.inner_text()可以打印这一个locator的文本信息

lc = page.locator(".truncate")
print(lc.inner_text())	# 输出nihao

然而一个html网页中可能有多个块的class包含truncate,那么 page.locator(".truncate") 就会定位到所有的块,这时候就需要使用.all()方法,将所有定位到的locator转变为list对象,然后我们遍历list,再打印文本信息

lcs = page.locator(".truncate").all()
for lc in lcs:print(lc.inner_text())

注意,如果locator定位到的元素个数大于1,则不能执行fill、click、inner_text等操作,需要使用all()将其转换为列表,下面是locator的一些方法和用法

locator(".truncate").count()		# 匹配元素的个数
locator(".truncate").first			# 第一个元素
locator(".truncate").last			# 最后一个元素
locator(".truncate").nth(3)			# 第三个元素

除了使用class定位,还可以使用id定位,一般而言html中的id是唯一的,例如下面的代码可以使用 page.locator("#animal") 来定位,"#"表示id

<div id='animal'>nihao
</div>

如果一个块中有多个class类别,例如下面的例子,使用 page.locator(".animal.plant") 定位,注意中间不能有空格

<div class='animal plant'>nihao
</div>

还可以直接使用page.locator(“div”)来定位这个div块,如果不是上述情况,而是其他的属性名,则可以用方括号来指示,例如下面的例子可以用 page.locator("[role=region]") 定位

<div role='region'>nihao
</div>

还可以是模糊匹配,包含 *=, ^=, *=等方式

[href*=www] -> href属性包含www的元素
[href^=www] -> href属性以www开头的元素
[href$=www] -> href属性以www结尾的元素

我们还可以通过多级选择器来选择,在下面的例子中,想定位nihao,可以使用 page.locator(".a > .b)" 定位,“>” 表示直接子节点,如果想定位oahin,还可以使用子孙节点的定位方式,使用空格来隔开 page.locator(".a .d") ,这样就跳过了中间节点".c"

<div class='a'><div class='b'>nihao</div><div class='c'><div class='d'>oahin</div></div>
</div>

实际定位

弄清楚如何定位后,接下来,我们要获取每一页中的所有题目的信息,找到某一个题目的信息,代码如下

在这里插入图片描述

可以使用下面的代码定位,但是如何确定是否准确定位到呢,一个方法就是执行一遍代码,打印出来定位到的块,查看是否符合预期,但是这样太麻烦了,浏览器中可以帮助我们查看

lcs = page.locator(".truncate .h-5")

在右上方(下方是另一个界面了)输入Ctrl + F开启搜索功能,输入.truncate .h-5,看到我们找到了50个元素,刚好对应一页中题目的个数

在这里插入图片描述

我们可以通过下面的代码获取到第i个元素的url地址,使用到了get_attribute方法获取某一个属性的值

lcs = page.locator(".truncate .h-5")
lcs.nth(i).get_attribute("href")

然后我们可以将url补充完整,特殊处理一下第一页51道题目的情况,将题目索引以及url保存在urls.txt文件当中,编写完成下面的脚本

from playwright.sync_api import Playwright, sync_playwright
from tqdm import trangedef run(playwright: Playwright) -> None:with open('urls.txt', 'w') as f:browser = playwright.chromium.launch(headless=True)context = browser.new_context()page = context.new_page()cnt = 1for page_index in trange(1, 73):page.goto(f"https://leetcode.cn/problemset/?page={page_index}")page.wait_for_timeout(5000)lcs = page.locator(".truncate .h-5")for problem_index in range(50):     # 第一页的题目索引要加一problem_page = f'https://leetcode.cn{lcs.nth(problem_index + int(page_index == 1)).get_attribute("href")}/description'f.write(str(cnt) + ' ' + problem_page + '\n')cnt += 1f.flush()context.close()browser.close()with sync_playwright() as playwright:# 获取系统参数run(playwright)

最终获取了信息啦!

在这里插入图片描述

如果对您有帮助,请不要吝啬您的赞呀,你们的鼓励是我最大的动力!

补充样例

下面的例子是打开有道翻译,输入英文,返回翻译后的信息代码,如果您感兴趣,可以看看哦,使用到的方法都差不多~

from playwright.sync_api import Playwright, sync_playwright, expect
import redef run(playwright: Playwright) -> None:browser = playwright.chromium.launch(headless=True)context = browser.new_context()page = context.new_page()page.goto("https://fanyi.youdao.com/#/") page.locator(".close").click()page.locator("div").filter(has_text=re.compile(r"^翻译$")).click()page.locator(".ic_language_arrowdown").first.click()page.get_by_text("英语").first.click()page.wait_for_timeout(1000)while True:word = input("=" * 100 + "\n>>> ")page.locator("#js_fanyi_input").click()page.locator("#js_fanyi_input").fill(word)page.wait_for_timeout(1000)if page.locator(".pron").count():   # 单个单词,打印音标以及所有意思for text in page.locator(".pron").all_inner_texts():split = text.split()if not split:continueelse:print(f"{split[0]}: /{split[1]}/")print(page.locator(".paraphrase-container").first.inner_text())else:   # 句子,直接显示翻译print(page.locator(".tgt.un-step-trans").inner_text())# ---------------------context.close()browser.close()with sync_playwright() as playwright:run(playwright)

执行效果

在这里插入图片描述

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

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

相关文章

筑牢代码安全之盾 —— 沙箱在源代码防泄密中四大特性

在这个数字化飞速发展的时代&#xff0c;源代码作为企业的核心资产&#xff0c;其安全性显得尤为重要。一旦泄露&#xff0c;不仅可能导致知识产权的损失&#xff0c;还可能引发一系列连锁反应&#xff0c;威胁企业的生存和发展。在这样的背景下&#xff0c;SDC沙盒以其独特的产…

电子电气架构 --- 关于DoIP的一些闲思 下

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自己,无利益不试图说服别人,是精神上的节…

【密码学】大整数分解问题和离散对数问题

公钥密码体制的主要思想是通过一种非对称性&#xff0c;即正向计算简单&#xff0c;逆向计算复杂的加密算法设计&#xff0c;来解决安全通信。本文介绍两种在密码学领域内最为人所熟知、应用最为广泛的数学难题——大整数分解问题与离散对数问题 一、大整数分解问题 &#xf…

【pyqt-实训训练LOG】串口助手

串口助手 前言一、ui设计二、ui的控件命名三、ui转py使用类的方法【扩展】使用ui文件导入&#xff01;P7的小错误解决办法 总结 前言 我的惯例就是万物之始&#xff0c;拜见吾师&#x1f970;⇨pyqt串口合集 最开始的时候我想的是&#xff0c;学了那么久的pyqt&#xff0c;我…

论文学习 StarGANv2 ——StarGAN v2: Diverse Image Synthesis for Multiple Domains

多领域不同图像合成 We have made dataset available at https://github.com/clovaai/stargan-v2. 摘要&#xff1a; 一个好的图像到图像转换模型应该学习不同视觉域之间的映射&#xff0c;同时满足以下属性: 1)生成图像的多样性 2)在多个域上的可扩展性。 现有的方法解决…

PFC电路中MOS管的选取3

MOS管的驱动波形 一个 MOS管在开通或者关断的时候&#xff0c;必定会经历一个线性区。这个线性区域在 Vgs波形上表现出一个平台&#xff0c;在这个平台的时候电流和电压的变化率是很大的&#xff0c;有很大的 dv/dt&#xff0c;di/dt &#xff0c;由于 di/dt变化非常大&#xf…

【java计算机毕设】学生项目竞赛管理系统 MySQL ssm JSP maven小组项目设计代码源码+万字文档

目录 1项目功能 2项目介绍 3项目地址 1项目功能 【java计算机毕设】学生项目竞赛管理系统 MySQL ssm JSP maven小组项目设计代码源码万字文档 2项目介绍 系统功能&#xff1a; 学生项目竞赛管理系统包括管理员、用户、教师三种角色。 管理员功能包括个人中心模块用于修改个…

一位互联网公司项目经理繁忙的一天

早晨&#xff1a;准备与计划 7:00 AM - 起床与准备 项目经理起床后&#xff0c;快速洗漱并享用早餐。之后花几分钟查看手机上的邮件和消息&#xff0c;确保没有紧急事务需要立即处理。 7:30 AM - 通勤时间 前往公司。在通勤途中&#xff0c;通过手机或平板电脑查看当天的会议…

Java多线程面试题

目录 一.线程和进程的区别 二.保证线程安全的手段 三.创建多线程的方式 四.线程池的讲解 五.volatile和synchronzied的区别 六.synchronized 和 Lock的区别 七.产生死锁的条件 八.Java当中常见的锁策略 本专栏全是博主自己收集的面试题&#xff0c;仅可参考…

C基础day8

一、思维导图 二、课后习题 #include<myhead.h> #define Max_Stu 100 //函数声明 //学生信息录入函数 void Enter_stu(int *Num_Stu,char Stu_name[][50],int Stu_score[]); //查看学生信息 void Print_stu(int Num_Stu,char Stu_name[][50],int Stu_score[]); //求出成绩…

运维锅总详解进程、内核线程、用户态线程和协程

I/O 密集型应用、计算密集型应用应该用什么实现&#xff1f;进程、内核线程、用户态线程、协程它们的原理和应用场景又是什么&#xff1f;如何组合它们才能让机器性能达到最优&#xff1f;它们的死锁和竞态又是什么&#xff1f;如何清晰地表示它们之间的关系&#xff1f;希望读…

红日靶场----(三)2.漏洞利用

上期的通过一句话木马实现对目标主机的持久后门 我使用的是蚁剑&#xff0c;蚁剑安装及使用参考&#xff1a; 下载地址&#xff1a; GitHub - AntSwordProject/AntSword-Loader: AntSword 加载器 安装即使用&#xff1a; 1. 快速入门 语雀 通过YXCMS的后台GETSHELL 利用…

Dify工作流中的变量聚合节点

一.定义 变量聚合节点&#xff08;原变量赋值节点&#xff09;负责整合不同分支的输出结果&#xff0c;确保无论哪个分支被执行&#xff0c;其结果都能通过一个统一的变量来引用和访问。这在多分支的情况下非常有用&#xff0c;可将不同分支下相同作用的变量映射为一个输出变量…

剖析自闭症孩子玩手的独特之处

自闭症孩子玩手的行为常常具有一些较为独特的特点。 重复性是一个显著的特征。他们可能会以一种几乎相同的方式、节奏和频率反复地摆弄自己的手&#xff0c;例如不停地握拳、张开&#xff0c;或者持续地旋转手腕。 动作的单调性也是常见的。玩手的方式可能较为单一&#xff0c;…

力扣 24两两交换链表中节点

画图 注意有头结点 注意判断时先判断cur->next ! nullptr,再判断cur->next->next ! nullptr 注意末尾返回dumyhead->next&#xff0c;用新建result指针来接并返回 class Solution { public:ListNode* swapPairs(ListNode* head) {ListNode *dummyhead new List…

小技巧(更新中)

1.Pycharm使用小技巧pycharm的使用小技巧1---快速找到模块内的函数和类&#xff0c;快速定位查看的模块所在位置_pycharm怎么查找某个函数-CSDN博客 2. Python库之requirments Python库安装之requirements.txt, environment.yml_python requirements-CSDN博客 3.执行.sh脚本的…

vue中v-if与v-show的区别

在 Vue.js 中&#xff0c;v-if 和 v-show 都是用来控制元素显示与隐藏的指令&#xff0c;但它们之间有几个关键的区别&#xff1a; 直接上图 一. 条件渲染方式不同 v-if&#xff1a; 真正的条件渲染&#xff1a;v-if 指令会根据表达式的真假来销毁或重新创建 DOM 元素及其…

LeetCode 88.合并两个有序数组 C写法

LeetCode 88.合并两个有序数组 C写法 思路&#xff1a; ​ 由题nums1的长度为mn&#xff0c;则我们不需要开辟新的数组去存储元素。题目要求要有序合并&#xff0c;于是可以判断哪边数更大&#xff0c;将更大的数尾插在nums1中。 ​ 定义三个变量来控制下标&#xff0c;end1控…

AI绘画工具Stable Diffusion神级插件InstantID,AI换脸完美版!

随着AI绘画技术的不断迭代&#xff0c;AI换脸也日臻完美。 从路线上看&#xff0c;主要有两条路线&#xff0c;一是一张图换脸&#xff0c;优点是操作简便&#xff0c;缺点是换个姿势的时候&#xff0c;往往不太像&#xff0c;roop等插件是基于这个思路&#xff1b;二是炼制专…

UWB:FiRa Consortium UCI Generic Technical Specification v1.1.0(1)- UCI架构和通用数据包头

FiRa fine ranging 精确测距 为了UWB产业能够蓬勃发展&#xff0c;各个公司的产品必须互联互通&#xff0c;不然就是一盘散沙&#xff0c;成不了气候。于是成立了FiRa UWB联盟&#xff0c;相当于WiFi里面的WiFi alliance&#xff08;WiFi联盟&#xff09;&#xff0c;蓝牙里面…