API を利用して LinkedIn の検索制限を回避する

制限

LinkedIn にはそのような制限があります - 商用利用制限。 あなたも私と同じように、つい最近までそれに触れたことも聞いたこともなかった可能性が非常に高いです。

API を利用して LinkedIn の検索制限を回避する

制限の本質は、連絡先以外の人の検索をあまりにも頻繁に使用すると (正確な指標はありません。アルゴリズムは、ユーザーのアクション (検索の頻度と量、検索、ユーザーの追加) に基づいて決定します)、検索結果がプロファイルは 1000 ではなく 100 に制限されます (デフォルトは 10 ページ、ページごとに XNUMX プロファイル)。 制限は毎月初めにリセットされます。 当然、 プレミアムアカウントにはこの制限はありません.

しかし、少し前に、私は得意なプロジェクトのために LinkedIn 検索を頻繁に使い始めたところ、突然この制限が発生しました。 当然のことながら、私はこれをあまり好きではありませんでした。なぜなら、私はこれを商業目的で使用していなかったので、最初に考えたのは、この制限を調べて、それを回避しようとすることでした。

[重要な説明: この記事の資料は情報提供および教育目的のみに提供されています。 作者は商業目的での使用を推奨しません。]

私たちはその問題を研究しています

ページネーションのある XNUMX 個のプロファイルの代わりに、検索では XNUMX 個だけが返されます。その後、プレミアム アカウントの「推奨」を含むブロックが挿入され、その下にはぼやけてクリックできないプロファイルが表示されます。

すぐに開発者コンソールに手が伸びて、これらの隠されたプロファイルを確認します。おそらく、ぼやけたスタイルを削除したり、マークアップのブロックから情報を抽出したりできるでしょう。 しかし、予想通り、これらのプロファイルは単なる プレースホルダーの写真 そして情報は保存されません。

API を利用して LinkedIn の検索制限を回避する

それでは、[ネットワーク] タブを見て、XNUMX つのプロファイルのみを返す代替検索結果が実際に機能するかどうかを確認してみましょう。 「/api/search/blended」で関心のあるリクエストを見つけて、その応答を確認します。

API を利用して LinkedIn の検索制限を回避する

プロファイルは「含まれる」配列で提供されますが、その中にはすでに 15 個のエンティティが含まれています。この場合、最初の XNUMX つは追加情報を持つオブジェクトであり、各オブジェクトには特定のプロファイルに関する情報 (たとえば、プロファイルがプレミアムかどうかなど) が含まれています。 )。

API を利用して LinkedIn の検索制限を回避する

次の 12 は実際のプロフィール、つまり検索結果であり、そのうち 28 つだけが表示されます。 すでにご想像のとおり、追加情報を受け取る人 (最初の 10 つのオブジェクト) のみが表示されます。 たとえば、制限なしでプロファイルから回答を取得すると、18 個のエンティティ (追加で XNUMX 個のオブジェクト) を受け取ります。 情報とXNUMXのプロフィール。

プロフィールに対する無制限の回答API を利用して LinkedIn の検索制限を回避する
API を利用して LinkedIn の検索制限を回避する

正確に 10 個が要求されているにもかかわらず、なぜ 10 個を超えるプロファイルが到着し、表示にまったく関与せず、次のページでも表示に参加しないのかは、まだわかりません。 リクエスト URL を分析すると、count=10 (応答で返されるプロファイルの数、最大 49) であることがわかります。

API を利用して LinkedIn の検索制限を回避する

この件に関してコメントをいただければ幸いです。

実験してみましょう

さて、私たちが今確かに知っている最も重要なことは、応答には表示されているよりも多くのプロファイルが含まれているということです。 これは、制限にもかかわらず、より多くのデータを取得できることを意味します。 fetch を使用して、コンソールから直接 API を自分で取得してみましょう。

API を利用して LinkedIn の検索制限を回避する

予想通り、エラー 403 が発生します。これはセキュリティによるもので、ここでは CSRF トークンを送信しません (ウィキペディアのCSRF。 簡単に言うと、一意のトークンが各リクエストに追加され、サーバー上で信頼性がチェックされます。

API を利用して LinkedIn の検索制限を回避する

これは、他の成功したリクエストまたは Cookie からコピーでき、「JSESSIONID」フィールドに保存されます。

トークンを見つける場所別のリクエストのヘッダー:

API を利用して LinkedIn の検索制限を回避する

または、コンソールから直接 Cookie から:

API を利用して LinkedIn の検索制限を回避する

もう一度試してみましょう。今回はフェッチする設定を渡します。ヘッダー内のパラメーターとして csrf-token を指定します。

API を利用して LinkedIn の検索制限を回避する

成功しました。10 個のプロファイルをすべて受け取りました。 :ただ:

ヘッダーの違いにより、応答の構造は元の要求で受信したものと若干異なります。 オブジェクトの csrf トークンの隣に「Accept: 'application/vnd.linkedin.normalized+json+2.1'」を追加すると、同じ構造を取得できます。
ヘッダーを追加した応答の例API を利用して LinkedIn の検索制限を回避する

Accept ヘッダーの詳細

次は何ですか?

次に、検索結果全体から 10 個のプロファイル (デフォルト = 0) が与えられるインデックスを指す「start」パラメータを編集 (手動または自動) することができます。 つまり、リクエストごとに 10 ずつ増やすことで、通常のページごとの出力を一度に 10 個のプロファイルで取得できます。

この段階では、私には重要なプロジェクトに取り組み続けるのに十分なデータと自由がありました。 しかし、このデータはすでに手元にあるので、その場ですぐに表示しようとしないのは罪でした。 フロントで使用されている Ember については説明しません。 jQuery がサイトに接続され、基本的な構文の知識をメモリから掘り出したので、数分で次の内容を作成できます。

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="/ja/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="/ja/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;

これを検索ページのコンソールで直接実行すると、クリックするたびに 10 個の新しいプロファイルを読み込み、リストに表示するボタンが追加されます。 もちろん、これを行う前に、トークンと URL を必要なものに変更してください。 プロフィール ブロックには、名前、位置、場所、プロフィールへのリンク、およびプレースホルダー画像が含まれます。

API を利用して LinkedIn の検索制限を回避する

まとめ

したがって、最小限の努力で弱点を見つけ、制限なく探索を取り戻すことができました。 データとそのパスを分析し、リクエスト自体を調べるだけで十分でした。

これが LinkedIn にとって深刻な問題であるとは言えません。脅威となるものではないからです。 最大は、保険料の支払いを回避できる「回避策」による利益の損失です。 おそらく、そのようなサーバーの応答は、サイトの他の部分が正しく動作するために必要であるか、単に開発者の怠惰とリソースの不足によって適切に動作できない可能性があります。 (この制限は 2015 年 XNUMX 月に登場しました。それ以前は制限はありませんでした)。

PS

当然のことながら、jQuery コードは機能のかなり原始的な例です。 現時点では、ニーズに合わせてブラウザ拡張機能を作成しました。 コントロール ボタンを追加し、写真、招待ボタン、一般的な接続を含む完全なプロファイルをレンダリングします。 さらに、場所、会社、その他のフィルターを動的に収集し、Cookie からトークンを取得します。 したがって、何もハードコードする必要はもうありません。 それは、「一度にリクエストするプロファイルの数、最大 49」などの追加の設定フィールドを追加します。

API を利用して LinkedIn の検索制限を回避する

私はまだこの追加作業を行っており、一般公開する予定です。 興味があれば書いてください。

出所: habr.com

コメントを追加します