A LinkedIn keresési korlátjának megkerülése az API-val való játékkal
Határ
Van egy ilyen korlátozás a LinkedIn-en - Kereskedelmi felhasználási korlát. Rendkívül valószínű, hogy te, akárcsak én egészen a közelmúltig, soha nem találkoztál és nem is hallottál róla.
A korlát lényege, hogy ha túl gyakran használod a névjegyeiden kívüli személyek keresését (nincs pontos mérőszám, az algoritmus a te cselekedeteid alapján dönt - milyen gyakran és mennyit kerestél, hozzáadtál személyeket), akkor a keresés eredménye három profilra lesz korlátozva 1000 helyett (alapértelmezett 100 oldal, oldalanként 10 profil). A limit minden hónap elején visszaállításra kerül. Természetesen, a prémium számlákra ez a korlátozás nem vonatkozik.
De nem sokkal ezelőtt egy kisállat-projekt miatt elkezdtem sokat játszani a LinkedIn keresővel, és hirtelen megkaptam ezt a korlátozást. Ez természetesen nem nagyon tetszett, mert nem használtam semmilyen kereskedelmi célra, így az első gondolatom az volt, hogy tanulmányozzam a korlátot, és megpróbáljam kikerülni.
[Fontos pontosítás: a cikkben szereplő anyagok kizárólag tájékoztatási és oktatási célokat szolgálnak. A szerző nem ösztönzi ezek kereskedelmi célú felhasználását.]
Tanulmányozzuk a problémát
Nálunk van: tíz oldalszámozással ellátott profil helyett a keresés csak hármat ad vissza, ezután beszúrásra kerül egy prémium fiók „ajánlásával” ellátott blokk, alatta pedig homályos és nem kattintható profilok.
A kéz azonnal a fejlesztői konzol felé nyúl, hogy megnézze ezeket a rejtett profilokat – talán eltávolíthatunk néhány elmosódó stílust, vagy információt nyerhetünk ki a jelölés egy blokkjából. De várhatóan ezek a profilok igazságosak helyőrző képek és semmilyen információ nem kerül tárolásra.
Rendben, most nézzük meg a Hálózat lapot, és ellenőrizzük, hogy a csak három profilt visszaadó alternatív keresési eredmények valóban működnek-e. Megtaláljuk a minket érdeklő kérést a „/api/search/blended”-re, és megnézzük a választ.
A profilok `included` tömbben érkeznek, de már 15 entitás van benne. Ebben az esetben az első három objektum további információkkal, minden objektum egy adott profilra vonatkozó információkat tartalmaz (például, hogy a profil prémium minőségű-e ).
A következő 12 valódi profil - keresési eredmények, amelyek közül csak hármat fogunk látni. Amint azt már sejtheti, csak azokat mutatja, akik további információkat kapnak (az első három objektum). Például, ha korlátlanul veszi a választ egy profilból, akkor 28 entitást kap – 10 objektumot további kiegészítőkkel. információk és 18 profil.
Válasz a profilra korlátozás nélkül
Miért érkezik 10-nél több profil, pedig pontosan 10-et kérnek, és ezek semmilyen módon nem vesznek részt a megjelenítésben, még a következő oldalon sem lesznek - még nem tudom. Ha elemzi a kérés URL-címét, láthatja, hogy count=10 (hány profilt kell visszaadni a válaszban, maximum 49).
Örömmel fogadok bármilyen észrevételt ez ügyben.
Kísérletezzünk
Oké, a legfontosabb dolog, amit most biztosan tudunk, az az, hogy több profil van a válaszban, mint amennyit mutatnak nekünk. Ez azt jelenti, hogy a korlátozás ellenére több adathoz juthatunk. Próbáljuk meg magunk lehúzni az API-t közvetlenül a konzolról, a fetch segítségével.
Ahogy az várható volt, 403-as hibát kapunk. Ez a biztonság miatt van, itt nem küldünk CSRF tokent (CSRF a Wikipédián. Dióhéjban, minden kéréshez egyedi token kerül hozzáadásra, amelynek hitelességét a szerver ellenőrzi).
Bármilyen más sikeres kérésből vagy cookie-kból másolható, ahol a „JSESSIONID” mezőben tárolódik.
Hol található a tokenEgy másik kérés fejléce:
Vagy cookie-kból, közvetlenül a konzolon keresztül:
Próbáljuk újra, ezúttal a fetch-nek adjuk át a beállításokat, amiben a fejlécben paraméterként adjuk meg a csrf-tokenünket.
Siker, megkapjuk mind a 10 profilt. :tada:
A fejlécek eltérése miatt a válasz szerkezete némileg eltér az eredeti kérésben kapotttól. Ugyanezt a struktúrát kaphatja meg, ha az objektumunkhoz a csrf token mellé hozzáadja az „Accept: ’application/vnd.linkedin.normalized+json+2.1” elemet. Példa válasz hozzáadott fejléccel
Ezután szerkesztheti (manuálisan vagy automatizálva) a `start` paramétert az indexre mutatva, amitől kezdve 10 profilt (alap = 0) kapunk a teljes keresési eredményből. Vagyis minden kérés után 10-zel növelve a szokásos oldalankénti kimenetet kapjuk, egyszerre 10 profilt.
Ebben a szakaszban elegendő adatom és szabadságom volt ahhoz, hogy folytassam a kisállat-projekten való munkát. De bűn lett volna, ha nem próbáljuk meg közvetlenül a helyszínen megjeleníteni ezeket az adatokat, hiszen az már kéznél volt. Nem térünk ki az Emberre, amelyet az elején használnak. A jQuery csatlakozott az oldalhoz, és az alapvető szintaxis ismereteit a memóriában kiásva néhány perc alatt elkészítheti a következőket.
jQuery kódot
/* рендер блока, принимаем данные профиля и вставляем блок в список профилей используя эти данные */
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="/hu/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="/hu/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>`
);
};
// дергаем апи, получаем данные и рендерим профили
const fetchProfiles = () => {
// токен
const csrf = 'ajax:9082932176494192209';
// объект с настройками запроса, передаем токен
const settings = { headers: { 'csrf-token': csrf } }
// урл запроса, с динамическим индексом старта в конце
const url = `https://www.linkedin.com/voyager/api/search/blended?count=10&filters=List(geoRegion-%3Ejp%3A0,network-%3ES,resultType-%3EPEOPLE)&origin=FACETED_SEARCH&q=all&queryContext=List(spellCorrectionEnabled-%3Etrue,relatedSearchesEnabled-%3Etrue)&start=${nextItemIndex}`;
/* делаем запрос, для каждого профиля в ответе вызываем рендер блока, и после инкрементируем стартовый индекс на 10 */
fetch(url, settings).then(response => response.json()).then(data => {
data.elements[0].elements.forEach(createProfileBlock);
nextItemIndex += 10;
});
};
// удаляем все профили из списка
$('.search-results__list').find('li').remove();
// вставляем кнопку загрузки профилей
$('.search-results__list').after('<button id="load-more">Load More</button>');
// добавляем функционал на кнопку
$('#load-more').addClass('artdeco-button').on('click', fetchProfiles);
// ставим по умолчания индекс профиля для запроса
window.nextItemIndex = 0;
Ha ezt közvetlenül a konzolban, a keresőoldalon teszi meg, a rendszer hozzáad egy gombot, amely minden kattintással 10 új profilt tölt be, és megjeleníti azokat egy listában. Természetesen, mielőtt ezt megtenné, módosítsa a tokent és az URL-t a szükségesre. A profilblokk tartalmazza a nevet, pozíciót, helyet, a profilra mutató hivatkozást és egy helyőrző képet.
Következtetés
Így minimális erőfeszítéssel meg tudtuk találni a gyenge pontot, és korlátozás nélkül visszanyertük keresésünket. Elég volt elemezni az adatokat és annak útját, belenézni magába a kérésbe.
Nem mondhatom, hogy ez komoly probléma a LinkedIn számára, mert nem jelent semmilyen veszélyt. Az ilyen „megkerülő megoldások” miatt a maximális kiesett nyereség, amely lehetővé teszi a prémium fizetésének elkerülését. Lehet, hogy egy ilyen szerverreakció szükséges a webhely más részeinek megfelelő működéséhez, vagy egyszerűen a fejlesztők lustasága és az erőforrások hiánya nem teszi lehetővé a megfelelő végrehajtást. (A korlátozás 2015 januárjában jelent meg; előtte nem volt korlát).
PS
Természetesen a jQuery kód meglehetősen primitív példa a képességekre. Jelenleg az igényeimnek megfelelő böngészőbővítményt készítettem. Vezérlőgombokat ad hozzá, és teljes profilokat jelenít meg képekkel, meghívógombbal és általános kapcsolatokkal. Ráadásul dinamikusan gyűjti a szűrőket a helyszínekre, cégekre és egyéb dolgokra, és lekéri a tokent a cookie-kból. Így már nem kell semmit keményen kódolni. Nos, további beállítási mezőket ad hozzá, például „hány profilt kérhet egyszerre, legfeljebb 49-et”.
Még mindig dolgozom ezen a kiegészítésen, és azt tervezem, hogy nyilvánosságra hozom. Írj ha érdekel.