Клиентско изрязване на уеб с 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 на цялата страница с помощта на jQuery .getзаявка.

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, за да търсим шаблони на скриптове в текста и да ги премахнем.

Или още по-добре, защо да не използваме Regex, за да намерим това, което търсим на първо място?

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

И работи! Използвайки кода на Regex по-горе, премахваме редовете на главата на таблицата (които не съдържат никакви предизвикателства) и след това съпоставяме всички редове на таблицата, за да броим броя на изпълнените предизвикателства.

Още по-лесно е, ако данните, които искате, са само там в отговора в обикновен текст. По време на писането потребителските точки бяха в html като

[ 1498 ]

само чака да бъде остърган.

var points = response.match(/

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

В горния модел на Regex ние съвпадаме с елемента h1, който търсим, включително този, [ ]който заобикаля точките, и групираме всяко число вътре с ([\d]*?).Получаваме обратно масив, първият [0]елемент е целият мач, а вторият [1]е нашият групов мач (нашите точки ).

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

Можете да използвате същия процес от три стъпки за изстъргване на данни от профили от различни уебсайтове:

  1. Използвайте JavaScript от страна на клиента
  2. Използвайте jQuery за изстъргване на данните
  3. Използвайте Regex, за да филтрирате данните за съответната информация

Докато не ударя проблем, CORS.

Не позволявайте на CORS да ви спрат!

CORS или Cross-Origin Resource Sharing може да бъде истински проблем с изстъргването на уеб от клиента.

От съображения за сигурност браузърите ограничават HTTP заявки с кръстосан произход, инициирани от скриптове. И тъй като използваме клиентски Javascript отпред за уеб изстъргване, може да възникнат CORS грешки.

Ето пример за опит за изтриване на данни от профили от CodeWars ...

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

По време на писането, стартирането на горния код ви дава грешка, свързана с CORS.

Ако няма Access-Control-Allow-Originзаглавка от мястото, което изстъргвате, можете да срещнете проблеми.

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.