クローラーを実行するときに、このような問題に遭遇することがよくあります。
WebサイトのデータはAjaxを介して読み込まれますが、Ajaxインターフェースは暗号化されているため、手間をかけずにクラックすることはできません。このとき、たとえば、クラッキングデータとグラブデータをバイパスする場合は、Seleniumを使用する必要があります。Seleniumは、クリックのシミュレーションやページめくりなどの操作を実行できますが、Ajaxデータを取得するのは簡単ではありません。データは、レンダリングされたHTMLから抽出されます。とても面倒です。
おそらくあなたは自分で考えます:私がSeleniumを使用してページを駆動し、同時にAjaxによって要求されたデータを保存できたとしたら。
当然、たとえば、エージェントのレイヤーを追加する方法があります。リアルタイム処理にはmitmdumpを使用するだけです。
しかし、エージェントがいない場合、良い方法はありませんか?
ここでは、Ajaxフックと呼ばれるツールを紹介します。Ajaxリクエストが発生する限り、Ajaxによって要求されたすべてのデータをインターセプトし、リクエストとレスポンスをインターセプトして、Ajaxデータのリアルタイム処理を実現できます。 。
アヤックスフック
フックは誰にとっても見知らぬ人ではないので、ここでは説明しません。理解できない場合は、「フックテクノロジー」で検索すると、いくつかの情報を見つけることができます。
次に、Ajaxフックは、その名前が示すように、フックAjaxリクエストです。Ajaxの2つの最も重要な部分は何ですか。もちろん、それはリクエストとレスポンスです。フックを使用すると、リクエストを開始する前とレスポンスを取得した後の両方を処理できます。
図に基本的なアクションポイントを示します。
では、フックAjaxリクエストをどのように作成するのでしょうか。次に、当然、Ajaxのネイティブ実装に深く入り込む必要があります。Ajaxは、実際にはXMLHttpRequestオブジェクトを使用して実装されています。Ajaxのリクエストとレスポンスをフックするために、実際には、send、onreadystatechangeなどの一部の属性に対して何らかの処理を行っています。
面倒そうに聞こえますが、心配しないでください。誰かがすでにこれを書いており、直接使用しています。GitHubアドレスはhttps://github.com/wendux/Ajax-hookです。
実際、内部実装の原則は非常に単純ですが、実際には簡単に触れただけです。詳しく理解したい場合は、https://www.jianshu.com/p/7337ac624b8eの記事をご覧ください。
わかりました、これをどのように使用しますか?
Ajax-hookの作成者は2つの主要なメソッドを提供します。1つはプロキシであり、もう1つはフックです。これらはすべてHook XMLHttpRequestによって機能します。
ここに公式の紹介があります:
プロキシメソッドとフックメソッドの両方を使用して、グローバルXMLHttpRequestをインターセプトできます。これらの違いは、フックのインターセプトの粒度が細かいことです。これは、XMLHttpRequestオブジェクトの特定のメソッド、属性、およびコールバックに固有である場合がありますが、使用するのがより面倒です。多くの場合、ビジネスロジックをコールバック間で分散させる必要があるだけでなく、エラーが発生しやすくなります。プロキシは高度な抽象化を備えており、リクエストコンテキストを構築します。リクエスト情報の設定は、各コールバックで直接取得できるため、使用がより簡単で効率的です。
ほとんどの場合、プロキシメソッドがニーズを満たさない場合を除き、プロキシメソッドを使用することをお勧めします。
次に、プロキシメソッドの使用方法を見てみましょう。その使用方法は次のとおりです。
proxy ({
//请求发起前进入
onRequest: (config, handler) => {
console.log(config.url)
handler.next(config);
},
//请求发生错误时进入,比如超时;注意,不包括http状态码错误,如404仍然会认为请求成功
onError: (err, handler) => {
console.log(err.type)
handler.next(err)
},
//请求成功后进入
onResponse: (response, handler) => {
console.log(response.response)
handler.next(response)
}
})
Ajaxフックがレプリケーションの3つのメソッドを提供していることは明らかです。onRequest、onResponse、onErrorは、リクエストが開始される前の処理、リクエストが成功した後の処理、エラーが発生したときの処理です。
次に、データクロールを実行する場合は、実際にはResponseの結果をインターセプトすることになります。実際には、onResponseメソッドを実装するのが適切です。
詳しく見てみましょう。このonResponseメソッドは、応答オブジェクトとハンドラオブジェクトの2つのパラメータを受け取ります。これらはすべて、Ajaxフックによってカプセル化されます。実際には、応答本文などの応答のコンテンツのみを使用する必要があります。印刷するには、実際にはAjaxで得られた結果を印刷します。
OK、それでは試してみましょう。
事例紹介
私の場合を考えてみましょう。リンクは次のとおりです:https://dynamic2.scrape.center/、インターフェースは次のとおりです:
このWebサイトは映画データのWebサイトです。データはAjaxを介してロードされますが、これらのAjaxリクエストは、図に示すように、暗号化されたパラメータートークンを伝送します。
実際、このパラメータを解決することは難しくありませんが、少し時間がかかります。
次に、図に示すように、Ajaxの戻り結果を確認します。
とてもピュアでクリア!したがって、Ajax応答を取得するときにこれらのデータを直接取得できれば、それは良いことです。
実行する方法?当然、前述のAjaxフックが使用されます。
それでは、このAjaxフックを使用して、これらのデータをリアルタイムで処理してみましょう。
実際の運用
まず第一に、最初のステップは、Ajaxフックを使用できるようにする必要があることです。このAjaxフックライブラリを導入する必要があるに違いありません。ブラウザでこのページを導入するにはどうすればよいですか?
JavaScript、Tampermonkey、Seleniumなどをコピーするなど、多くの答えがあります。
ここでは最も簡単な方法を使用します。Seleniumは自動的にAjaxフックのソースコードを実行します。
現時点では、Ajax-hookのソースコードを見つける必要があります。GitHubに移動して見つけてください。リンクは次のとおりです。https://raw.githubusercontent.com/wendux/Ajax-hook/master/dist/ajaxhook.min.js 、写真が示すように:
ほら、コードの量は本当に少ないです。
このコードをコピーして、Webサイトhttps://dynamic2.scrape.center/のコンソールに貼り付けます。
この時点で、Ajaxフックを表すahオブジェクトを取得し、その中でプロキシメソッドを使用できます。
どうやって使うのですか?onResponseメソッドを直接実装し、Responseの結果を出力するだけです。実装は次のとおりです。
ah.proxy({
//请求成功后进入
onResponse: (response, handler) => {
if (response.config.url.startsWith('/api/movie')) {
console.log(response.response)
handler.next(response)
}
}
})
このコードをコンソールに挿入して実行します。現時点では、Ajax応答のフックを実装しています。Ajaxリクエストがある限り、応答の結果が出力されます。
この時点でクリックしてページをめくり、新しいAjaxリクエストをトリガーすると、図に示すように、コンソールがResponseの結果を出力することがわかります。
さて、これでAjaxデータを取得できます。
データ転送
これでデータがブラウザに表示されました。どのように保存すればよいですか?
保存するのは簡単ではありません。最も簡単な方法は、このデータを独自のインターフェースの1つに転送して保存することです。
次に、Flaskを使用してインターフェイスを作成します。クロスドメイン制限を解除することを忘れないでください。実装は次のとおりです。
import json
from flask import Flask, request, jsonify
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
@app.route('/receiver/movie', methods=['POST'])
def receive():
content = json.loads(request.data)
print(content)
# to something
return jsonify({'status': True})
if __name__ == '__main__':
app.run(host='0.0.0.0', port=80, debug=True)
ここでは簡単な例を書きました。POSTリクエストを受信できるAPIを書きました。アドレスは/ receiver / movieで、POSTデータを出力して応答を返します。
もちろん、ここでは、データの切り取りやデータベースへの保存など、さまざまな操作を実行できます。
さて、サーバーが利用可能になったので、Ajaxフック側でデータを送信しましょう。
ここでは、ライブラリアドレスがhttps://unpkg.com/[email protected]/dist/axios.min.jsであるaxiosライブラリを使用します。これは、ブラウザーで実行したときにも使用できます。
axiosを導入した後、以前のプロキシメソッドを次のように変更しました。
ah.proxy({
//请求成功后进入
onResponse: (response, handler) => {
if (response.config.url.startsWith('/api/movie')) {
axios.post('http://localhost/receiver/movie', {
url: window.location.href,
data: response.response
})
console.log(response.response)
handler.next(response)
}
}
})
実際、ここではaxiosのpostメソッドを呼び出し、現在のURLと応答データをサーバーに送信します。
これまでは、各Ajaxリクエストの応答結果がこのFlaskサーバーに送信され、Flaskサーバーがそれを格納して処理します。
オートメーション
これで、Ajaxインターセプトとデータ転送を実現できるようになりました。最後のステップは、当然、クロールを自動化することです。
自動化は3つの部分に分かれています。
- ウェブサイトを開く
- Ajaxフック、axios、およびプロキシのコードを挿入します。
- 次のページを自動的にクリックしてページをめくります。
最も重要なのは2番目のステップです。Ajax-hook、axios、およびプロキシのコードを今すぐhook.jsファイルに入れ、Seleniumのexecute_scriptで実行します。
他の手順は非常に簡単で、最終的な実装は次のとおりです。
from selenium import webdriver
import time
browser = webdriver.Chrome()
browser.get('https://dynamic2.scrape.center/')
browser.execute_script(open('hook.js').read())
time.sleep(2)
for index in range(10):
print('current page', index)
btn_next = browser.find_element_by_css_selector('.btn-next')
btn_next.click()
time.sleep(2)
最後に、それを実行します。
ブラウザーが最初にページを開き、次に次のページをクリックするシミュレーションを行った後、Flask Server側を観察して戻ったことがわかります。図に示すように、Ajaxデータが受信されていることがわかります。
OK、それだけです。
総括する
この時点で、以下が完了しています。
- Ajax応答フック
- データの転送と受信
- ブラウザの自動化
将来同じような状況に遭遇しても、同じように対処することができます。
このセクションのコード:https://github.com/Python3WebSpider/AjaxHookSpider。