
GASでのHTML取得を作ってはみたものの、なんだか挙動が怪しい。
たまに、取得できなかったり、スピードが異常に遅かったり・・・
安定した運用ができないと判断して、とりあえず、会社で使っているサーバーの余っている部分を利用して、
簡単なAPIシステムを作って見ることにした。
APIの肝はセキュリティ
誰でも利用できるAPIは便利ですが、世の中のAPIは、ユーザー登録して、セキュリティコードを発行して、トークン管理やシグネチャコード処理な度を行いセキュリティを担保します。
今回のクローリング専用APIなので、URLを送ったら、サイトの静的HTMLを返すだけの処理を行うようにします。
でも、セキュリティは舐めてはいけないので、以下のようなシグネチャ構成をとることにしました。
シグネチャ
セキュリティコードと、API問い合わせ日時と、API問い合わせをするユーザー(クライアント)に発行したセキュリティコードをSHA256でエンコードして、
Base64パッキングします。
出来上がったコードをAPI側で、5分以内の問い合わせ + エンコードされたシグネチャコードの判定処理を行い、無事にセキュリティコード判定ができれば、まずは処理スルーさせるようにします。
判定がNGになった場合は、その場でエラーを返します。
PHPによるクローリング処理
PHPによるクローリング処理は極めてシンプルです。
以下のコードで手軽に行うことができるんですね。
class Crawl{
public $data = null;
public static function get_html($url = null){
if(!$url){return;}
$html = file_get_contents($url);
return $html;
}
}
呼び出し側
上記のclassをrequireしておいて、以下のコードでHTMLが取得できます。
$html = Crawl::get_html($_POST["url"]);
取得したhtmlをechoするだけでOKです。
CORS対応
そもそも、なんでこんなめんどくさいことをしているのかというと、
Javascript側から、別ドメインのWebページのHTMLを取得するのが、基本的に、CORSセキュリティに引っかかってできないので、
自分のサーバーであれば、CORS制限を解除することができるので、PHP側でHTMLを取得してしまおうという話なのである。
なので、サーバーの Nginx の設定に以下を追加するのを忘れないようにしましょう。
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' '*' always;
※Apacheやそれ以外のWebサーバーソフトを使っている場合は、それぞれのCORS対応を調べて設定してください。
クライアント側のJS
最後に、クライアント側で、以下のコードでHTMLを取得することが可能になります。
const html = new Php().init()
export class Php{
constructor(){
super()
}
async init(){
const body = {
url: this.amazon_url,
}
this.body = JSON.stringify(body);
this.timestamp = new Date().toISOString();
return await this.send()
}
get setting(){
return {
endpoint: "クロールAPIサーバーのURL",
secret_key: "@your secret-key"
}
}
async createSignature() {
const encoder = new TextEncoder();
const key = await crypto.subtle.importKey(
"raw",
encoder.encode(this.setting.secret_key),
{ name: "HMAC", hash: "SHA-256" },
false,
["sign"]
);
const signature = await crypto.subtle.sign(
"HMAC",
key,
encoder.encode(this.timestamp + "\n" + this.body)
);
return Array.from(new Uint8Array(signature))
.map(b => b.toString(16).padStart(2, "0"))
.join("");
}
async send() {
const signature = await this.createSignature();
const headers = {
"Content-Type": "application/json",
"X-TIMESTAMP": this.timestamp,
"X-SIGNATURE": signature
};
const response = await fetch(this.setting.endpoint, {
method: "POST",
headers,
body: this.body
});
return await response.json();
}
}
node系のjsで呼び出したいときは、cryptモジュールをincludeしてお使いください。
Github
GitHubに、プロジェクトを掲載しておくので、独自でAPI連携したいと思う人は、参考にしてみてください。
https://github.com/yugeta/crawl
あとがき
今回構築したクロールAPIを使って、無事に、Amazonの商品リンクを再構築することができました。
ブログなどで使いたい人は、ひとまず以下のURLで公開しているので、お試しください。
https://yugeta.github.io/amazon_affiliate_link_maker/src/
GoogleChromeの機能拡張は、少し仕事の時間の余裕ができたら、再構築に取り掛かりたいと思います。
0 件のコメント:
コメントを投稿