OCamlでスクレイピングとWebサーバーを開発する手順を書いていきます。
# 開発環境構築
$ brew install opam
$ opam init # コマンド実行時の質問にはすべて「y」を書いてEnter
$ opam install dune
# プロジェクトのディレクトリ作成
$ dune init proj scraping_server
$ cd scraping_server
# 外部パッケージのインストール
$ opam install opium cohttp-lwt-unix cohttp-async tls lambdasoup
$ eval $(opam env)
$ dune init proj scraping_server
を実行後、以下のファイルが作られていることを確認してください。
以下の内容になるように libraries の箇所に追記しましょう。
(executable
(public_name scraping_server)
(name main)
(libraries
scraping_server
opium
cohttp-lwt-unix
cohttp-async
tls
lambdasoup))
インストールしている外部パッケージは以下のものです。
scraping_server/bin/main.ml を以下の内容に書き換えます。
open Opium
let handler _request =
"test"
|> Response.of_plain_text
|> Lwt.return
;;
let _ =
App.empty
|> App.get "/" handler
|> App.run_command
;;
その後、以下のコマンドを実行して http://localhost:3000 にブラウザでアクセスすると、”test” の文字が表示されます。
$ dune exec scraping_server
これで、Webサーバーの起動ができました。
スクレイピングで取得した情報を表示する scraping_server/bin/main.ml に以下の実装を追加します。
open Opium
(* パッケージを追加 *)
open Lwt
open Soup
(* HTMLを取得する関数を追加 *)
let get_html =
let url = Uri.of_string "https://en.wikipedia.org/wiki/List_of_programming_languages" in
Cohttp_lwt_unix.Client.get(url) >>= fun (_resp, body) ->
body |> Cohttp_lwt.Body.to_string
;;
(* HTMLをパースする関数を追加 *)
let extract_items html =
(parse html) $$ ".div-col li"
|> to_list
|> List.fold_left (fun list elem ->
(trimmed_texts elem |> String.concat "") :: list) []
;;
(* スクレイピングする関数を追加 *)
let scraping =
get_html >>= fun html ->
html |> extract_items |> Lwt.return
;;
(* JSONに変換する関数を追加 *)
let convert_to_json list =
list
|> List.map (fun str -> `String str)
|> (fun list -> `List list)
;;
let handler _request =
(* 追加した関数を使用する *)
scraping >>= fun items ->
items
|> convert_to_json
|> Response.of_json
|> Lwt.return
;;
let _ =
App.empty
|> App.get "/" handler
|> App.run_command
;;
追加実装の後、 $ dune exec scraping_server を再実行して http://localhost:3000 にアクセスすると、 Wikipediaのページから取得したプログラミング言語一覧の文字が表示されるようになります。
|>
左側の値を、右側の関数の引数に入れて実行します。
::
左側の値を、右側のリストの先頭に追加します。
;;
コードのトップレベルで式を定義するときの区切り文字として式の終わりに書きます。
>>=
左側に非同期関数、右側に実行結果を引数に受け取る関数を書くことができます。
Lwtのライブラリで用意されている演算子です。
$$
左側にLambdaSoupのnode、右側にCSSセレクターを書くことで、
nodeからCSSセレクターに該当する要素をすべて抽出できます。
LambdaSoupのライブラリで用意されている演算子です。