1. 爬虫与playwright
网页爬虫并不是一个新概念。在JavaScript
生态系统中,Cheerio
、Selenium
、Puppeteer
和Playwright
等工具都帮助简化了网页爬虫的过程。作为一个较新的网页爬虫库,Playwright
具有以下几个吸引人的特点:
1.1 强大的定位器(Locators)
Playwright
使用定位器来选择网页上的元素,这些定位器具有内置的自动等待和重试逻辑。自动等待逻辑简化了您的爬虫代码,因为您不必手动等待网页加载完成。
此外,重试逻辑使Playwright
成为抓取现代单页应用 (SPA)
的理想库,这些应用在初始页面加载后会动态加载数据。
示例代码:
const { chromium }=require('playwright');
(async ()=>{
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
// 使用定位器选择元素
const element = await page.locator('text="Example Domain"').first();
console.log(await element.textContent());
await browser.close();
})();
1.2 多种定位器方法
使用定位器时,Playwright
允许您使用多种不同的语法来指定要在网页上定位的元素,包括CSS
选择器语法、XPath
语法和元素文本内容。还可以对定位器应用过滤器,以进一步细化定位器的范围。
示例代码:
// CSS选择器
const cssLocator = page.locator('div.classname');
// XPath语法
const xpathLocator = page.locator('//div[@class="classname"]');
// 元素文本内容
const textLocator = page.locator('text="Example Domain"');
// 过滤器
const filteredLocator = page.locator('div.classname').filter({ hasText: 'specific text' });
1.3 Playwright的其他优势
自动处理等待
Playwright
内置的智能等待机制可以自动处理网络延迟和动态内容加载问题,使爬虫代码更加简洁和可靠。
跨浏览器支持
Playwright
支持在多个浏览器(如Chromium
、Firefox
和WebKit
)上运行,从而确保爬取的数据具有一致性。
无头模式
Playwright
可以在无头模式下运行,减少资源消耗,提高爬取效率。
2. 使用Playwright进行网页爬虫
下面将创建一个Node.js
项目,安装Playwright
,并学习如何使用Playwright
定位、交互和提取网页数据。
2.1 前置条件
本文中的代码示例在最新的长期支持版本(LTS)
的Node.js
上运行,截至撰写本文时,该版本为v18.15.0
。请确保在开始之前已安装Node.js
。
推荐使用能够突出显示JavaScript
语法并具备自动完成功能的代码编辑器,例如Visual Studio Code
。
2.2 创建一个新项目
打开一个新的终端窗口,为Node.js
项目创建一个新文件夹并进入该文件夹:
mkdir playwright-demo
cd playwright-demo
接下来,通过运行以下npm命令创建的Node.js
项目:
npm init -y
2.3 安装Playwright
创建Node.js
项目后,在终端窗口中使用以下命令安装Playwright
库:
npm install playwright
该库可能需要一些时间来安装,因为Playwright在安装过程中会下载必要的浏览器。
2.4 打开主页
安装Playwright
库后,在项目文件夹中创建一个名为index.js
的新文件。然后将以下代码复制到其中:
const playwright =require("playwright");
(async ()=>{
const browser = await playwright.chromium.launch({
headless:false,
});
const context = await browser.newContext();
const page = await context.newPage();
await page.goto("https://brightdata.com/");
await page.waitForTimeout(10000);
await browser.close();
})();
使用以下命令在终端中运行代码片段:
node index.js
应该会打开一个Chromium
浏览器并加载Bright Data
主页。
2.5 定位元素
现在已经使用Playwright
导航到Bright Data
的主页,可以使用定位器来选择网页上的特定元素。Playwright
有多种定位器,以下部分将演示每种定位器的工作原理。
使用CSS选择器定位元素
Playwright
允许您使用CSS选择器在网页上定位元素,这是一种在CSS
中用于应用样式到特定HTML
元素的简洁而强大的语法。
例如,Bright Data
的徽标是页面头部的一个<svg>
元素,并且附加了page_header_logo_svg
类:
const logoSvg = page.locator(".page_header_logo_svg");
使用XPath
查询定位元素
XPath
是另一种可以用来定位XML
文档中元素的选择器语法。由于HTML
是XML
,可以使用该语法在网页上查找HTML
元素。
例如,可以使用以下XPath
查询选择与上一节中相同的SVG徽标:
const logoSvg = page.locator("//*[@class='page_header_logo_svg']");
按角色定位元素
HTML
元素可以具有不同的角色,这些角色为网页提供语义意义,使屏幕阅读器和其他工具更容易支持该网页。您可以阅读更多关于角色的信息这里。
以下代码片段演示了如何使用角色和名称找到Start free trial
按钮:
const signupButton = page.getByRole("button", {
name: "Start free trial",
});
按文本定位元素
如果HTML
元素没有有意义的标识符属性,例如id
或class
属性,可以使用getByText
方法按文本选择元素。
例如,Bright Data
主页的英雄部分有一个标题,其中包含蓝色的structured data
字样:
const structuredData = page.getByText("structured data");
按标签定位元素
在HTML
表单中,输入元素通常有标签。Playwright
可以使用这些标签来识别与该标签关联的输入元素,使用getByLabel
方法。
例如,Bright Data
登录页面有一个包含Work email
字样的输入元素:
await page.goto("https://brightdata.com/cp/start");
const emailInput = page.getByLabel("Work email");
按占位符定位元素
还可以根据显示的占位符值定位输入元素,使用getByPlaceholder
方法。
await page.goto("https://brightdata.com/cp/start");
const emailInput = page.getByPlaceholder("[email protected]");
按alt
文本定位元素
HTML
允许使用alt
属性为图像添加文本描述,如果图片未加载,该描述会显示出来,并由屏幕阅读器读取以描述图像。Playwright
的getByAltText
方法允许使用alt
属性定位img
元素。
例如,Bright Data
列出了使用其数据的行业。可以使用alt
值healthcare use case
检索用于医疗行业的图像:
const healthcareImage = page.getByAltText("healthcare use case");
按标题定位元素
最后一个Playwright
选择器是getByTitle
方法,它通过title
属性定位HTML元素。当用指针悬停在HTML
组件上时,会看到title
值。 例如,Bright Data
帮助台网站包含一个具有title
属性的登录链接:
await page.goto("https://help.brightdata.com/hc/en-us");
const signInLink = page.getByTitle("Opens a dialog");
2.6 与元素交互
定位网页上的元素后,可以与之交互。例如,可能需要登录网站才能抓取受保护的页面。
以下代码片段演示了不同的Playwright
方法来与网页上的元素交互。代码中的每个函数都有相应的解释:
const playwright =require("playwright");
(async ()=>{
const browser = await playwright.chromium.launch({
headless:false,
});
const context = await browser.newContext();
const page = await context.newPage();
await page.goto("https://brightdata.com/");
await page.locator("#hero_new").getByRole("button",{ name:"Start free trial"}).click();
await page.locator(".hs_firstname input").fill("John");
await page.locator(".hs_lastname input").fill("Smith");
await page.locator(".hs_email input").type("[email protected]");
await page.locator(".hs_numemployees select").selectOption("1-9 employees");
await page.locator(".legal-consent-container input").check();
await page.waitForTimeout(10000);
await browser.close();
})();
点击元素
在上面的代码片段中,Playwright
首先点击了Start free trial
按钮,以便显示对话框:
await page.getByRole("button", { name: "Start free trial" }).click();
填充文本字段
示例中,代码片段使用两种方法填充注册表单上的文本字段:
await page.locator(".hs_firstname input").fill("John");
await page.locator(".hs_lastname input").fill("Smith");
await page.locator(".hs_email input").type("[email protected]");
选择下拉选项
注册表单有一个下拉字段,用于选择公司规模,Playwright
将其填充为1–9 employees
:
await page.locator(".hs_numemployees select").selectOption("1-9 employees");
勾选复选框和单选按钮
在提交表单之前,您需要接受条款和条件。以下代码片段选中了相应的复选框:
await page.locator(".legal-consent-container input").check();
从元素中提取数据
数据提取是网页爬虫的关键。Playwright
允许您使用多种方法从定位到的元素中检索不同类型的数据。以下部分介绍了其中的一些方法。
提取内部文本
innerText
方法允许您提取元素内部的文本。例如,Bright Data
有一个标题:
const headerText = await page.locator(".brd_hero__title.h1").innerText();
提取内部HTML
Playwright
还允许您使用innerHTML方法提取元素的内部HTML
。例如,可以获取Bright Data
页脚的HTML
:
const footerHtml = await page.locator("#footer").innerHTML();
提取属性值
可能需要从HTML
元素的属性中提取数据,例如链接的href
属性。以下Playwright
代码片段演示了如何抓取登录链接的href
属性:
const signUpHref = await page.getByText("Log in").getAttribute("href");
截图页面
在抓取数据时,可能需要截取屏幕截图以进行审核。可以使用
screenshot`方法来执行此操作。该函数允许配置多个选项,例如保存截图文件的位置以及是否截取整个页面的截图。
以下代码片段截取了Bright Data
全页面截图并保存:
await page.screenshot({
path: "homepage.png",
fullPage: true,
});
通过上述步骤和示例,可以使用Playwright
有效地进行网页爬虫,定位和提取网页上的数据。
小结论
详细介绍了如何使用Playwright
进行网页爬虫,包括环境配置、编写脚本、元素交互,元素内容提取等。Playwright强大的功能和灵活的API,使其成为网页爬虫的理想工具,帮助你高效地从网页中提取所需数据,提升数据采集的效率和质量。
Python到TypeScript的快速入门
对于熟悉Python的
测试人员和开发人员来说,初次学习使用TypeScript
可能并不需要花费太多时间
3. TypeScript
语法基础
3.1 变量和类型
在Python
中,变量声明是动态的,而在TypeScript
中,我们需要显式声明变量类型。
Python
:
name = "Alice"
age = 30
TypeScript
:
let name: string = "Alice";
let age: number = 30;
3.2 异步代码
在Python
中,我们使用async
和await
来处理异步代码,TypeScript
中也是如此。
Python
:
async def fetch_data():
data = await fetch('https://api.example.com')
return data
TypeScript
:
async function fetchData(): Promise<any> {
const response = await fetch('https://api.example.com');
const data = await response.json();
return data;
}
3.3 类和函数
TypeScript
与Python
类似,支持面向对象编程。
Python
:
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
return f"{self.name} says hello!"
dog = Animal("Dog")
print(dog.speak())
TypeScript
:
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
speak(): string {
return `${this.name} says hello!`;
}
}
const dog = new Animal("Dog");
console.log(dog.speak());
4. Playwright
入门
4.1 Playwright
安装配置
在项目中安装 ·Playwright· 后,创建一个新的测试文件 test.ts
。
4.2 基本语法
import { chromium, Browser, Page } from 'playwright';
(async () => {
const browser: Browser = await chromium.launch({ headless: false });
const page: Page = await browser.newPage();
await page.goto('https://example.com');
const title: string = await page.title();
console.log(`页面标题是: ${title}`);
await browser.close();
})();
4.3 运行测试脚本
在终端中运行以下命令编译并执行 TypeScript
脚本:
npx ts-node test.ts
5. Playwright
进阶
5.1 Hooks
钩子
Playwright
提供了钩子函数,可以在测试执行的不同阶段执行特定操作。常见的钩子函数有
beforeAll()
在所有的test()
执行之前运行1次,且只运行1次。
beforeEach()
在每一个test()
执行之前运行1次,运行总次数取决于多少个test()
。
afterAll()
在所有的test()
执行之后运行1次,且只运行1次。
afterEach()
在每一个test()
执行之后运行1次,运行总次数取决于多少个test()
。
示例如下:
import { chromium, Browser, Page } from 'playwright';
let browser: Browser;
let page: Page;
beforeAll(async () => {
browser = await chromium.launch();
page = await browser.newPage();
});
afterAll(async () => {
await browser.close();
});
beforeEach(async () => {
await page.goto('https://example.com');
});
afterEach(async () => {
// 清理代码
});
5.2 断言(Assertions)
使用 Playwright
的内置断言库,可以方便地验证测试结果,这部分对于使用Python
还是Typescript
来说区别并不大。示例如下
import { test, expect } from '@playwright/test';
test('has title', async ({ page }) => {
await page.goto('https://example.com');
await expect(page).toHaveTitle('Example Domain');
});
test('get started link', async ({ page }) => {
await page.goto('https://playwright.dev/');
const getStarted = page.locator('text=Get Started');
await expect(getStarted).toHaveAttribute('href', '/docs/intro');
});
总结
通过这篇教程,相信你对 TypeScript
的基本语法有了一个初步了解,结合Playwright
提供的钩子和断言,完全可以开始自动化测试脚本编写。进阶和高级的Playwright
用法可以参考官网