Webskrabning på klientsiden med JavaScript ved hjælp af jQuery og Regex

Da jeg byggede mit første open source-projekt, codeBadges, troede jeg, det ville være let at hente brugerprofildata fra alle de vigtigste kodelæringswebsteder.

Jeg var fortrolig med API-opkald og fik anmodninger. Jeg troede, jeg kunne bare bruge jQuery til at hente dataene fra de forskellige API'er og bruge dem.

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

Nå, det var let. Men det viser sig, at ikke alle websteder har en offentlig API, som du bare kan hente de data, du vil have fra.

Men bare fordi der ikke er nogen offentlig API, betyder det ikke, at du skal give op! Du kan bruge webskrabning til at hente dataene med kun lidt ekstra arbejde .

Lad os se, hvordan vi kan bruge webskrabning på klientsiden med JavaScript.

For eksempel vil jeg hente mine brugeroplysninger fra min offentlige freeCodeCamp-profil. Men du kan bruge disse trin på enhver offentlig HTML-side.

Det første skridt i at skrabe dataene er at få fat i den fulde side html ved hjælp af en jQuery- .getanmodning.

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

Awesome, hele sidens kildekode er lige logget på konsollen.

Bemærk: Hvis du får en fejl på dette trin i retning af No ‘Access-Control-Allow-Origin’ header is present on the requested resourceikke bekymre dig. Rul ned til sektionen Lad ikke CORS stoppe dig i dette indlæg.

Det var let. Ved hjælp af JavaScript og jQuery anmoder ovenstående kode om en side fra www.freecodecamp.org, som en browser ville. Og freeCodeCamp reagerer med siden. I stedet for en browser, der kører koden for at få vist siden, får vi HTML-koden.

Og det er hvad webskrabning er, udpakning af data fra websteder.

Ok, svaret er ikke nøjagtigt så pænt som de data, vi får tilbage fra en API.

Men ... vi har dataene derinde et eller andet sted.

Når vi først har kildekoden, er de oplysninger, vi har brug for, derinde, vi skal bare hente de data, vi har brug for!

Vi kan søge gennem svaret for at finde de elementer, vi har brug for.

Lad os sige, at vi vil vide, hvor mange udfordringer brugeren har gennemført, fra det brugerprofilsvar, vi fik tilbage.

I skrivende stund er en gennemført udfordrings af en autocamper organiseret i tabeller på brugerprofilen. Så for at få det samlede antal udfordringer afsluttet kan vi tælle antallet af rækker.

En måde er at pakke hele svaret i et jQuery-objekt, så vi kan bruge jQuery-metoder som .find()at hente dataene.

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

Dette fungerer fint - vi får det rigtige resultat. Men det er ikke en god måde at få det resultat, vi er efter. At omdanne svaret til et jQuery-objekt indlæser faktisk hele siden, inklusive alle de eksterne scripts, skrifttyper og typografiark fra denne side ... Uh oh!

Vi har brug for et par data. Vi har virkelig ikke brug for siden belastningen, og bestemt ikke alle de eksterne ressourcer, der følger med den.

Vi kunne fjerne script-tags og derefter køre resten af ​​svaret gennem jQuery. For at gøre dette kunne vi bruge Regex til at lede efter scriptmønstre i teksten og fjerne dem.

Eller endnu bedre, hvorfor ikke bruge Regex til at finde det, vi leder efter i første omgang?

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

Og det fungerer! Ved at bruge Regex-koden ovenfor fjerner vi tabelhovedrækkerne (der ikke indeholdt nogen udfordringer) og matcher derefter alle tabelrækker for at tælle antallet af udførte udfordringer.

Det er endnu lettere, hvis de ønskede data bare er der i svaret i almindelig tekst. På tidspunktet for skrivningen var brugerpointene i html-lignende

[ 1498 ]

bare venter på at blive skrabet.

var points = response.match(/

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

I det ovennævnte Regex-mønster matcher vi det h1-element, vi leder efter, inklusive det, [ ]der omgiver punkterne, og grupperer ethvert tal indeni med. ([\d]*?).Vi får en matrix tilbage, det første [0]element er hele kampen, og det andet [1]er vores gruppekamp (vores point ).

Regex er nyttigt til at matche alle slags mønstre i strenge, og det er fantastisk at søge gennem vores svar for at få de data, vi har brug for.

Du kan bruge den samme 3-trins proces til at skrabe profildata fra en række forskellige websteder:

  1. Brug JavaScript på klientsiden
  2. Brug jQuery til at skrabe dataene
  3. Brug Regex til at filtrere dataene efter de relevante oplysninger

Indtil jeg rammer et problem, CORS.

Lad ikke CORS stoppe dig!

CORS eller Cross-Origin Resource Sharing kan være et reelt problem med webskrabning på klientsiden.

Af sikkerhedsmæssige årsager begrænser browsere HTTP-anmodninger på tværs af oprindelse, der startes fra scripts. Og fordi vi bruger Javascript på klientsiden på frontenden til webskrabning, kan der opstå CORS-fejl.

Her er et eksempel, der forsøger at skrabe profildata fra CodeWars ...

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

I skrivende stund giver kørsel af ovenstående kode dig en CORS-relateret fejl.

Hvis der ikke er nogen Access-Control-Allow-Originoverskrift fra det sted, du skraber, kan du støde på problemer.

Den dårlige nyhed er, at du skal køre disse slags anmodninger på serversiden for at komme omkring dette problem.

Whaaaaaaat, dette formodes at være webskrabning på klientsiden ?!

Den gode nyhed er, at takket være mange andre vidunderlige udviklere, der er stødt på de samme problemer, behøver du ikke røre bagenden selv.

Vi holder fast inden for vores frontend-script og kan bruge værktøjer på tværs af domæner som Enhver Oprindelse, Uanset Oprindelse, Alle Oprindelser, crossorigin og sandsynligvis meget mere. Jeg har fundet ud af, at du ofte har brug for at teste et par af disse for at finde den, der fungerer på det sted, du prøver at skrabe.

Tilbage til vores eksempel på CodeWars kan vi sende vores anmodning via et værktøj på tværs af domæner for at omgå CORS-problemet.

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

Og ligesom magi har vi vores svar.