【GAS】ChatGPTAPIを使ってHTMLを解析してスクレイピングする

当サイトではアフィリエイト広告を利用して商品を紹介しています。

1度だけスクレイピングをすればよいページ群があり、年代によってページの作りが違うサイトが有りました。

その構造にいちいちコードを修正をして対応をするのも手間なので、ならばHTMLを渡して、ChatGPTに解析結果を出してもらえばよいのでは?
と思いついたので実際にやってみました。

もちろんレスポンスに時間がかかりますしChatGPTにリクエストをするたびに、料金がかかるので多用するのはおすすめはできませんが、テクニックの1つとしてはありだと思いました。

ポイント
  • JSON形式で返すように指定する
  • 時々別の形で返してくるので、サンプルの出力を間に挟むことで、出力を固定させる

ChatGPTを扱うコード

※APIのキーは事前に取得してください


/**
 * ChatGPT インスタンスを作成する
 * @param {string} model - 使用するモデルの指定(デフォルトは "gpt-3.5-turbo")
 * @returns {object} ChatGPT - 作成された ChatGPT インスタンス
 */
function createChatGptInstance(model = "gpt-3.5-turbo") {
  const apiKey = getApiKey();
  return new ChatGPT(apiKey, model);
}

/**
 * ChatGPT クラス
 * Note: https://platform.openai.com/docs/api-reference/introduction
 * Note: https://platform.openai.com/docs/models/overview
 */
class ChatGPT {
  /**
   * ChatGPT のコンストラクタ
   * @param {string} [apiKey] - OpenAI API キー(省略可能)
   */
  constructor(apiKey = getApiKey(), model = "gpt-3.5-turbo") {
    this.apiKey = apiKey;
    this.model = model
  }

  /**
   * プロンプトに対する応答を生成する
   * @param {string} prompt - プロンプト
   * @returns {string} 生成されたテキスト
   */
  generate(prompt) {
    const url = "https://api.openai.com/v1/chat/completions"; // URLをChatGPT APIのエンドポイントに変更
    const messages = [{ 'role': 'user', 'content': prompt }]; // プロンプトをメッセージ形式に変換
    const options = {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "Authorization": `Bearer ${this.apiKey}`,
      },
      payload: JSON.stringify({
        model: this.model, // モデルをgpt-3.5-turboに変更
        messages: messages, // メッセージをpayloadに追加
        max_tokens: 4096,
        temperature: 0.8,
      }),
    };

    const response = UrlFetchApp.fetch(url, options);
    const data = JSON.parse(response.getContentText());
    const generatedText = data.choices[0].message.content.trim(); // APIレスポンスから生成されたテキストを取得

    return generatedText;
  }
  /**
   * プロンプトに対する応答を生成する
   * @param {string} prompt - プロンプト
   * @returns {string} 生成されたテキスト
   */
  generateFromMsgObj(massageObject) {
    if (!Array.isArray(massageObject)) {
      throw new Error("Expected 'massageObject' to be an array of message objects");
    }

    const url = "https://api.openai.com/v1/chat/completions"; // URLをChatGPT APIのエンドポイントに変更
    const messages = massageObject; // プロンプトをメッセージ形式に変換
    const options = {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "Authorization": `Bearer ${this.apiKey}`,
      },
      payload: JSON.stringify({
        model: this.model, // モデルをgpt-3.5-turboに変更
        messages: messages, // メッセージをpayloadに追加
        max_tokens: 1000,
        temperature: 0.8,
      }),
    };

    const response = UrlFetchApp.fetch(url, options);
    const data = JSON.parse(response.getContentText());
    const generatedText = data.choices[0].message.content.trim(); // APIレスポンスから生成されたテキストを取得

    return generatedText;
  }

}

/**
 * プロパティストアから API キーを取得する
 * @returns {string} 取得した API キー
 */
function getApiKey() {
  const scriptProperties = PropertiesService.getScriptProperties();
  return scriptProperties.getProperty("OPENAI_API_KEY");
}

呼び出し側のコード(プロンプト)

function testGpt() {

  const chatGpt = ChatGPT.createChatGptInstance()

  const text = `***ここに解析するHTMLを入力***`
  const prompt = [
    {
      "role": "system",
      "content": `
あなたは、HTMlを解析するJSの関数です
 オブジェクト または false 以外の文字列を返しません。

■命令
HTMLを解析してください。

名前 userName ※投稿者のこともあります。ユーザーの名前です
ステータス status
結果 result 


■レスポンス オブジェクト ※複数ある場合は配列にする。 [{},{},{}・・・]
{

  userName	:
  status	: 
  result	: 

}
`
    },
    {
      "role": "user",
      "content": `レスポンスのサンプルを出力してください。`
    },
    {
      "role": "assistant",
      "content": `[
    {
  userName	: "hoge",
  status	: "ok",
  result	: "ok"
    },
    {
  userName	: "hoge",
  status	: "ok",
  result	: "ok"
    }
  ]`
    },
    {
      "role": "user",
      "content": "レスポンスは完璧です。以下のHTMLも前回と同様にレスポンスを返してください。" + text
    }
  ]
  const result = chatGpt.generateFromMsgObj(prompt)
  console.log(chatGpt.generateFromMsgObj(prompt))
  return result

}