Памятка по синтаксису JavaScript
для Node.js в примерах.
Навигация:
- Переменные
- Типы данных
- Функции
- Условия
- Обработка ошибок
- Массивы
- Объекты
- Циклы
- Асинхронные операции
- Регулярные выражения
- Математические вычисления
- Express
- Axios
- Fetch
- Cheerio
- Puppeteer
Переменная var
поддерживает любую область видимости и ее возможно объявить повторно (считается устаревшим методом и рекомендуется не использовать).
console.log(varVariable) // Uncaught ReferenceError: varVariable is not defined (не определена)
if (true) {
var varVariable = true
}
console.log(varVariable) // true
var varVariable = 123
console.log(varVariable) // 123
Переменная let
позволяет изменять содержимое с другим типом данных (в отличии от const
), но ограничина областью видимости (в отличии от var
).
console.log(letVariable) // Uncaught ReferenceError: letVariable is not defined
if (true) {
let letVariable = 'letVariable is defined'
}
console.log(letVariable) // Uncaught ReferenceError: letVariable is not defined
let letVariable = 'string'
console.log(letVariable)
let letVariable = 'string' // Uncaught SyntaxError: Identifier 'letVariable' has already been declared (идентификатор уже объявлен)
letVariable = 123
console.log(letVariable)
Переменная константа const
требует обязательной инициализации во время объявления, и не позволяет изменять значение переменной после ее объявления.
const constVariable = 'string'
constVariable = '123' // Uncaught TypeError: Assignment to constant variable (ошибка присвоения значения к постоянной переменной)
typeof 32 // number
typeof 3.2 // number
typeof 123n // bigint
typeof 'text' // string
typeof true // boolean
typeof false // boolean
typeof null // object
typeof { key: 'value' } // object
typeof [1, 2, 3] // object
typeof function() {} // function
typeof Symbol('id') // symbol
Преобразовать аргумент в число. Возвращает NaN
, если преобразование невозможно.
Number("123") // 123
Number("123.45") // 123.45
Number("abc") // NaN
Number(undefined) // NaN
Number(true) // 1
Number(false) // 0
Number(null) // 0
Преобразовать строку в целое число. Прекращает чтение, как только встречает нецифровой символ.
parseInt("123abc") // 123
parseInt("12.34") // 12
parseInt("abc123") // NaN
Преобразовать строку в число с плавающей точкой.
parseFloat("123.45abc") // 123.45
parseFloat("abc123.45") // NaN
Преобразовать значение в строку.
(123).toString() // "123"
(true).toString() // "true"
String(123) // "123"
String(true) // "true"
String(false) // "false"
String(null) // "null"
String(undefined) // "undefined"
Преобразовать значение в булевое (логическое) значение. Все значения, кроме 0
, null
, NaN
, undefined
и пустой строки, преобразуются в true
.
Boolean(123) // true
Boolean("Hello") // true
Boolean(0) // false
!0 // true
!!0 // false
Boolean(null) // false
Boolean(NaN) // false
Boolean(undefined) // false
Boolean("") // false
function sum (param1, param2) {
console.log(param1*param2)
}
sum(2,2) // 4
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min
}
getRandomInt(1,100) // Например, 44
function functionName (paramName) {
if (paramName === 0) {
console.log(`${paramName} равно 0`)
}
else if (paramName < 10) {
console.log(`${paramName} меньше 10`)
}
else if (paramName >= 10) {
console.log(`${paramName} больше или равно 10`)
}
else {
console.log(`Переданное значение - ${paramName} - не подходит под заданные условия`)
}
}
functionName(0) // 0 равно 0
functionName(5) // 5 меньше 10
functionName(15) // 15 больше или равно 10
functionName('test') // Переданное значение - test - не подходит под заданные условия
Однострочный формат условия ?:
, который подходит для использования в теле переменной
let input = 1
input === 1 ? true : false // true
input = 2
input === 1 ? true : false // false
Проверить одно значение сразу на большое количество условий с помощью конструкции switch
function getDayOfWeek(day) {
switch (day) {
case 1:
return 'Понедельник'
case 2:
return 'Вторник'
case 3:
return 'Среда'
case 4:
return 'Четверг'
case 5:
return 'Пятница'
case 6:
return 'Суббота'
case 7:
return 'Воскресенье'
default:
return 'Неправильно задан параметр'
}
}
console.log(getDayOfWeek(1)) // Понедельник
console.log(getDayOfWeek(5)) // Пятница
console.log(getDayOfWeek(7)) // Воскресенье
console.log(getDayOfWeek(8)) // Неправильно задан параметр
function errorTest(a, b) {
// Блок кода, который будет выполняется до тех пор, пока не возникнет ошибка
try {
if (b === 0) {
throw new Error("на ноль делить нельзя")
}
console.log(a / b) // выполняется, если ошибок нет
}
// Блок кода, который будет выполнен, если в блоке try возникнет ошибка
catch (error) {
console.log(`Ошибка: ${error.message}`) // Обработка ошибки
}
// Блок кода, который выполняется в любом случае
finally {
console.log("Блок finally выполняется всегда") // Всегда выполняется
}
}
errorTest(10, 2)
// 5
// Блок finally выполняется всегда
errorTest(10, 0)
// Ошибка: на ноль делить нельзя
// Блок finally выполняется всегда
Классический массив и его методы.
const array = [3, 2, 'string']
Array.isArray(array) // Проверка, является ли переменная массивом (true)
array[2] = 1 // Изменить содержимое элемента в массиве по индексу
array.sort() // сортировка по умолчанию: [ 1, 2, 3 ]
array.reverse() // Поменять порядок следования: [ 3, 2, 1 ]
array[0] + array[1] + array[2] // 6
array[3] // undefined (не определено)
array[3] = 4 // Добавить новый элемент в массив по индексу
array.push(5) // Добавить новый элемент с конца
array[4] // 5
array.slice(3,5) // Вывести содержимое массива с 4-го по 5-й индекс: [ 4, 5 ]
array.unshift(0) // Добавить элемент(ы) (через запятую) в начало массива
array.shift() // Удалить первый элемент из массива
array.pop() // Удалить последний элемент из массива
array[array.length-1] // Вывести содержимое последнего элемента в массиве
array.indexOf(1) // Выводит индекс первого вхождения элемента в массив, или -1, если элемент не найден
Вложенный массив, а также методы фильтрации и объединения:
const data = [
{ id: 1, name: 'red' },
{ id: 2, name: 'blue' },
]
data.push({id: 3, name: 'green'}) // Добавить новый элемент в массив
const nameArray = data.map(item => item.name) // Пересобрать новый массив
const filterArray = nameArray.filter(item => item.length >= 4) // отфильтровать содержимое массива по длинне содержимого
// [ 'blue', 'green' ]
[...nameArray, ...filterArray] // объеденить два массива
// [ 'red', 'blue', 'green', 'blue', 'green' ]
const idArray = data.map(item => item.id)
// Метод reduce выполняет функцию для каждого элемента массива, чтобы получить одно итоговое значение (сумму)
idArray.reduce((accumulator, current) => accumulator + current, 0) // 3
Преобразовать объект в массив и наоборот:
const obj = { a: 1, b: 2, c: 3 }
obj.b // 2
let keys = Object.keys(obj) // [ 'a', 'b', 'c' ]
let values = Object.values(obj) // [ 1, 2, 3 ]
const arr = Object.entries(obj) // [["a", 1], ["b", 2], ["c", 3]]
arr[1][1] // 2
Object.fromEntries(arr) // { a: 1, b: 2, c: 3 }
Объект представляет из себя список пар (ключ-значение), разделенного запятыми. Используя переменную const
при объявлении объектов, возможно изменять содержимое дочерних элементов.
const box = {
height: 8,
width: 40,
scrollable: true,
style: {
fg: 'white',
bg: 'black'
}
}
box.height // 8
box.style // { fg: 'white', bg: 'black' }
box.style.fg // white
box.style.fg = 'blue'
box.style.fg // blue
Объекты и вложенные массивы JavaScript
могут содержать дочерние массивы внутри []
и вложенные объекты внутри {}
.
const obj = [
'JavaScript',
2024,
[
'Express',
'Axios',
],
{
name: 'Alex',
age: 29,
num: [1, 'string', {}],
test: {}
}
]
Конвертация в JSON
:
const jsonString = JSON.stringify(obj) // Конвертация из объекта JavaScript в JSON
const obj = JSON.parse(jsonString) // Конвертация из JSON в JavaScript
Методы объекта назначаются через функции
const obj = {
default: 10,
get() {
return this.default
},
plus(num) {
if (isNaN(num)) {return}
this.default += num
},
minus(num) {
if (isNaN(num)) {return}
this.default -= num
}
}
obj.minus(1)
obj.get() // 9
obj.plus(2)
obj.get() // 11
Оператор return
используется для выхода из функции (т.е. последующий код не читается), который возвращает значение указанное после ключевого слова.
Примеры циклов взяты из проекта multranslate, для проверки всех строк в массиве и увеличения количества видимых строк с учетом autowrap
. Имеется две реальных строки, необходимо узнать количество виртуальных строк с учетом длинны символов в строке. Например, если максимальная длинна одной строки составляет, 36
, то на одну реальную строку в 92
символа приходится дополнительно еще 2
виртуальных. Количество найденных виртуальных строк прибавляется к изначально зафиксированному значению количества всех реальных строк.
// На входе 2 строки, разделенные символом \r
const text = "Первая строка\rВторая очень длинная строка, которое будет превышать максимальное значение символов в строке"
// Фиксируем текущее максимальное количество строк и длинну символов в строке с учетом размеров окна
const maxLines = box.height - 2 // 6
const maxChars = box.width - 4 // 36
// Разбиваем текст на массив из строк
const bufferLine = text.split('\r')
// Забираем реальное количество строк (2)
let viewLines = bufferLine.length
// Вывести количество строк в каждой строке массива
bufferLine.map(item => item.length) // [ 13, 92 ]
Классический цикл for
итерирует числами с типом данных number
(int
/ integer
). С каждой интерацией объявленное значение (let i = 0
) увеличивается на заданное количество (i++
- на единицу), цикл завершается в случае успешного соблюдения условия (i < bufferLine.length
).
for (let i = 0; i < bufferLine.length; i++) {
if (bufferLine[i].length > maxChars) {
// Добавляем одну виртуальную строку без учета остатка символов
viewLines++
}
}
console.log(`${maxLines} ${maxChars} ${viewLines}`) // 6 36 3
// Уменьшаем значение на 1, для проверки в других циклах
viewLines--
for (let i = 0; i < bufferLine.length; i++) {
if (bufferLine[i].length > maxChars) {
// Добавляем все виртуальные строки, с округлением в меньшую сторону
viewLines += Math.floor(bufferLine[1].length / maxChars)
}
}
console.log(`${maxLines} ${maxChars} ${viewLines}`) // 6 36 4
viewLines -= 2
Цикл for..in
итерирует по индексам массива, с типом данных string
. Сколько элементов в массиве (bufferLine.length
), столько и будет индексов (отсчет начинается с нуля).
for (let index in bufferLine) {
if (bufferLine[Number(index)].length > maxChars) {
viewLines += Math.floor(bufferLine[1].length / maxChars)
}
}
console.log(`${maxLines} ${maxChars} ${viewLines}`) // 6 36 4
viewLines -= 2
Цикл for..of
итерирует по элементам массива, с уникальным типом данных каждого элемента в массиве.
const array = [1, 'string', {}]
for (let arr of array) {
console.log(typeof arr)
}
// number
// string
// object
for (let line of bufferLine) {
console.log(typeof line)
if (line.length > maxChars) {
viewLines += Math.floor(bufferLine[1].length / maxChars)
}
}
console.log(`${maxLines} ${maxChars} ${viewLines}`) // 6 36 4
viewLines -= 2
Метод массива forEach
выполняет указанную функцию для каждого элемента в массиве.
bufferLine.forEach(line => {
if (line.length > maxChars) {
viewLines += Math.floor(bufferLine[1].length / maxChars)
}
})
console.log(`${maxLines} ${maxChars} ${viewLines}`) // 6 36 4
viewLines -= 2
Цикл while
Выполняет тело цикла {}
до тех пор, пока условие истинно
let i = 0
while (i < bufferLine.length) {
if (bufferLine[i].length > maxChars) {
viewLines += Math.floor(bufferLine[1].length / maxChars)
}
i++
}
console.log(`${maxLines} ${maxChars} ${viewLines}`) // 6 36 4
viewLines -= 2
Цикл do..while
сначала выполняет тело цикла, а затем проверяет условие, это гарантирует, что интерация будет выполнена как минимум один раз.
i = 0
do {
if (bufferLine[i].length > maxChars) {
viewLines += Math.floor(bufferLine[1].length / maxChars)
}
i++
} while (i < bufferLine.length)
console.log(`${maxLines} ${maxChars} ${viewLines}`) // 6 36 4
Операторы:
continue
- прерывает текущую интерацию, для продолжения цикла с следующим значениемbreak
- прерывает и завершает цикл
let arr = [0, 1, 2, 4]
for (const value of arr) {
console.log(`Начало ${value}-й итерации`)
if (value === 1) {
console.log('Пропустить оставшуюся часть кода и перейти к следующей итерации')
continue
} else if (value === 2) {
console.log('Полностью выйти из цикла')
break
}
console.log(`Конец ${value}-й итерации`)
}
// Начало 0-й итерации
// Конец 0-й итерации
// Начало 1-й итерации
// Пропустить оставшуюся часть кода и перейти к следующей итерации
// Начало 2-й итерации
// Полностью выйти из цикла
Promise
(промис) — это объект, который используется для обработки асинхронных операций, позволяя работать с результатами, когда они станут доступны, не блокируя основной поток выполнения. Он может находиться в одном из трех состояний:
Pending
(Ожидание): Операция только отправлена на выполнение или еще выполняется.Fulfilled
(Выполнен): Операция завершилась успешно.Rejected
(Отклонен): Операция завершилась с ошибкой.
С помощью ключевых слов resolve
(разрешить/успех) и reject
(отклонить/ошибка) производится управление возвращаемым результатом выполнения.
let testPromise = new Promise((resolve, reject) => {
if (true) {
resolve("Операция выполнена успешно")
} else {
reject("Ошибка выполнения операции")
}
})
testPromise.then(result => console.log(result)).catch(error => console.error(error))
Метод then
используется для обработки успешного выполнения промиса (в состоянии fulfilled
).
Метод catch
используется для обработки ошибок или отказов промиса (в состоянии rejected
).
async
— это ключевое слово, которое делает функцию асинхронной и позволяет использовать await
, чтобы приостановить выполнение до тех пор, пока все промисы не будут выполнены.
await
— это ключевое слово, которое используется внутри асинхронной функции (async). Оно заставляет ждать выполнения промиса и возвращает его результат.
// Импортируем функцию exec из модуля child_process, которая позволяет запускать команды операционной системы
const { exec } = require('child_process')
// Основная функция выполнения команды ping в промис
function pingHost(host) {
return new Promise((resolve) => {
// Выполняем команду ping для указанного хоста с timeout 50 мс
exec(`ping -n 1 -w 50 ${host}`, (error) => {
// Если нет ошибки, значит хост отвечает (alive: true)
if (!error) {
resolve({ host, alive: true })
}
// Если есть ошибка, хост не отвечает (alive: false)
else {
resolve({ host, alive: false })
}
})
})
}
// Асинхронная функция создания промисов и получения результатов
async function pingSubnet(subnet) {
// Массив для хранения промисов
const promises = []
// Генерация и пинг каждого IP-адреса в диапазоне от 1 до 254
for (let i = 1; i <= 254; i++) {
// Формируем IP-адрес, заменяя последний октет подсети
const host = `${subnet.split('.').slice(0,3).join('.')}.${i}`
// Добавляем промис в массив для выполнения пинга в фоне и продолжения интерации
promises.push(pingHost(host)) // Promise { <pending> }
}
// Ждем завершения выполнения всех промисов
const results = await Promise.all(promises)
results.forEach(result => {
if (result.alive) {
console.log(`+++ ${result.host}`)
} else {
console.log(`- ${result.host}`)
}
})
}
pingSubnet('192.168.3.0')
Использовать внешнюю библиотеку ping: npm install ping
const ping = require('ping')
// Асинхронная функция отправки команды ping через библиотеку
async function pingHost(host) {
try {
const res = await ping.promise.probe(host, { timeout: 1 })
return { host, alive: res.alive }
} catch (error) {
return { host, alive: false }
}
}
// Функция возврата промисов вручную без async
function pingHost(host) {
return ping.promise.probe(host, { timeout: 1 })
.then(res => {
return { host, alive: res.alive }
})
.catch(error => {
return { host, alive: false }
})
}
async function pingSubnet(subnet) {
const promises = []
for (let i = 1; i <= 254; i++) {
const host = `${subnet.split('.').slice(0,3).join('.')}.${i}`
promises.push(pingHost(host))
}
const results = await Promise.all(promises)
results.forEach(result => {
if (result.alive) {
console.log(`+++ ${result.host}`)
} else {
console.log(`- ${result.host}`)
}
})
}
pingSubnet('192.168.3.0')
await Promise.all()
- дожидается успешного выполнения всех запросов.
await Promise.allSettled()
- дожидается выполнения всех запросов не зависимо от успеха (возвращает статус и результат).
await Promise.race()
- дожидается первого успешного выполнения, что бы получить результат от него не зависимо от его успеха.
Преобразовать строку в массив из букв (char
).
let line = "javascript"
let arr = Array.from(str) // ['j', 'a', 'v', 'a', 's', 'c', 'r', 'i', 'p', 't']
Метод split()
используется для преобразования строки в массив.
line = "1,2,3,4,5" // '1,2,3,4,5'
arr = line.split(",") // [ '1', '2', '3', '4', '5' ]
Метод join()
используется для объединение массива в строку.
let arrSlice = arr.slice(1, 3) // Срез, выводит содержимое массива с 1 по 3 индекс (два элемента)
arrSlice.join() // Собирает массив в строку: '2,3'
arrSlice.join(" - ") // '2 - 3'
Метод match()
используется для поиска совпадений с регулярным выражением в строке. Он возвращает массив с найденными совпадениями или null
, если совпадений не найдено.
let stringForRegex = "Текст для проверки текста"
stringForRegex.match(/текст/)[0] // Получить содержимое первого совпадения
stringForRegex.match(/текст/).index // Возвращает порядковый индекс первого совпадения в тексте (19)
stringForRegex.match(/текст/i)[0] // Возвращает только первое совпадение без учета регистра
stringForRegex.match(/текст/gi) // Получить массив всех совпадений: [ 'Текст', 'текст' ]
stringForRegex = "2024-10-25"
stringForRegex.match(/(\d{4})-(\d{2})-(\d{2})/) // Группа захвата, которая возвращает полное совпадение, а также значения отдельных групп
// [ '2024-10-25', '2024', '10', '25', index: 0, input: '25-10-2024', groups: undefined ]
Метод search()
возвращает только индекс первого совпадения.
"Текст для проверки текста".search('про') // 10
Метод replace()
заменяет найденные совпадения в строке на другие значения.
stringForRegex = "Текст для замены"
stringForRegex.replace(/для/, "после") // 'Текст после замены'
stringForRegex.replace(/^т/i, "Этот т") // 'Этот текст для замены'
stringForRegex.replace(/$/, "!") // 'Текст для замены!'
stringForRegex.replace(/(Текст)/, "$1 только") // 'Текст только для замены'
stringForRegex.replace(/\s[а-яА-Я]{3}/, "") // 'Текст замены'
stringForRegex.replace(/\s\p{L}+$/u, " кириллицы") // 'Текст для кириллицы'
stringForRegex = "Text for regex"
stringForRegex.replace(/\s\w{3}/, "") // Используется для замены любых латинских букв: 'Text regex'
stringForRegex.replace(/\s[a-zA-Z_]{3}/, "") // эквивалент \w
stringForRegex = "2024-10-25"
stringForRegex = stringForRegex.replace(/(\d{4})-(\d{2})-(\d{2})/,"$3.$2.$1") // Поменять порядок через группы захвата: '25.10.2024'
stringForRegex.replace(/\d{2}\./g, "11.") // Заменяет найденные две идущие цифры подряд: '11.11.2024'
stringForRegex.replace(/\d{4}/, "2025") // Заменяет четыре идущие цифры подряд: '25.10.2025'
stringForRegex.replace(/20\d+/, "2025") // Заменяет 20 и любые идущие за ним цифры: '25.10.2025'
stringForRegex.replace(/10.+/g, "11.2025") // Заменяет 10 и любое количетво символов идущее за ним: '25.11.2025'
stringForRegex.replace(/\d{2,4}/g, "11") // Заменяет найденные цифры следующие в порядке от 2 до 4: ('11.11.11')
stringForRegex.replace(/[45]/g, "1") // Заменить 4 или 5 на 1: '21.10.2021'
Math.min(9, 10) // Получить наименьшее значение двух чисел: 9
Math.max(9, 10) // Получить максимальное значение двух чисел: 10
Math.floor(10 / 3) // Округлить в меньшую сторону: 3
Math.ceil(10/3) // Откруглить в большую сторону: 4
Math.trunc(4.9) // Отбрасывание дробной части: 4
Math.round(4.5) // Округление до ближайшего целого: 5
Math.round(4.45) // Округление до ближайшего целого: 4
Math.fround(5.05) // Ближайшее число с плавающей точкой одинарной точности: 5.050000190734863
Math.random() // Псевдослучайное число между 0 и 1, например, 0.2309471255442206
Math.abs(-7) // Получить абсолютное значение: 7
Math.sign(-3) // Определение знака числа (-1, 0, 1): -1
Math.pow(2, 3) // Возведение в степень: 8
Math.sqrt(16) // Квадратный корень: 4
Math.cbrt(27) // Кубический корень: 3
Math.imul(2, 4) // Целочисленное 32-битное умножение: 8
Math.clz32(1) // Количество ведущих нулей в 32-битном представлении: 31
Создаем директорию, инициализируем проект и устанавливаем зависимости
mkdir api && cd api
npm init -y
npm install express
Серверная часть API
сервера в файле server.js
const express = require('express')
const web = express()
// Middleware для парсинга JSON данных в теле запроса
web.use(express.json())
// Обработка GET запроса с параметрами в пути и заголовками
web.get('/user/:id', (req, res) => {
const userId = req.params.id // Получаем параметр id из пути
const customHeader = req.headers['custom-header'] // Чтение заголовка custom-header
res.json({
message: `GET запрос для пользователя с ID ${userId}`,
customHeader: customHeader || 'Заголовок отсутствует'
})
})
// Обработка POST запроса с данными в теле запроса и заголовками
web.post('/user', (req, res) => {
const { name, age } = req.body // Получаем данные из тела POST запроса
const authHeader = req.headers['authorization'] // Чтение содержимого из заголовка `authorization`
if (authHeader !== 'Bearer TOKEN') {
res.json({
message: `Авторизация не пройдена, переданный токен: ${authHeader}`
})
} else {
res.json({
name: name || 'Не указано',
age: age || 'Не указано',
})
}
})
// Запуск сервера на порту 3000
const PORT = 3000
web.listen(PORT, () => {
console.log(`Сервер запущен на http://localhost:${PORT}`)
})
Запуск сервера
node server.js
Клиентская часть для работы с API
npm install axios
Пример GET
запроса
const axios = require('axios')
// URL сервера
const url = 'http://localhost:3000'
// Пример GET запроса с параметром id в пути и кастомным заголовком
async function getUser(userId, Header) {
try {
const response = await axios.get(`${url}/user/${userId}`, {
headers: {
'custom-header': Header
}
})
console.log('GET Ответ:', response.data)
} catch (error) {
console.error('Ошибка GET запроса:', error.message)
}
}
await getUser(1, 'Value')
// GET Ответ: {
// message: 'GET запрос для пользователя с ID 1',
// customHeader: 'Value'
// }
Пример POST
запроса
// Пример POST запроса с телом и заголовком авторизации
async function createUser(key, name, age) {
try {
const response = await axios.post(`${url}/user`, {
name: name,
age: age
}, {
headers: {
'Authorization': `Bearer ${key}`
}
})
console.log('POST Ответ:', response.data)
} catch (error) {
console.error('Ошибка POST запроса:', error.message)
}
}
await createUser('KEY', 'Alex', 29)
// POST Ответ: { message: 'Авторизация не пройдена, переданный токен: Bearer KEY' }
await createUser('TOKEN', 'Alex', 29)
// POST Ответ: { name: 'Alex', age: 29 }
async function fetchData(url) {
try {
// Отправляем GET-запрос на указанный URL
const response = await fetch(url)
// Проверяем, что ответ успешен
if (!response.ok) {
throw new Error(`Error Status: ${response.status}`)
}
// Получаем и выводим данные в формате JSON
const data = await response.json()
return data
}
// Обрабатываем ошибки
catch (error) {
console.error('Error:', error)
}
}
const result = await fetchData('https://jsonplaceholder.typicode.com/todos/1')
result // { userId: 1, id: 1, title: 'delectus aut autem', completed: false }
JSON.stringify(result) // '{"userId":1,"id":1,"title":"delectus aut autem","completed":false}'
Cheerio - это библиотека для работы с HTML
и XML
в Node.js
npm install axios cheerio https-proxy-agent iconv-lite
Подключаем библиотеки и получаем содержимое страницы с помощью Axios
через Proxy
const axios = require('axios')
const cheerio = require('cheerio')
const proxy = require('https-proxy-agent')
const iconv = require('iconv-lite')
// Имя агента в заголовке запросов (вместо axios)
const headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0 Win64 x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
}
const proxyAddress = '192.168.3.100'
const proxyPort = 9090
const username = 'test'
const password = 'test'
// Создание экземпляра Axios с использованием конфигурации Proxy
const createAxiosProxy = () => {
const config = {}
config.httpsAgent = new proxy.HttpsProxyAgent(`http://${username}:${password}@${proxyAddress}:${proxyPort}`)
return axios.create(config)
}
const axiosProxy = createAxiosProxy()
const url = "https://rutor.info"
// Отправляем запрос
const response = await axiosProxy.get(url, {
responseType: 'arraybuffer',
headers: headers
})
// Декодируем ответ
html = iconv.decode(response.data, 'utf8')
Вытаскиваем данные с помощью Cheerio
const data = cheerio.load(html)
// Обращаемся к элементу div (не обязательно указывать название элемента) с id="ws" > div с id="index" > элемент "tbody" (таблица) > элемент "tr" (строки)
data('div#ws #index tbody tr').length // 171
// Исключить из вывода строку с class="backgr" (загловки столбцов)
data('#ws #index tbody tr').not('.backgr').length // 170
// Получить содержимое первого элемента "tr" в формате HTML, строки или текста без тегов
data('#ws #index tbody tr').not('.backgr').eq(0).html()
data('#ws #index tbody tr').not('.backgr').eq(0).toString()
data('#ws #index tbody tr').not('.backgr').eq(0).text()
// Получить содержимое элемента по частичному совпадению
data('#ws #index tbody tr').not('.backgr').find('td:contains("слово")').text().replace('\n','').trim()
// 'Мужское слово (2024) WEB-DLRip'
// Получить содержимое второго элемента по индексу в строке (столбцe)
data('#ws #index tbody tr').not('.backgr').eq(0).find('td').eq(1).text().replace('\n','').trim()
// 'Launcher for Zapret [v 1.3] (2024) PC | Portable'
// Получить содержимое атрибута "href" из элемента с классом "downgif"
data('#ws #index tbody tr').not('.backgr').eq(0).find('td a.downgif').attr('href')
// '//d.rutor.info/download/1008549'
// Получить содержимое атрибута "href" из второго элемента "a" в элементе "td"
data('#ws #index tbody tr').not('.backgr').eq(0).find('td a:nth-child(2)').attr('href')
// 'magnet:?xt=urn:btih:f1ca88b9421b243b6cb3d4da90e8fe133f381817&dn=rutor.info&tr=udp://opentor.net:6969&tr=http://retracker.local/announce'
// Фильтруем все элементы по частичному совпадению
data('#ws #index tbody tr').not('.backgr').filter((index, element) => {
// Проверяем, содержит ли текущая строка "tr" слово "Крит" в одном из столбцов "td"
return data(element).find('td:contains("Крит")').length > 0
}).map((index, element) => {
// Если слово найдено, извлекаем текст всех "td" в этой строке с помощью map()
return data(element).find('td').map((index, element) => data(element).text()).get().join(' | ').replace('\n','')
}).get()
// [
// '29 Окт 24 | Критик / The Critic (2023) WEB-DLRip 1080p от ExKinoRay | P | 6.10 GB | 1 4',
// '28 Окт 24 | Критик / The Critic (2023) WEB-DLRip | P | 1.46 GB | 58 22',
// '28 Окт 24 | Критик / The Critic (2023) WEB-DLRip-AVC от DoMiNo & селезень | P | 1.46 GB | 64 19',
// '28 Окт 24 | Критик / The Critic (2023) WEB-DL 1080p | P | RGB | 1 | 5.63 GB | 115 54'
// ]
const torrents = []
// Собираем объект из всех элементов
data('#ws #index tbody tr').not('.backgr').each((index, element) => {
const row = data(element)
const torrent = {
'Date': row.find('td').eq(0).text().trim(),
'Name': row.find('td').eq(1).find('a').last().text().trim(),
'Link': 'https://rutor.info' + row.find('td').eq(1).find('a[href^="/torrent"]').attr('href'),
'DownloadLink': 'https://' + row.find('td').eq(1).find('a.downgif').attr('href'),
'Magnet': row.find('td').eq(1).find('a[href^="magnet:"]').attr('href')
}
torrents.push(torrent)
})
// Конвертируем объект в формат JSON
console.log(JSON.stringify(torrents, null, 2))
// [
// {
// "Date": "29 Окт 24",
// "Name": "Launcher for Zapret [v 1.3] (2024) PC | Portable",
// "Link": "https://rutor.info/torrent/1008549/launcher-for-zapret-v-1.3-2024-pc-portable",
// "DownloadLink": "https:////d.rutor.info/download/1008549",
// "Magnet": "magnet:?xt=urn:btih:f1ca88b9421b243b6cb3d4da90e8fe133f381817&dn=rutor.info&tr=udp://opentor.net:6969&tr=http://retracker.local/announce"
// },
// ...
// ]
Puppeteer — это библиотека, которая предоставляет API
для автоматизации любых действий в браузерах Google Chrome и Mozilla Firefox через протокол Chrome DevTools
и WebDriver BiDi
.
mkdir api && cd api && npm init -y && npm install puppeteer
Пример получения списка файлов раздачи с сайта RuTor.
const puppeteer = require('puppeteer')
// Запускаем браузер и открываем новую пустую страницу
const browser = await puppeteer.launch({
headless: true // Отключить отображение браузера (параметр по умолчанию)
})
const page = await browser.newPage()
// Открываем страницу с ожиданием загрузки 60 сек
const query = 721221
await page.goto(`https://rutor.info/torrent/${query}`, {
timeout: 60000,
waitUntil: 'domcontentloaded' // ожидать только полной загрузки DOM (не ждать загрузки внешних ресурсов, таких как изображения, стили и скрипты)
})
await page.evaluate(() => {
// Находим кнопку по JavaScript пути и нажимаем на нее
// document.querySelector("#details > tbody > tr:nth-child(11) > td.header > span").click()
// document.querySelector("#details > tbody > tr:nth-child(12) > td.header > span").click()
// Находим все кпноки которые содержат class="button"
const buttons = document.querySelectorAll('span.button')
// Проходимся по найденным кнопкам
buttons.forEach(button => {
// Проверяем, содержит ли кнопка текст "Файлы" и нажимаем на нее
if (button.textContent.includes('Файлы')) {
button.click()
}
})
})
// Дождаться загрузки результатов
// const elementHandle = await page.waitForSelector('#files')
// Ищем элемент с идентификатором #files и проверяем, что элемент существует его содержимое не содержит текст загрузки
await page.waitForFunction(() => {
const element = document.querySelector('#files')
return element && !element.textContent.includes("Происходит загрузка списка файлов...")
}, {
timeout: 30000, // Ожидать результат 30 секунд
polling: 50 // Проверка каждые 50мс (по умолчанию 100мс)
})
// Забираем результат после успешной проверки
const elementContent = await page.evaluate(() => {
const element = document.querySelector('#files')
return element ? element.textContent : null
})
// Закрываем браузер
await browser.close()
// Разбиваем полученные результаты на массив из строк (split) исключая первую строку (slince)
const lines = elementContent.trim().split('\n').slice(1)
// Регулярное выражение для разбиения строки на название и размер
const regex = /^(.+?)([\d.]+\s*\S+)\s+\((\d+)\)$/
const torrents = []
for (const line of lines) {
const match = line.match(regex)
const torrent = {
'Name': match[1],
'Size': match[2]
}
torrents.push(torrent)
}
console.log(JSON.stringify(torrents, null, 2))
Пример создания API
для получения результатов проверки скорости интернета в формате JSON
через Ookla SpeedTest.
const puppeteer = require('puppeteer')
const browser = await puppeteer.launch({
headless: false
})
const page = await browser.newPage()
await page.goto(`https://www.speedtest.net`, {
waitUntil: 'domcontentloaded'
})
// Дождаться, когда кнопка "Go" станет доступной
await page.waitForSelector('span[data-testid="start-button"]')
// Возвращаем массив всех элементов span на странице с их текстом
await page.evaluate(() => {
return Array.from(document.querySelectorAll('span')).map(elemet => ({
Text: elemet.innerText, // Текст, отображаемый внутри элемента
Content: elemet.textContent, // Весь текст внутри элемента, включая скрытые части
// HTML: elemet.innerHTML, // HTML-код, который находится внутри элемента
// AllHTML: elemet.outerHTML , // Весь HTML-код, который находится внутри элемента
id: elemet.id, // Уникальный идентификатор элемента (#)
className: elemet.className,
tagName: elemet.tagName // Имя тега элемента (например, SPAN)
}))
})
// Находим и нажимаем на кнопку
await page.evaluate(() => {
const buttons = document.querySelectorAll('span')
buttons.forEach(button => {
if (button.textContent.includes('Go') || button.innerText.includes('GO')) {
button.click()
}
})
})
// Функция для получения результата
async function checkResult () {
return await page.evaluate(() => {
const element = document.querySelector('div.result-data a')
return element ? element.getAttribute('href') : null
})
}
// Цикл для проверки получения результата
let resultUrl = '#'
// Проверяем, что результат содержит в начале строки 'http'
while (!resultUrl.startsWith('http')) {
resultUrl = await checkResult()
}
await browser.close()
// Считываем данные из полученного url с помощью Fetch
const result = await fetch(resultUrl)
const resultHTML = await result.text()
// Вытаскиваем JSON из HTML страницы
const resultJSON = resultHTML.split('window.OOKLA')[3].replace('.INIT_DATA = ','').replace(';\n','')
const resultObj = JSON.parse(resultJSON)
resultObj.result.id // 16947429430
resultObj.result.download // 7169 (7.17)
resultObj.result.upload // 4939 (4.94)
resultObj.result.idle_latency // 171 (ping)