Об авторе Феликс Ант Технологическая команда Financial Data Experience
Шаги в нашем повседневном использовании браузера: запустить браузер, открыть веб-страницу и взаимодействовать. а также无头浏览器
Относится к браузерам, сценарии которых мы используем для выполнения вышеуказанного процесса, который может имитировать реальные сценарии использования браузера.
С безголовым браузером мы можем делать такие вещи, как:
- Делайте скриншоты веб-страниц и сохраняйте их в виде изображений или PDF-файлов.
- Захватите выполнение и рендеринг одностраничного приложения (SPA) (решите проблему, заключающуюся в том, что традиционный сканер HTTP, сканирующий одностраничное приложение, с трудом обрабатывает асинхронные запросы)
- Выполняйте автоматическую отправку форм, автоматическое тестирование пользовательского интерфейса, имитацию ввода с клавиатуры и т. д.
- Используйте некоторые инструменты отладки и инструменты анализа производительности, которые поставляются с браузером, чтобы помочь нам проанализировать проблему.
- Протестируйте в новейшей среде безголового браузера и используйте новейшие функции браузера.
- Пишите сканеры, чтобы они делали то, что вы хотите~
Существует множество безголовых браузеров, включая, помимо прочего:
- PhantomJS, основанный на Webkit
- SlimerJS, основанный на Gecko
- HtmlUnit, основанный на Rhnio
- TrifleJS, основанный на Trident
- Splash, основанный на Webkit
В этой статье в основном представлен безголовый браузер (безголовый Chrome), предоставляемый Google, основанный наChrome DevTools protocolПредоставляет нам множество инкапсулированных интерфейсов для управления браузером.
простой пример кода
чтобы использовать
async
/await
и другие новые функции, вам необходимо использовать версию Node v7.6.0 или более позднюю.
Запустить/закрыть браузер, открыть страницу
// 启动浏览器
const browser = await puppeteer.launch({
// 关闭无头模式,方便我们看到这个无头浏览器执行的过程
// headless: false,
timeout: 30000, // 默认超时为30秒,设置为0则表示不设置超时
});
// 打开空白页面
const page = await browser.newPage();
// 进行交互
// ...
// 关闭浏览器
// await browser.close();
Установить размер окна страницы
// 设置浏览器视窗
page.setViewport({
width: 1376,
height: 768,
});
Введите URL
// 地址栏输入网页地址
await page.goto('https://google.com/', {
// 配置项
// waitUntil: 'networkidle', // 等待网络状态为空闲的时候才继续执行
});
Сохранить веб-страницу как изображение
Откройте веб-страницу и сохраните скриншот локально:
await page.screenshot({
path: 'path/to/saved.png',
});
сохранить веб-страницу в формате pdf
Откройте веб-страницу и сохраните PDF-файл локально:
await page.pdf({
path: 'path/to/saved.pdf',
format: 'A4', // 保存尺寸
});
выполнить скрипт
Чтобы получить среду хостинга на открытой веб-странице, мы можем использоватьPage.evaluate
метод:
// 获取视窗信息
const dimensions = await page.evaluate(() => {
return {
width: document.documentElement.clientWidth,
height: document.documentElement.clientHeight,
deviceScaleFactor: window.devicePixelRatio
};
});
console.log('视窗信息:', dimensions);
// 获取 html
// 获取上下文句柄
const htmlHandle = await page.$('html');
// 执行计算
const html = await page.evaluate(body => body.outerHTML, htmlHandle);
// 销毁句柄
await htmlHandle.dispose();
console.log('html:', html);
Page.$
Можно понимать как наше обычно используемоеdocument.querySelector
, а такжеPage.?
соответствуетdocument.querySelectorAll
.
Отправить форму автоматически
Откройте главную страницу Google, введите ключевое слово и нажмите Enter для поиска:
// 地址栏输入网页地址
await page.goto('https://google.com/', {
waitUntil: 'networkidle', // 等待网络状态为空闲的时候才继续执行
});
// 聚焦搜索框
// await page.click('#lst-ib');
await page.focus('#lst-ib');
// 输入搜索关键字
await page.type('辣子鸡', {
delay: 1000, // 控制 keypress 也就是每个字母输入的间隔
});
// 回车
await page.press('Enter');
Пример сложного кода
Каждое простое действие связано с серией сложных взаимодействий Давайте рассмотрим еще два конкретных примера.
Сканирование одностраничного приложения: имитация заказа на вынос Ele.me
Традиционный сканер основан на протоколе HTTP, имитирующем UserAgent для отправки http-запроса и использующем регулярный синтаксический анализ для получения содержимого для сканирования после получения содержимого html.
Но при столкновении с одностраничным приложением (SPA) или проверке входа в систему этот тип сканера относительно бессилен.
В безголовом браузере операция взаимодействия человека с компьютером полностью используется при сканировании веб-страниц, поэтому инициализация страницы может быть полностью выполнена с использованием среды хост-браузера, и нет необходимости заботиться о том, что должно быть задействовано в интерфейсная инициализация этого одностраничного приложения HTTP-запрос.
Различные клики, ввод и другие инструкции, предоставляемые безголовым браузером, полностью имитируют человеческие клики, ввод и другие инструкции, поэтому не нужно беспокоиться об обычном письме.
Конечно, в некоторых сценариях эффективнее использовать традиционные поисковые роботы HTTP (записывающие обычные совпадения).
Я не буду здесь подробно сравнивать эти различия.Следующий пример используется только в качестве демонстрации для имитации полного взаимодействия человека с компьютером: использование мобильной версии Ele.me для заказа еды на вынос.
Сначала посмотрите на эффект:
Код длинный и не весь выложен, ключ в несколько строк:
const puppeteer = require('puppeteer');
const devices = require('puppeteer/DeviceDescriptors');
const iPhone6 = devices['iPhone 6'];
console.log('启动浏览器');
const browser = await puppeteer.launch();
console.log('打开页面');
const page = await browser.newPage();
// 模拟移动端设备
await page.emulate(iPhone6);
console.log('地址栏输入网页地址');
await page.goto(url);
console.log('等待页面准备好');
await page.waitForSelector('.search-wrapper .search');
console.log('点击搜索框');
await page.tap('.search-wrapper .search');
await page.type('麦当劳', {
delay: 200, // 每个字母之间输入的间隔
});
console.log('回车开始搜索');
await page.tap('button');
console.log('等待搜素结果渲染出来');
await page.waitForSelector('[class^="index-container"]');
console.log('找到搜索到的第一家外卖店!');
await page.tap('[class^="index-container"]');
console.log('等待菜单渲染出来');
await page.waitForSelector('[class^="fooddetails-food-panel"]');
console.log('直接选一个菜品吧');
await page.tap('[class^="fooddetails-cart-button"]');
// console.log('===为了看清楚,傲娇地等两秒===');
await page.waitFor(2000);
await page.tap('[class^=submit-btn-submitbutton]');
// 关闭浏览器
await browser.close();
Ключевые шаги:
- загрузить страницу
- Подождите, пока DOM будет нажат, чтобы отобразиться, и нажмите
- Продолжайте ждать, пока DOM, который нужно щелкнуть, будет отображен на следующем шаге, а затем нажмите
Несколько ключевых команд:
-
page.tap
(илиpage.click
) за клики -
page.waitForSelector
Это означает ожидание появления указанного элемента на веб-странице.Если он уже появился, он немедленно продолжит выполнение.Следующие параметры:selector
селектор, такой же, как наш обычно используемыйdocument.querySelector
Полученные параметры совпадают -
page.waitFor
можно сдать позжеselector
Селектор,function
функция илиtimeout
Миллисекантное время, напримерpage.waitFor(2000)
Относится к ожиданию в течение 2 секунд перед продолжением выполнения. В примере эта функция используется для приостановки операции в основном для демонстрации.
Все вышеперечисленные команды могут принимать одинselector
Селектор используется как параметр, и вот несколько дополнительных методов:
-
page.$(selector)
с нашим обычнымdocument.querySelector(selector)
Непротиворечивый, возвращаетElementHandle
дескриптор элемента -
page.?(selector)
с нашим обычнымdocument.querySelectorAll(selector)
Согласован, возвращает массив
В контексте браузера с заголовком мы выбираем элемент следующим образом:
const body = document.querySelector('body');
const bodyInnerHTML = body.innerHTML;
console.log('bodyInnerHTML: ', bodyInnerHTML);
В безголовом браузере нам сначала нужно получить дескриптор, а после получения информации в среде через дескриптор уничтожить дескриптор.
// 获取 html
// 获取上下文句柄
const bodyHandle = await page.$('body');
// 执行计算
const bodyInnerHTML = await page.evaluate(dom => dom.innerHTML, bodyHandle);
// 销毁句柄
await bodyHandle.dispose();
console.log('bodyInnerHTML:', bodyInnerHTML);
Кроме того, вы также можете использоватьpage.$eval
:
const bodyInnerHTML = await page.$eval('body', dom => dom.innerHTML);
console.log('bodyInnerHTML: ', bodyInnerHTML);
page.evaluate
Это означает, что для выполнения скрипта в среде браузера вы можете передать второй параметр как дескриптор, иpage.$eval
Затем выполните операцию с выбранным элементом DOM.
Массовый экспорт веб-страниц: загрузка книг Тьюринга
я здесьСообщество ТьюрингаЯ купил много электронных книг наmobi
отформатировать вkindle
или нажатьpdf
Формат отправляется в почтовый ящик для чтения, но эти push-каналы часто закрыты, и их можно оставить на веб-странице только для чтения.
Для меня не очень удобно, и онлайн-эффект чтения этих книг - это рендеринг сервера (с большой меткой, не в состоянии выбрать хорошую версию типографии), лучший способ, конечно, непосредственно читать и сохранять в PDF или картинки.
Используя безголовый режим браузера, я написал простую загрузку купленных книг какpdf
В локальном скрипте поддерживается пакетная загрузка купленных книг.
Используйте метод, введите пароль учетной записи и сохраните путь, например:
$ node ./demo/download-ituring-books.js '用户名' '密码' './books'
Уведомление:puppeteer
изPage.pdf()
В настоящее время поддерживается только использование в безголовом режиме, поэтому, если вы хотите увидеть процесс захвата с состоянием головы, выполните дляPage.pdf()
Этот шаг сначала сообщит об ошибке:
Поэтому при запуске этого скрипта он должен оставаться в безголовом режиме:
const browser = await puppeteer.launch({
// 关闭无头模式,方便我们看到这个无头浏览器执行的过程
// 注意若调用了 Page.pdf 即保存为 pdf,则需要保持为无头模式
// headless: false,
});
Взгляните на эффект исполнения:
На моей книжной полке более 20 книг, после скачивания она выглядит так:
Что еще может безголовый браузер?
Проще говоря, безголовый браузер может имитировать различные действия людей в безголовом браузере. Естественно, много ручной работы можно выполнить с помощью безголового браузера (например, в процессе загрузки pdf выше на самом деле человек открывает каждую страницу статьи, а затем нажимаетctrl+p
илиcommand+p
сохранить в локальный автоматизированный процесс).
Поскольку то, что можно решить с помощью автоматизированных средств, не требует повторного человеческого труда, кроме того, мы также можем:
- инструмент автоматизации Например, автоматическая отправка формы, автоматическая загрузка
- Автоматизируйте тестирование пользовательского интерфейса Если вы записываете правильную структуру DOM или снимок экрана, а затем автоматически выполняете указанную операцию, проверьте соответствие структуры DOM или снимка экрана (утверждение пользовательского интерфейса).
- инструмент контроля времени Например, регулярно делайте снимки экрана, чтобы отправлять еженедельные отчеты, или регулярно проверяйте, доступны ли страницы важных бизнес-направлений, и сотрудничайте с оповещениями по электронной почте.
- рептилия Например, там, где традиционные сканеры HTTP не могут сканировать, это можно сделать с помощью возможностей рендеринга безголовых браузеров.
- etc
Заинтересованные студенты могут подписаться на колонку или отправить свое резюме на qingsheng.lqs####alibaba-inc.com'.replace('####', '@'). Приглашаются люди с высокими идеалами~
Оригинальный адрес:GitHub.com/proto team/no…