Omgår LinkedIn-søkelimet ved å leke med API-en

Begrensning

Det er en slik begrensning på LinkedIn — Begrensning på kommersiell bruk. Det er svært sannsynlig at du, som jeg for ikke så lenge siden, aldri har støtt på eller hørt om det.

Omgår LinkedIn-søkelimet ved å leke med API-en

Kjernen i begrensningen er at hvis du bruker søk etter folk utenfor kontaktene dine for ofte (det finnes ingen eksakte målinger, det avgjøres av algoritmen basert på aktivitetsmønsteret ditt — hvor ofte og mye du har søkt og lagt til folk), vil søkeresultatene bli begrenset til tre profiler i stedet for 1000 (som standard 100 sider, 10 profiler per side). Begrensningen tilbakestilles i begynnelsen av hver måned. Selvfølgelig, har premiumkontoer ikke denne begrensningen.

Men for ikke lenge siden begynte jeg å eksperimentere mye med søk på LinkedIn for et hobbyprosjekt, og plutselig fikk jeg denne begrensningen. Selvfølgelig likte jeg ikke dette, ettersom jeg ikke hadde brukt det til kommersielle formål, så første tanken var å undersøke begrensningen og forsøke å omgå den.

[Viktig presisering — materialene i denne artikkelen er kun ment for informasjons- og utdanningsformål. Forfatteren oppfordrer ikke til bruk av dem i kommersielle sammenhenger.]

Vi undersøker problemet

Vi har: i stedet for ti profiler med paginering, gir søket kun tre, etterfulgt av en boks med "anbefaling" om premiumkonto og deretter utydelige og ikke-klikkbare profiler.

Håndledningen strekker seg umiddelbart til utviklerkonsollen for å se disse skjulte profilene — kanskje vi kan fjerne noen stiler som gjør dem uklare, eller hente informasjon fra boksen i markup. Men, som forventet, er disse profilene bare placeholder-bilder og inneholder ingen informasjon.

Omgår LinkedIn-søkelimet ved å leke med API-en

Greit, nå ser vi på Network-fanen og sjekker om det faktisk skjer et alternativt søkeresultat som returnerer bare tre profiler. Vi finner forespørselen til “/api/search/blended” og ser på svaret.

Omgår LinkedIn-søkelimet ved å leke med API-en

Profilene kommer i en array kalt `included`, men det er hele 15 enheter i den. I dette tilfellet er de første tre av dem objekter med tilleggsinformasjon, hver objekt inneholder informasjon om den spesifikke profilen (for eksempel om profilen er premium).

Omgår LinkedIn-søkelimet ved å leke med API-en

De påfølgende 12 er ekte profiler – søkresultater hvor vi bare vil se tre. Som man kan gjette, vises kun de som får tilleggsinformasjon (de første tre objektene). For eksempel, hvis vi tar svaret fra profilen uten grense, så kommer det 28 enheter – 10 objekter med tilleggsinformasjon og 18 profiler.

Svar for profil uten grenseOmgår LinkedIn-søkelimet ved å leke med API-en
Omgår LinkedIn-søkelimet ved å leke med API-en

Hvorfor kommer det flere profiler enn 10, selv om det etterspørres nøyaktig 10, og de ikke er med i visningen, selv på neste side vil de ikke være der – vet jeg foreløpig ikke. Hvis jeg analyserer URL-en i forespørselen, kan jeg se at count=10 (hvor mange profiler som skal returneres i svaret, maks 49).

Omgår LinkedIn-søkelimet ved å leke med API-en

Jeg ville sette pris på alle kommentarer om dette.

Vi eksperimenterer

Bra, det viktigste er at vi nå vet sikkert – det kommer flere profiler i svaret enn det som vises for oss. Dette betyr at vi kan hente mer data, til tross for grensen. La oss prøve å hente APIet selv, direkte fra konsollen, ved hjelp av fetch.

Omgår LinkedIn-søkelimet ved å leke med API-en

Som forventet får vi en feil, 403. Dette er relatert til sikkerhet, vi sender ikke CSRF-tokenet (CSRF på Wikipedia. Kort fortalt – til hver forespørsel legges det til et unikt token som kontrolleres på serveren for autentisitet).

Omgår LinkedIn-søkelimet ved å leke med API-en

Det kan kopieres fra hvilken som helst annen vellykket forespørsel eller fra informasjonskapsler, hvor det lagres i feltet 'JSESSIONID'.

Hvor å finne tokenetOverskrift fra en annen forespørsel:

Omgår LinkedIn-søkelimet ved å leke med API-en

Eller fra informasjonskapsler, direkte via konsollen:

Omgår LinkedIn-søkelimet ved å leke med API-en

La oss prøve igjen, denne gangen sender vi inn innstillinger til fetch, hvor vi spesifiserer parameteren for header vårt csrf-token.

Omgår LinkedIn-søkelimet ved å leke med API-en

Suksess, vi mottar alle 10 profiler. :tada:

På grunn av forskjellen i overskrifter, er strukturen på svaret litt forskjellig fra det som kommer i den originale forespørselen. Vi kan få samme struktur hvis vi legger til 'Accept: 'application/vnd.linkedin.normalized+json+2.1' i objektet vårt, sammen med csrf-tokenet.
Eksempel på svar med lagt til overskriftOmgår LinkedIn-søkelimet ved å leke med API-en

Mer om Accept-overskriften

Hva skjer videre?

Videre kan parameteren `start` redigeres (manuelt eller automatiseres), som angir indeksen fra hvilken vi vil få 10 profiler (standard = 0) fra hele søket. Med andre ord, ved å inkrementere det med 10 etter hver forespørsel, får vi vanlig paginering, med 10 profiler om gangen.

På dette stadiet hadde jeg nok data og frihet til å fortsette arbeidet med pet-prosjektet. Men det ville vært en skam å ikke prøve å visualisere disse dataene på stedet, siden de er klare. Vi vil ikke gå inn i Ember, som brukes på frontenden. jQuery var koblet til nettstedet, og ved å hente frem kunnskap om grunnleggende syntaks kan man på noen få minutter lage følgende.

Kode i jQuery

/* рендер блока, принимаем данные профиля и вставляем блок в список профилей используя эти данные */
const  createProfileBlock = ({ headline, publicIdentifier, subline, title }) => {
    $('.search-results__list').append(
        `<li class="search-result search-result__occluded-item ember-view">
            <div class="search-entity search-result search-result--person search-result--occlusion-enabled ember-view">
                <div class="search-result__wrapper">
                    <div class="search-result__image-wrapper">
                        <a class="search-result__result-link ember-view" href="/no/in/${publicIdentifier}/">
                            <figure class="search-result__image">
                                <div class="ivm-image-view-model ember-view">
                                    <img class="lazy-image ivm-view-attr__img--centered EntityPhoto-circle-4  presence-entity__image EntityPhoto-circle-4 loaded" src="http://www.userlogos.org/files/logos/give/Habrahabr3.png" />
                                </div>
                            </figure>
                        </a>
                    </div>
                    
                    <div class="search-result__info pt3 pb4 ph0">
                        <a class="search-result__result-link ember-view" href="/no/in/${publicIdentifier}/">
                            <h3 class="actor-name-with-distance search-result__title single-line-truncate ember-view">
                                ${title.text}
                            </h3>
                        </a>

                        <p class="subline-level-1 t-14 t-black t-normal search-result__truncate">${headline.text}</p>

                        <p class="subline-level-2 t-12 t-black--light t-normal search-result__truncate">${subline.text}</p>
                    </div>
                </div>
            </div>
        <li>`
 );
};

// henter API, henter data og rendre profiler
const fetchProfiles = () =&gt; {
 // token
 const csrf = 'ajax:9082932176494192209';
 
 // objekt med forespørselinnstillinger, sender token
 const settings = { headers: { 'csrf-token': csrf } }

 // URL for forespørsel, med dynamisk startindeks på slutten
 const url = `https://www.linkedin.com/voyager/api/search/blended?count=10&amp;filters=List(geoRegion-jp0,network-S,resultType-PEOPLE)&amp;origin=FACETED_SEARCH&amp;q=all&amp;queryContext=List(spellCorrectionEnabled-true,relatedSearchesEnabled-true)&amp;start=${nextItemIndex}`; 
 /* utfør forespørsel, for hver profil i svaret kaller vi render blokk, og deretter inkrementerer vi startindeksen med 10 */
 fetch(url, settings).then(response =&gt; response.json()).then(data =&gt; {
 data.elements[0].elements.forEach(createProfileBlock);
 nextItemIndex += 10;
});
};


// fjerner alle profiler fra listen
$('.search-results__list').find('li').remove();
// setter inn knapp for å laste ned profiler
$('.search-results__list').after('<button id="load-more">Last flere</button>');
// legger til funksjonalitet på knappen
$('#load-more').addClass('artdeco-button').on('click', fetchProfiles);

// setter standard profilindeks for forespørselen
window.nextItemIndex = 0;

Hvis dette kjøres direkte i konsollen på søkesiden, vil det legge til en knapp som laster inn 10 nye profiler ved hver klikk, og renderer dem som en liste. Selvfølgelig må token og url endres til det nødvendige. Profilblokken vil inneholde navn, stilling, beliggenhet, lenke til profilen og et plassholderbilde.

Omgår LinkedIn-søkelimet ved å leke med API-en

Konklusjon

Dermed klarte vi med minimal innsats å finne et sårbart punkt og gjenvinne søk uten begrensninger. Det var bare nødvendig å analysere dataene og deres vei, samt se nærmere på forespørselen.

Jeg kan ikke si at dette utgjør et alvorlig problem for LinkedIn, fordi det ikke utgjør noen trussel. Maksimalt er det tapt inntekt på grunn av slike «omgåelser», som gjør at man unngår å betale for premium. Kanskje er et slikt serverrespons nødvendig for å sikre at andre deler av nettstedet fungerer korrekt, eller det er bare lathet hos utviklerne og mangel på ressurser som hindrer dem i å gjøre en god jobb. (Begrensningen ble innført i januar 2015; før dette var det ikke noe tak).

P.S.

Selvfølgelig er koden i jQuery et ganske primitivt eksempel på muligheter. Jeg har for øyeblikket laget en utvidelse for nettleseren til mine egne behov. Den legger til kontrollknapper og renderer fullverdig profiler med bilder, invitasjonsknapp og felles forbindelser. Den samler også dynamisk filtre for steder, selskaper og annet, og henter token fra informasjonskapsler. Så det er ikke nødvendig å hardkode noe lenger. I tillegg legger den til ekstra innstillingsfelt, som «hvor mange profiler som skal hentes om gangen, opptil 49».

Omgår LinkedIn-søkelimet ved å leke med API-en

Jeg jobber fortsatt med dette tillegget, og planlegger å publisere det offentlig. Kontakt meg hvis du er interessert.

Kilde: habr.com

Kjøp pålitelig hosting for nettsteder med DDoS-beskyttelse, VPS VDS-servere 🔥 Kjøp pålitelig hosting for nettsteder med DDoS-beskyttelse, VPS VDS-servere | ProHoster