Вы когда-нибудь задумывались, как веб-приложения просматривают ссылку после того, как вы разместили ее на своей шкале времени или отправили сообщение? Я был на солнце и возвращался несколько раз, пытаясь понять это.
У меня было много вопросов, на которые нужно было ответить, но либо никто не понимал того, что я спрашивал, либо я задавал неправильные вопросы.
Я получил самые тревожные ответы: «Вы можете использовать инструмент API парсера для этого, это то, что я использовал в своем проекте».
Такие услуги, как
Еще несколько…..
Пока однажды я не встретил ангела-хранителя и познакомился с протоколом открытого графа.
Спасибо, Эмма 🤗.
К вашему сведению. Правильное слово для обозначения того, что мы делаем, называется парсинг веб-страниц.
Что такое протокол открытого графа?
Протокол Open Graph позволяет любой веб-странице стать многофункциональным объектом в социальном графе. Например, это используется в Facebook, чтобы любая веб-страница имела те же функции, что и любой другой объект на Facebook.
~ Кто-то из https://ogp.me/
Короче говоря, он описывает веб-сайт с такими объектами, как заголовок, описание, изображения и т. Д. С тегами <meta>
.
Я здесь не для того, чтобы говорить о протоколе открытого графа, я здесь, чтобы показать вам, как получить эти данные для предварительного просмотра ссылок, поэтому, если вы хотите узнать больше о OGP, вот пара ссылок.
К вашему сведению - у Twitter есть собственный метатег, но они используют префикс «twitter» вместо «og».
Как мы это делаем ?
Это простой процесс, не требующий особого труда. Мы загрузим веб-страницу в виде текста в нашем приложении Node.js. Затем мы выберем нужные нам HTML-элементы и получим данные / текст, которые они содержат, сохраним их в файл JSON, а затем отправим данные обратно.
"Но как мы можем выбрать дом на заднем конце Адель?"
Простая, с помощью cheerio и других подобных модулей, cheerio - это Быстрая, гибкая и экономичная реализация основного jQuery, разработанная специально для сервера.
Можем ли мы сделать это на передней панели?
Насколько я знаю, вы не можете, это невозможно сделать во внешнем скрипте, когда вы попытаетесь получить, например, мое портфолио или любой другой сайт в консоли Chrome, он выдаст ошибку cors (Cross-Origin Resource Sharing).
Чтобы обойти эту проблему, мы отправим URL-адрес на внутренний сервер, обработаем запрос, а затем отправим обратно данные, которые мы удалили.
Предпосылка
- JQuery, если вы знаете, как выбрать элемент и получить его значения, все хорошо.
- Асинхронный / Ожидание
- NodeJS / ExpressJS
ОК ДАВАЕМ КОД !!!
Если вы хотите присоединиться к нам, у меня есть стартовые файлы, которые вы можете клонировать / скачать, и я тоже буду добавлять готовые файлы.
1 - Познакомьтесь со скриптом внешнего интерфейса
В нашем внешнем скрипте, расположенном в папке public / javascript, есть довольно небольшой объем кода, у нас есть прослушиватель событий щелчка на нашей кнопке добавления, который будет
- вставьте карточку предварительного просмотра загрузки с идентификатором.
- отправьте почтовый запрос на бэкэнд с URL-ссылкой и идентификатором карты, которая была добавлена на страницу.
- подождите, пока данные вернутся, затем добавьте данные в правильную карточку предварительного просмотра, но ищите идентификатор карточки.
const addButton = document.querySelector('button'); addButton.addEventListener('click', async (e) => { e.preventDefault(); try { let urlInput = document.querySelector('input'); const id = await uuid(); const fetchData = { method: 'POST', headers: { 'Content-Type': 'application/json;charset=utf-8' }, body: JSON.stringify({ previewUrl: urlInput.value, id }) }; urlInput.value = ''; prependLoadingPreview(id); const data = await fetch('/get-preview', fetchData) .then(res => res.json()); addDataToPreview(data); } catch (err) { console.log(err); } });
Эта функция принимает идентификатор и добавит предварительный просмотр загрузки в неупорядоченный список,
function prependLoadingPreview(id) { document.querySelector(`ul`).prepend(document.createRange() .createContextualFragment(`<li class="preview-container loading" data-id="${id}"></li>`,'text/html')); }
Эта функция получит объект, она получит список загрузки по его идентификатору, который был добавлен ранее, удалит имя класса загрузки, затем добавит данные
Object example { id: "a60d491d-8c70-4620-aa18-111ae1abaea9", url: "https://www.adelak.me", img:"https://www.npmjs.com/package/mongoose", title: "Mongoose", description: "Mongoose is a MongoDB object modeling tool designed to work in an asynchronous environment. Mongoose supports both promises and callbacks.", domain: "npmjs.com" } function addDataToPreview({ id, url, img, title, description, domain }) { const li = document.querySelector(`li[data-id="${id}"]`); li.classList.remove('loading'); li.innerHTML = `<svg class="delete-button" viewBox="0 0 24 24" onClick="removePreview(this)"><polygon points="17.8,16.7 16.6,17.9 12,13.3 7.4,17.9 6.2,16.7 10.8,12.1 6.2,7.5 7.4,6.3 12,11 16.6,6.4 17.8,7.6 13.2,12.2"></polygon></svg> <a href="${url}" target="_blank"><img class="preview-image" src="${img}" alt="preview image" onError="imgError(this)"/><div class="preview-info"><h5 class="preview-title">${title}</h5><p class="preview-description">${description}</p><span class="preview-url">${domain}</span></div></a>`; }
Эта функция удаляет карту предварительного просмотра
const removePreview = async (e) => { try{ let li = e.parentElement; li.parentElement.removeChild(li); const id = li.getAttribute('data-id'); await fetch(`/remove/${id}`, { method: 'POST' }); }catch(err){ console.log(err); } }
UUID CDN делал загрузку приложения очень медленной, благодаря broofa, который придумал эту функцию, он будет создавать наш уникальный идентификатор для каждой карты предварительного просмотра.
function uuid(){ let date = new Date().getTime(); const randomStrings = (c) => { const r = (date + Math.random()*16)%16 | 0; date = Math.floor(date/16); return (c=='x' ? r :(r&0x3|0x8)).toString(16); } const id = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, randomStrings); return id; }
2 - Установка модулей
Нам нужно установить несколько модулей.
Cheerio, чтобы загрузить исходный код веб-страницы, которую мы хотим просканировать.
ExpressJS для создания нашего HTTP-сервера.
Express-handlebars - шаблонизатор, который упрощает написание HTML-кода и отображает страницу.
Node-fetch, чтобы сделать наш HTTP-запрос в node.js.
Я добавил эти модули в зависимости, просто установите их, запустив npm i
в командной строке.
3 - Создание нашего сервера
В app.js мы запросили все наши модули, настроили механизм просмотра и промежуточное ПО.
Мы можем начать с создания домашнего маршрута, который будет отображать домашний храм и передать ему данные в data.json
(в настоящее время data,json
пусто).
app.get('/', function(req, res) { res.render('home.handlebars', { data }); });
Откройте командную строку и запустите npm start, затем в браузере откройте localhost: // 3000.
Вы должны получить пустую домашнюю страницу с полем ввода.
Теперь мы работаем над получением метаданных, которые мы хотим получить с веб-страницы, давайте создадим маршрут публикации для получения идентификатора и URL-адреса из внешнего интерфейса после нажатия кнопки добавления.
В теле запроса мы ожидаем значение от previewUrl и id.
app.post('/get-preview',(req, res) => { const { previewUrl, id } = req.body; console.log(previewUrl); //https://medium.com/@adoolak/how-to-deploy-a-reactjs-and-express-app-to-heroku-afb5b117e0eb console.log(id);//"a60d491d-8c70-4620-aa18-111ae1abaea9" });
Давайте поработаем над получением HTML-страницы из моего последнего сообщения среднего размера.
Превратите анонимную функцию в функцию async / await и используйте fetch API из модуля node-fetch, затем создайте переменную с именем html и присвойте ей значение метода fetch (убедитесь, что вы используете ключевое слово await, чтобы дождаться результат выборки), передайте ему значение previewUrl из тела запроса, а затем привяжите к нему .then(res => res.text())
.
Затем мы используем cheerio, помните, что cheerio - это реализация основного jquery для серверной части.
Создайте переменную со знаком $ и присвойте ей значение cheerio.load(),
pass переменной html в метод загрузки, теперь вы можете попробовать выбрать элемент html с помощью знака $.
app.post('/get-preview',async (req, res) => { const { previewUrl, id } = req.body; const html = await fetch(previewUrl).then(res => res.text()); const $ = cheerio.load(html); console.log($('h1').text()) //How to deploy a Reactjs and Express App to Heroku });
Теперь мы можем начать получать нужные метатеги, создать переменную с именем metaTagData
, которая будет содержать объект данных,
id - мы передадим объекту id от req.body
,
url - URL-адрес веб-сайта для ключа URL-адреса.
домен - для домена нам просто нужно доменное имя previewUrl, мы можем использовать модуль url из nodejs, чтобы получить имя хоста.
title - используйте cheerio, чтобы выбрать метатег с атрибутом name="title"
img - используйте cheerio, чтобы выбрать метатег с атрибутом name="title"
описание - используйте cheerio, чтобы выбрать метатег с атрибутом name="description"
и получить атрибут content
.
У мета-тегов есть еще один атрибут, называемый content
, в котором хранятся значения. Чтобы получить значения, вам нужно связать селекторы cheerio с помощью метода attr
и передать ему строку content
.
У вас должен получиться такой объект.
const metaTagData = { id:id, url: previewUrl, domain: url.parse(previewUrl).hostname, title: $('meta[name="title"]').attr('content'), img: $('meta[name="image"]').attr('content'), description: $('meta[name="description"]').attr('content'), }
Теперь это должно сработать, но некоторые веб-страницы используют базовый метатег html, некоторые используют открытый график, некоторые используют карточки twitter, некоторые используют атрибут свойства вместо атрибута имени, некоторые не добавляют метатег изображения, мы может в основном закончиться отсутствием данных или отсутствием данных.
Решение
Создание функции, которая вернет первое, что найдет
const getMetaRag = (name) => { return( $(`meta[name=${name}]`).attr('content') || $(`meta[name="og:${name}"]`).attr('content') || $(`meta[name="twitter:${name}"]`).attr('content') || $(`meta[property=${name}]`).attr('content') || $(`meta[property="og:${name}"]`).attr('content') || $(`meta[property="twitter:${name}"]`).attr('content') ); }
Теперь мы можем изменить значение title, img и описания нашего объекта metaTagData на функцию getMetaTag и передать ей имя метатега в виде строки.
А что, если веб-страница вообще не использует метатеги?
Мы добавляем резервное значение в наши ключи title, img и description.
const metaTagData = { id:id, url: previewUrl, domain: url.parse(previewUrl).hostname, title: getMetaTag('title') || $(`h1`).text(), img: getMetaTag('image') || './images/no-image.png', description: getMetaTag('description') || $(`p`).text(), }
title - вернется к первому тегу h1 на странице.
img - вернется к изображению в папке public / images.
описание - вернется к тегу первого абзаца на странице.
Некоторые описания могут быть немного длинными, я решил, что все описания должны содержать не более 200 символов.
let { description } = metaTagData; if(description.length > 200){ metaTagData.description = description.substring(0,200) + '...'; }
Затем мы помещаем данные в начало массива данных, используя метод массива unshift, затем записываем их в файл data.json
, используя writeFile
из модуля nodejs fs (файловая система).
data.unshift(metaTagData); fs.writeFile("./data.json", JSON.stringify(data, null, 2),()=>{ res.status(201).json(data.shift()); });
Первый параметр метода writeFile
принимает расположение файла, второй параметр, который мы передаем в данные, которые мы хотим записать в файл, поскольку это файл JSON, который нам нужен для строкового преобразования данных с помощью методаJSON.stringify
, третий параметр принимает функция обратного вызова, где мы отвечаем JSON и передаем ему данные с помощью метода массива сдвига, а также устанавливаем статус HTTP на 201.
Тестовый запуск!
Если вы запустите свое приложение и перейдете по ссылке на любую веб-страницу, а затем нажмете «Добавить», у вас должно получиться это.
Удаление карты
Чтобы удалить карту, создайте другой почтовый маршрут, который будет принимать идентификатор из параметра URL, создайте переменную с именем indexOfId и значение, которое вы сопоставляете с массивом данных json, и верните только идентификатор каждого объекта, а затем объедините метод массива indexOf()
на карту, даст вам точное положение идентификатора, который вы хотите удалить из массива (убедитесь, что вы передали идентификатор из параметра url в метод indexOf).
Затем мы используем метод массива splice для удаления данных из массива данных json и передачи первого параметра переменной indexOfId
и второго параметра значения 1
, что указывает на то, что мы хотим удалить только объект из массива.
Затем мы используем модуль fs nodejs, чтобы перезаписать новые отредактированные данные в файл data.json
, и ответим статусом 200 и используем ответ end()
для завершения запроса.
app.post('/remove/:id', (req, res) => { const { id } = req.params; const indexOfId = data.map(dataId => dataId.id) .indexOf(id); data.splice(indexOfId,1); fs.writeFile("./data.json", JSON.stringify(data, null, 2), () => ( res.status(200).end() )); });
Тестовый запуск!
Если вы попытаетесь удалить карту, а затем обновите страницу, удаленные карты больше не будут там.
Конец пути!!
Вывод
Мы узнали, как создать предварительный просмотр ссылки, удаляя метатеги веб-поиска, но с его помощью вы можете делать больше, чем сбрасывать метатеги.
Возьмем, к примеру, Adidas, они не доказывают наличие API для своего продукта, изображений, цен и т. Д., И вы хотите создать побочный проект электронной коммерции.
Вы можете перейти на их веб-страницу и начать очистку продуктов, но если веб-страница, такая как adidas.com, использует react, angular или vue, это может стать сложным для веб-мусора.
Вам нужно будет использовать браузер без головы, чтобы обойти такие веб-сайты.
!!! Однако будьте осторожны, удаление некоторых веб-сайтов является незаконным !!!
Ресурсы безголового браузера
Есть вопросы?
Напишите мне в твиттере @Adel_xoxo, и я отвечу, насколько мне известно.
~ Адель ак