Korlát
A LinkedIn-en van egy ilyen korlátozás — . Nagy valószínűséggel, te is, mint én nemrég, soha nem találkoztál vele, és nem hallottál róla.

A korlátozás lényege, hogy ha túlságosan gyakran keresel embereket a kapcsolataidon kívül (nincsenek pontos metrikák, ezt az algoritmus dönti el a te lépéseid alapján - mennyire gyakran és sokat kerestél, adtál hozzá embereket), akkor a keresési eredmény három profillal lesz korlátozva, a 1000 helyett (alapértelmezetten 100 oldal, 10 profil egy oldalon). A korlátozás minden hónap elején visszaállításra kerül. Természetesen, .
De nem olyan régen, egy kis projekt miatt, elkezdtem sokat kísérletezni a LinkedIn kereséssel, és hirtelen megkaptam ezt a korlátozást. Természetesen, ez nem tetszett, mert nem használtam kereskedelmi célokra, ezért az első gondolatom az volt, hogy megértem a korlátozást és megpróbálom megkerülni.
[Fontos pontosítás - a cikkben található anyagok kizárólag tájékoztató és oktatási célokat szolgálnak. A szerző nem bátorítja azok kereskedelmi célú felhasználását.]
A probléma tanulmányozása
Van: a tíz profillal ellátott lapozás helyett a keresés csak hármat ad ki, utánuk megjelenik egy blokk a prémium fiók "ajánlásával", és alatta elmosódott és nem kattintható profilok találhatók.
Azonnal nyúlok a fejlesztői konzolhoz, hogy megnézzem ezeket a rejtett profilokat - lehet, hogy el tudunk távolítani néhány stílust, ami a homályt okozza, vagy információt tudunk kinyerni a blokk elemből a kódolásban. De, ahogy várható volt, ezek a profilok csupán és semmilyen információt nem tárolnak.

Jó, most nézzük a Hálózat fülre, és ellenőrizzük, hogy valóban működik-e az alternatív keresési eredmény, amely csak három profilt ad vissza. Megkeressük az általunk érdeklő kérdést a “/api/search/blended”-t és megnézzük a választ.

A profilok az `included` tömbben érkeznek, de abban összesen 15 entitás van. Itt az első három közülük - objektumok további információkkal, minden objektum tartalmaz információt egy konkrét profilról (például, hogy prémium profil-e).

A következő 12 valódi profil — keresési eredmények, amelyekből csak hármat fognak bemutatni. Ahogy azt már sejthetjük, csak azokat mutatja, akikről kiegészítő információ érkezik (az első három objektum). Például, ha a korlátlan profil válaszát vesszük, akkor 28 entitás érkezik — 10 objektum kiegészítő információkkal és 18 profil.
Válasz korlátlan profilhoz

Miért jön több mint 10 profil, miközben pontosan 10-et kérünk, és ezek semmilyen módon nem vesznek részt a megjelenítésben, még a következő oldalon sem — egyelőre nem tudom. Ha elemezzük a kérés URL-jét, láthatjuk, hogy count=10 (hány profilt kell visszaadni a válaszban, maximum 49).
Örömmel várom a megjegyzéseket ezzel kapcsolatban.
Kísérletezünk
Jól van, a legfontosabb, hogy most már pontosan tudjuk — a válaszban több profil érkezik, mint amennyit mutatnak. Ezért több adatot is kinyerhetünk, függetlenül a korláttól. Próbáljuk meg közvetlenül az API-t hívni, a konzol segítségével, fetch útján.

Várhatóan hibaüzenetet kapunk, 403. Ez a biztonsággal kapcsolatos, itt nem küldjük el a CSRF tokent (. Ha röviden összefoglaljuk — minden kéréshez egyedi tokent adnak hozzá, amelyet a szerver az érvényesség ellenőrzésére használ).

Ezt bármely más sikeres kérésből másolhatod, vagy a sütikből, ahol a ‘JSESSIONID’ mezőben tárolják.
Hol található a tokenEgy másik kérés fejléc:

Vagy a sütikből, közvetlenül a konzolon keresztül:

Próbáljuk meg ismét, ezúttal a fetch-be beállítjuk a paramétereket, amelyekben megadjuk a csf-tokenünket a fejlécben.

Siker, mind a 10 profilt megkapjuk. :tada:
A fejlécek közötti eltérés miatt a válasz struktúrája kissé eltér attól, ami az eredeti kérésben érkezik. Az ‘Accept: ‘application/vnd.linkedin.normalized+json+2.1’ fejléc hozzáadásával hasonló struktúrát kaphatunk, a csrf token mellett.
Példa válasz a hozzáadott fejléccel
Mi következik?
Ezután szerkeszthetjük (kézzel vagy automatizálva) a `start` paramétert, amely megadja azt az indexet, ahonnan 10 profilt kapunk (alapértelmezett = 0) az összes keresési eredményből. Más szóval, ha minden kérés után 10-tel növeljük, akkor normál lapozott megjelenítést kapunk, 10 profil egyszerre.
Ez a szakasz elegendő adatot és szabadságot adott ahhoz, hogy folytassam a munkát a pet-projectemen. De bűn lett volna nem kipróbálni, hogy ezeket az adatokat közvetlenül a helyszínen jelenítsük meg, mivel kéznél voltak. Az Ember, amelyet a frontend használ, nem lesz a téma. Az oldalon jQuery volt beillesztve, és az alapvető szintaxis tudásomat felidézve pár perc alatt létrehozható a következő.
jQuery kód
/* рендер блока, принимаем данные профиля и вставляем блок в список профилей используя эти данные */
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>`
);
};
// hívjuk az API-t, lekérjük az adatokat és megjelenítjük a profilokat
const fetchProfiles = () => {
// token
const csrf = 'ajax:9082932176494192209';
// a kérés beállításainak objektuma, átadjuk a tokent
const settings = { headers: { 'csrf-token': csrf } }
// a kérés URL-je, dinamikus kezdő indexszel a végén
const url = `https://www.linkedin.com/voyager/api/search/blended?count=10&filters=List(geoRegion-jp0,network-S,resultType-PEOPLE)&origin=FACETED_SEARCH&q=all&queryContext=List(spellCorrectionEnabled-true,relatedSearchesEnabled-true)&start=${nextItemIndex}`;
/* kérés indítása, minden válaszban kapott profil esetén meghívjuk a blokk megjelenítést, majd növeljük a kezdő indexet 10-el */
fetch(url, settings).then(response => response.json()).then(data => {
data.elements[0].elements.forEach(createProfileBlock);
nextItemIndex += 10;
});
};
// eltávolítjuk az összes profilt a listából
$('.search-results__list').find('li').remove();
// beillesztjük a profilok betöltésének gombját
$('.search-results__list').after('<button id="load-more">Több betöltése</button>');
// funkció hozzáadása a gombhoz
$('#load-more').addClass('artdeco-button').on('click', fetchProfiles);
// alapértelmezett profil index beállítása a lekérdezéshez
window.nextItemIndex = 0;
Ha ezt közvetlenül a keresőoldal konzoljában futtatjuk, akkor ez hozzáad egy gombot, amely minden egyes kattintásra 10 új profilt tölt be, és ezek listázásra kerülnek. Természetesen a tokent és az url-t előtte kell módosítani a szükségesre. A profil blokk tartalmazni fogja a nevet, pozíciót, helyszínt, profil linket és egy helyettesítő képet.

Zárás
Így a minimális erőfeszítéssel sikerült megtalálni a sebezhető pontot és visszaszerezni a korlátok nélküli keresést. Csak elemezni kellett az adatokat és azok útját, belenézni magába a kérésbe.
Nem mondhatom, hogy ez komoly probléma lenne a LinkedIn számára, mivel nem jelent fenyegetést. Legfeljebb ez egy elveszett nyereség az ilyen "körbejárások" miatt, amely lehetővé teszi a prémium díj megfizetése nélküli hozzáférést. Lehet, hogy egy ilyen szerver válasz szükséges a weboldal más elemeinek helyes működéséhez, vagy egyszerűen a fejlesztők lustasága, amely a megfelelő erőforrások hiányához vezetett. (A korlátozás 2015 januárjában jelent meg, addig nem volt limit.)
P.S.
Természetesen a jQuery kód egy meglehetősen primitív példa a lehetőségekről. Jelenleg egy böngésző kiegészítőt hoztam létre a saját igényeimnek megfelelően. Ez hozzáad ellenőrzési gombokat, és teljes profilt renderel képekkel, meghívó gombbal és közös kapcsolatokkal. Ráadásul dinamikusan összegyűjti a helyszínek, cégek és egyéb szűrőket, kinyeri a tokent a sütiből. Így már semmit sem kell hardkodolni. Továbbá további beállítási mezőket is hozzáad, például "hány profilt kérjünk egyszerre, legfeljebb 49".

Még mindig dolgozom ezen a kiegészítőn, és tervezem, hogy nyilvánosságra hozom. Írj, ha érdekel.
Forrás: habr.com


