LoginSignup
7

More than 5 years have passed since last update.

Common Lisp入門してwebスクレイピングやろうとしてる

Last updated at Posted at 2017-12-17

この記事はwebスクレイピング Advent Calendar 2017 18日目の記事です。

モチベーション

wgetの記事書こうと思ったけど他所のアドベントカレンダーでネタ被りしたので急遽変更。
気になってたCommon Lispを使ってスクレイピングをやってみようとおもう。
環境はmacOSで。

Common Lisp導入

こちらの記事(いまから始めるCommon Lisp)を参照

mac OSでCommon Lispやるときはroswellを入れればいいらしい

$ brew install roswell

セットアップ

$ ros setup

これで対話型インタプリタ(REPL)が使えるようになる

$ ros run

*印に変わったら成功

HTTPクライアント

pythonでいうとrequestsとかurllibにあたる
どうやらこちらもdexadorとdrakmaの二大流派
common lispのパッケージはql:quickloadでロードできる

  • dexador
* (ql:quickload :dexador)

とりあえずこれでHTMLをgetでとってこよう

* (dex:get "https://ja.wikipedia.org/wiki/Common_Lisp")

実行結果

~~~ 略 ~~~
        <script>(window.RLQ=window.RLQ||[]).push(function(){mw.config.set({\"wgPageParseReport\":{\"limitreport\":{\"cputime\":\"0.284\",\"walltime\":\"0.327\",\"ppvisitednodes\":{\"value\":5364,\"limit\":1000000},\"ppgeneratednodes\":{\"value\":0,\"limit\":1500000},\"postexpandincludesize\":{\"value\":80208,\"limit\":2097152},\"templateargumentsize\":{\"value\":9196,\"limit\":2097152},\"expansiondepth\":{\"value\":11,\"limit\":40},\"expensivefunctioncount\":{\"value\":2,\"limit\":500},\"entityaccesscount\":{\"value\":1,\"limit\":400},\"timingprofile\":[\"100.00%  209.440      1 -total\",\" 17.69%   37.051      3 Template:Navbox\",\" 16.89%   35.370      1 Template:Infobox_プログラミング言語\",\" 15.10%   31.618      1 Template:Infobox\",\" 13.08%   27.391    319 Template:Lang\",\"  8.88%   18.598      1 Template:Normdaten\",\"  7.89%   16.516      1 Template:プログラミング言語一覧\",\"  7.47%   15.654      1 Template:LISP系言語\",\"  7.07%   14.817      1 Template:Wikibookslang\",\"  5.88%   12.322      1 Template:Sister\"]},\"scribunto\":{\"limitreport-timeusage\":{\"value\":\"0.027\",\"limit\":\"10.000\"},\"limitreport-memusage\":{\"value\":1454412,\"limit\":52428800}},\"cachereport\":{\"origin\":\"mw1299\",\"timestamp\":\"20171211105149\",\"ttl\":1900800,\"transientcontent\":false}}});});</script><script>(window.RLQ=window.RLQ||[]).push(function(){mw.config.set({\"wgBackendResponseTime\":95,\"wgHostname\":\"mw1326\"});});</script>
    </body>
</html>
"
200
#<HASH-TABLE :TEST EQUAL :COUNT 25 {1004CC8A53}>
#<QURI.URI.HTTP:URI-HTTPS https://ja.wikipedia.org/wiki/Common_Lisp>
#<CL+SSL::SSL-STREAM for #<FD-STREAM for "socket 192.168.100.104:49730, peer: 198.35.26.96:443" {10040C6563}>>

なぜかダブルクウォートの横にバックスラッシュが入ってる。なんやこれ

  • drakma
* (ql:quickload :drakma)

こちらはhttp-requestを使う

* (drakma:http-request "https://ja.wikipedia.org/wiki/Common_Lisp")

実行結果

        <script>(window.RLQ=window.RLQ||[]).push(function(){mw.config.set({\"wgPageParseReport\":{\"limitreport\":{\"cputime\":\"0.284\",\"walltime\":\"0.327\",\"ppvisitednodes\":{\"value\":5364,\"limit\":1000000},\"ppgeneratednodes\":{\"value\":0,\"limit\":1500000},\"postexpandincludesize\":{\"value\":80208,\"limit\":2097152},\"templateargumentsize\":{\"value\":9196,\"limit\":2097152},\"expansiondepth\":{\"value\":11,\"limit\":40},\"expensivefunctioncount\":{\"value\":2,\"limit\":500},\"entityaccesscount\":{\"value\":1,\"limit\":400},\"timingprofile\":[\"100.00%  209.440      1 -total\",\" 17.69%   37.051      3 Template:Navbox\",\" 16.89%   35.370      1 Template:Infobox_プログラミング言語\",\" 15.10%   31.618      1 Template:Infobox\",\" 13.08%   27.391    319 Template:Lang\",\"  8.88%   18.598      1 Template:Normdaten\",\"  7.89%   16.516      1 Template:プログラミング言語一覧\",\"  7.47%   15.654      1 Template:LISP系言語\",\"  7.07%   14.817      1 Template:Wikibookslang\",\"  5.88%   12.322      1 Template:Sister\"]},\"scribunto\":{\"limitreport-timeusage\":{\"value\":\"0.027\",\"limit\":\"10.000\"},\"limitreport-memusage\":{\"value\":1454412,\"limit\":52428800}},\"cachereport\":{\"origin\":\"mw1299\",\"timestamp\":\"20171211105149\",\"ttl\":1900800,\"transientcontent\":false}}});});</script><script>(window.RLQ=window.RLQ||[]).push(function(){mw.config.set({\"wgBackendResponseTime\":95,\"wgHostname\":\"mw1326\"});});</script>
    </body>
</html>
"
200
((:DATE . "Sun, 17 Dec 2017 18:22:39 GMT")
 (:CONTENT-TYPE . "text/html; charset=UTF-8") (:CONTENT-LENGTH . "155338")
 (:CONNECTION . "close") (:SERVER . "mw1258.eqiad.wmnet")
 (:VARY . "Accept-Encoding,Cookie,Authorization")
 (:X-POWERED-BY . "HHVM/3.18.6-dev")
 (:P3P
  . "CP=\"This is not a P3P policy! See https://ja.wikipedia.org/wiki/%E7%89%B9%E5%88%A5:CentralAutoLogin/P3P for more info.\"")
 (:X-CONTENT-TYPE-OPTIONS . "nosniff") (:CONTENT-LANGUAGE . "ja")
 (:X-UA-COMPATIBLE . "IE=Edge")
 (:LINK
  . "</static/images/project-logos/jawiki.png>;rel=preload;as=image;media=not all and (min-resolution: 1.5dppx),</static/images/project-logos/jawiki-1.5x.png>;rel=preload;as=image;media=(min-resolution: 1.5dppx) and (max-resolution: 1.999999dppx),</static/images/project-logos/jawiki-2x.png>;rel=preload;as=image;media=(min-resolution: 2dppx)")
 (:LAST-MODIFIED . "Mon, 11 Dec 2017 10:47:05 GMT")
 (:BACKEND-TIMING . "D=104736 t=1513272634846516")
 (:X-VARNISH
  . "946126485 499974105, 450452950, 293262949 167365522, 672744697 669126420")
 (:VIA . "1.1 varnish-v4, 1.1 varnish-v4, 1.1 varnish-v4, 1.1 varnish-v4")
 (:AGE . "142534")
 (:X-CACHE . "cp1052 hit/1, cp2007 pass, cp4032 hit/6, cp4029 hit/3")
 (:X-CACHE-STATUS . "hit-front")
 (:STRICT-TRANSPORT-SECURITY . "max-age=106384710; includeSubDomains; preload")
 (:SET-COOKIE
  . "WMF-Last-Access=17-Dec-2017;Path=/;HttpOnly;secure;Expires=Thu, 18 Jan 2018 12:00:00 GMT,WMF-Last-Access-Global=17-Dec-2017;Path=/;Domain=.wikipedia.org;HttpOnly;secure;Expires=Thu, 18 Jan 2018 12:00:00 GMT,GeoIP=JP:::35.69:139.69:v4; Path=/; secure; Domain=.wikipedia.org")
 (:X-ANALYTICS . "ns=0;page_id=172200;https=1;nocookies=1")
 (:X-CLIENT-IP . "111.239.64.212")
 (:CACHE-CONTROL . "private, s-maxage=0, max-age=0, must-revalidate")
 (:ACCEPT-RANGES . "bytes"))
#<PURI:URI https://ja.wikipedia.org/wiki/Common_Lisp>
#<FLEXI-STREAMS:FLEXI-IO-STREAM {100254B403}>
T
"OK"

こっちはやたら値が返ってきてるけど、やっぱりダブルクウォートの前にバックスラッシュがある。なんかもやっとするので消したいなあ。

取得したHTMLを変数に入れる

* (defvar *source* (drakma:http-request "https://ja.wikipedia.org/wiki/Common_Lisp"))

dexadorのほうは処理が終わらなかった。原因不明。

HTMLパーサー

plumpとclssを使う

  • plump
* (ql:quickload :plump)
* (ql:quickload :clss)
* (defvar *parse* (plump:parse *source*))
* *parse*

#<PLUMP-DOM:ROOT {1004B7FEF3}>

これでbeautifulSoupみたいにHTMLの中を解析できるようになる

  • clss

clss:selectを使ってparseからタイトルを抜き出してみよう

* (clss:select "title" *parse*)

#(#<PLUMP-DOM:ELEMENT title {10020211B3}>) 

これだとステータスが返ってきてるだけなので、書き方を変えなければいけない

(plump:text (car (coerce (clss:select "title" *parse*) 'list)))

"Common Lisp - Wikipedia"

coerceは値をlistに型変換してる。carはlistの一番目の要素を取得する。
最後にplump:textをかけてやるとタイトルを取得できる。

所感

スクレイピングはpythonでいいんじゃないかな

参考:
http://blog.ryoana.com/entry/2016/12/30/004941
http://d.hatena.ne.jp/masatoi/20170203/1486121334

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7