備忘録ついでに書いておきます。
無料で簡単にJSONを返してくれるAPIを作りたかったので、GAS(Google Apps Script)を利用してみました。全体的な流れとしては、weblioの英和辞書で、検索した単語の意味一覧をJSONで返すAPIを作り、それをローカルのJSから取得します。ライブラリは使いたくなかったのでaxiosなどは使用していません。
#GASでスクレイピング
まずはGASへアクセスして新規プロジェクトを立ち上げましょう。そして、スクレイピングするために「Parser」というライブラリを導入します。「ライブラリの追加」から、スクリプトIDに「1Mc8BthYthXx6CoIz90-JiSzSafVnT6U3t0z_W3hLTAX5ek4w0G_EIrNw」で検索して追加することができます。
次に、スクレイピングする対象であるweblioの構造を見ていきます。
まず、URLに注目するとhttps://ejje.weblio.jp/content/(単語名)
で、調べたい単語の意味一覧にに飛べるようです。
また、ページのソースを見ると、<div class=level0>
のタグの中に意味が格納されていることが分かりました。
構造が大体わかったので、実際にスクレイピングしてみます。
function doGet(e) {
// スクレイピング対象のurlを定義
let url = `https://ejje.weblio.jp/content/${e.parameter.word}`;
// HTMLの取得
let html = UrlFetchApp.fetch(url).getContentText();
// 要素の抽出
let data = Parser.data(html)
.from('<div class=level0>')
.to('</div>')
.iterate();
}
${e.parameter}
でGETリクエスト時のパラメータを受け渡すことができます。渡す際はURLの末尾に?word=(検索したい単語)
を追加してアクセスします。
html要素の抽出はUrlFetchApp.fetch(url).getContentText();
で行い、同一のタグが複数ある場合はParser.data(html).from(タグ名開始).to(タグ名終了).iterate()
で配列にまとめることができます。
#スクレイピングしたデータをJSONにして返す
前項のdata
ではまだ、不要なタグや配列の形式のままになっているので、正規表現で不要部分を削除する作業と、データを後で扱いやすいようにするためにオブジェクト形式にしてキーを追加する作業を行いたいと思います。
まずは正規表現を使ってタグを消し、リストにまとめていきます。
const dataList = []
for (const content in data) {
dataList.push(data[content].replace(/<("[^"]*"|'[^']*'|[^'">])*>/g,''));
}
次に、dataListをオブジェクトにして一つずつキーを追加していきます。
const newDataList = dataList.map((word, key) => ({key, word}));
最後に、JSON形式に変換して返します。
const json_data = JSON.stringify(newDataList);
return ContentService.createTextOutput(json_data).setMimeType(ContentService.MimeType.JSON);
保存したら「新しいデプロイ」から「ウェブアプリ」を選択し、アクセスできるユーザーを「全員」にして保存してください。
すると、このようなURLが発行されます。
コピーして末尾に?word=english
を追加して飛んでみます。
無事、「english」の意味だけ抽出されました!(品詞名のノイズが入っていますが…)
#Javascriptから取得してみる
意味を抽出してJSONを返してくれるAPIは完成したので、今度はローカルのJSからフェッチしてみます。※下ではReactを使用していますが、関数部分は生のjsでも同じはずです
const [answerList, setAnswerList] = useState([]);
const [word, onChangeWord] = useState('');
const url = 'https://script.google.com/macros/s/xxxxx/exec';
// urlに検索したい単語の文字列を追加してjsonをフェッチする
const fetchAnswer = async () => {
const submitUrl = url + '?word=' + word;
return fetch(submitUrl)
.then(res => res.json());
}
// 検索ボタンを押したときにfetchAnswer関数を実行し、リストに入れる
const onPressFetch = () => {
(async() => {
setAnswerList(await fetchAnswer());
})();
}
// 省略
<View>
<Input onChangeText={onChangeWord}
value={word}
/>
<Button title="検索"
onPress={onPressFetch}
/>
</View>
Inputに入力された文字をパラメータとしてGASに渡し、GASが返却したJSONをfetchAnswerでフェッチしています。フェッチしたものをリストに入れて良い感じに表示すると下のようになりました!