Клієнтське веб-вишкрібання за допомогою JavaScript за допомогою jQuery та Regex

Коли я будував свій перший проект з відкритим кодом, codeBadges, я думав, що буде легко отримати дані профілю користувача з усіх основних веб-сайтів, що вивчають коди.

Я був знайомий із дзвінками API та отримував запити. Я думав, що можу просто використовувати jQuery для отримання даних з різних API та їх використання.

var name = 'codemzy'; $.get('//api.github.com/users/' + name, function(response) { var followers = response.followers;});

Ну, це було легко. Але виявляється, що не на кожному веб-сайті є загальнодоступний API, з якого ви можете просто захопити потрібні дані.

Але те, що не існує загальнодоступного API, не означає, що вам потрібно здатися! Ви можете скористатися веб-скребком для отримання даних, лише трохи попрацювавши .

Давайте подивимося, як ми можемо використовувати веб-скрапінг на стороні клієнта за допомогою JavaScript.

Наприклад, я захоплюю інформацію про користувача з мого загальнодоступного профілю freeCodeCamp. Але ви можете використовувати ці дії на будь-якій загальнодоступній HTML-сторінці.

Першим кроком у вишкрібанні даних є захоплення повної сторінки html за допомогою .getзапиту jQuery .

var name = "codemzy";$.get('//www.freecodecamp.com/' + name, function(response) { console.log(response);});

Дивовижно, вихідний код цілої сторінки щойно увійшов на консоль.

Примітка. Якщо на цьому етапі ви отримуєте помилку, подібну до No ‘Access-Control-Allow-Origin’ header is present on the requested resourceне хвилюйся. Прокрутіть униз до розділу Не дозволяти CORS зупинити вас у цій публікації.

Це було легко. Використовуючи JavaScript та jQuery, наведений вище код запитує сторінку з www.freecodecamp.org, як це робить браузер. І freeCodeCamp відповідає сторінкою. Замість браузера, на якому запущений код для відображення сторінки, ми отримуємо HTML-код.

І ось що таке веб-скрапінг, витягуючи дані з веб-сайтів.

Гаразд, відповідь не настільки акуратна, як дані, які ми отримуємо з API.

Але ... у нас є дані, десь там.

Після того, як у нас є вихідний код, там є необхідна інформація, нам просто потрібно взяти потрібні нам дані!

Ми можемо шукати відповідь, щоб знайти потрібні нам елементи.

Скажімо, ми хочемо знати, скільки завдань вирішив користувач, з відповіді на профіль користувача, який ми отримали назад.

На момент написання статті виконані завдання для кемпера впорядковані в таблиці в профілі користувача. Отже, щоб отримати загальну кількість виконаних завдань, ми можемо порахувати кількість рядків.

Одним із способів є обгортання всієї відповіді в об’єкт jQuery, щоб ми могли використовувати методи jQuery, такі як .find()отримання даних.

// number of challenges completedvar challenges = $(response).find('tbody tr').length;

Це чудово працює - ми отримуємо правильний результат. Але це не найкращий спосіб отримати результат, за яким ми прагнемо. Перетворення відповіді на об’єкт jQuery фактично завантажує всю сторінку, включаючи всі зовнішні сценарії, шрифти та таблиці стилів із цієї сторінки ... О, о!

Нам потрібно кілька біт даних. Нам дійсно не потрібне завантаження сторінки, і, звичайно, не всі зовнішні ресурси, які з нею поставляються.

Ми могли б видалити теги сценарію, а потім виконати решту відповідей через jQuery. Для цього ми могли б використовувати Regex для пошуку шаблонів сценаріїв у тексті та їх видалення.

Або ще краще, чому б не використовувати регулярний вираз для пошуку того, що ми шукаємо в першу чергу?

// number of challenges completedvar challenges = response.replace(/[\s|\S]*?/g).match(//g).length;

І це працює! Використовуючи код регулярного виразу вище, ми видаляємо рядки заголовка таблиці (які не містили жодних проблем), а потім збігаємо всі рядки таблиці, щоб підрахувати кількість виконаних завдань.

Це ще простіше, якщо потрібні вам дані просто є у відповіді у вигляді простого тексту. На момент написання користувацькі бали були в html, як

[ 1498 ]

просто чекаючи, щоб їх зішкребли.

var points = response.match(/

\[ ([\d]*?) \]/)[1];

У наведеному вище шаблоні регулярних виразів ми співпадаємо з елементом h1, який ми шукаємо, включаючи той, [ ]що оточує точки, і згрупуємо будь-яке число всередині за допомогою. ([\d]*?).Ми отримуємо масив назад, перший [0]елемент - це весь збіг, а другий [1]- збіг нашої групи (наші очки ).

Regex корисний для узгодження всіх видів шаблонів у рядках, і він чудовий для пошуку в нашій відповіді, щоб отримати потрібні нам дані.

You can use the same 3 step process to scrape profile data from a variety of websites:

  1. Use client-side JavaScript
  2. Use jQuery to scrape the data
  3. Use Regex to filter the data for the relevant information

Until I hit a problem, CORS.

Don’t Let CORS Stop You!

CORS or Cross-Origin Resource Sharing, can be a real problem with client-side web scraping.

For security reasons, browsers restrict cross-origin HTTP requests initiated from within scripts. And because we are using client-side Javascript on the front end for web scraping, CORS errors can occur.

Here’s an example trying to scrape profile data from CodeWars…

var name = "codemzy";$.get('//www.codewars.com/users/' + name, function(response) { console.log(response);});

At the time of writing, running the above code gives you a CORS related error.

If there is noAccess-Control-Allow-Origin header from the place you’re scraping, you can run into problems.

The bad news is, you need to run these sorts of requests server-side to get around this issue.

Whaaaaaaaat, this is supposed to be client-side web scraping?!

The good news is, thanks to lots of other wonderful developers that have run into the same issues, you don’t have to touch the back end yourself.

Staying firmly within our front end script, we can use cross-domain tools such as Any Origin, Whatever Origin, All Origins, crossorigin and probably a lot more. I have found that you often need to test a few of these to find the one that will work on the site you are trying to scrape.

Back to our CodeWars example, we can send our request via a cross-domain tool to bypass the CORS issue.

var name = "codemzy";var url = "//anyorigin.com/go?url=" + encodeURIComponent("//www.codewars.com/users/") + name + "&callback=?";$.get(url, function(response) { console.log(response);});

And just like magic, we have our response.