Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Lispmeetup #56 Common lispによるwebスクレイピング技法

533 views

Published on

lispmeetup #56 Common lispによるwebスクレイピング技法

Published in: Engineering
  • Be the first to comment

  • Be the first to like this

Lispmeetup #56 Common lispによるwebスクレイピング技法

  1. 1. COMMON LISPによる WEBスクレイピング技法 SATOSHI IMAI Created: 2017-09-25 Mon 19:26
  2. 2. 1 世はまさにビッグデータ解析時代 データをどう集めるかが問題 自前のデータを集めるのは大変 Web上に公開されているデータを半自動的に収集する ロボットを作る 日本の著作権法ではデータ解析目的の複製はOK サイトのルート直下にあるrobots.txtに従おう アクセス頻度は常識的な範囲で
  3. 3. 2 WEBスクレイピングとは Webをクローリングし、必要な情報を切り出すことでデータ を収集すること APIが用意されているものは素直に使おう Twitter、FacebookなどはOAuth認証が必要
  4. 4. 3 WEBスクレイピングに必要なもの HTTPクライアント dexador、drakma HTML/XMLパーサ plump CSSセレクタ clss OAuth認証 (TwitterなどのAPIを使う場合) cl-oauth
  5. 5. 4 日経新聞から現在の日経平均株価 を取得 (ql:quickload :dexador) (ql:quickload :plump) (ql:quickload :clss) (ql:quickload :cl-ppcre) (defparameter article-html (dex:get "http://www.nikkei.com/markets/kabu/")) (defparameter parse-tree (plump:parse article-html)) (defparameter sub-tree (aref (clss:select "span.mkc-stock_prices" parse-tree) 0)) (print (plump:text (aref (plump:children sub-tree) 0)))
  6. 6. 4.1 同じことをPYTHONでやろうとすると import urllib.request from bs4 import BeautifulSoup url = "http://www.nikkei.com/markets/kabu/" response = urllib.request.urlopen(url) data = response.read() soup = BeautifulSoup(data, "html.parser") span = soup.find_all("span") nikkei_heikin = "" for tag in span: try: string_ = tag.get("class").pop(0) if string_ in "mkc-stock_prices": nikkei_heikin = tag.string break except: pass print(nikkei_heikin)
  7. 7. 5 ロイターの記事から本文を取得 (defparameter article-html (dex:get "http://jp.reuters.com/article/idJPL3N0U325520141219")) (defparameter body-class (aref (nth-value 1 (ppcre:scan-to-strings "(ArticleBody_body_.*?)"" article-html)) 0)) (defparameter parse-tree (plump:parse article-html)) (defparameter sub-tree (aref (clss:select (format nil ".~A" body-class) parse-tree) 0)) (defun node-text (node) (flet ((cat (strs) (reduce (lambda (s1 s2) (concatenate 'string s1 s2)) strs))) (let ((text-list nil)) (plump:traverse node (lambda (node) (push (plump:text node) text-list)) :test #'plump:text-node-p) (cat (nreverse text-list))))) (print (node-text sub-tree))
  8. 8. 6 連番でない画像を上から順番にダ ウンロード 連番ならこうすればいい wget http://example.com/H1000{00..99}.JPG 連番でなく、ページの特定の場所にあるような画像ならパ ースが必要 例: http://logofaves.com/
  9. 9. 6.1 連番でない画像を上から順番にダウンロー ド(2) .boxesクラスの部分木を取ってきて、さらにIMGタグを探し、 URLでフィルタをかける (defparameter article-html (dex:get "http://logofaves.com/")) (defparameter parse-tree (plump:parse article-html)) (defparameter sub-trees (clss:select "img" (aref (clss:select ".boxes" parse-tree) 0))) (defparameter urls (remove-if-not (lambda (url) (cl-ppcre:scan "^http://logofaves.com/wp-content/uploads/" url)) (map 'list (lambda (node) (gethash "src" (plump:attributes node))) sub-trees))) (loop for i from 0 for url in urls do (dex:fetch url (format nil "/tmp/logo-~3,'0d.jpg" i)))
  10. 10. 7 APIから収集 cl-oauthを使ってTwitterのAPIから取得する
  11. 11. 8 CL-OAUTHでOAUTH1.0認証 認証の流れ コンシューマトークンを作る それを認証サーバに送りリクエストトークンを取得する 認証用URLにアクセス、ユーザアカウントでログイン コールバックURLにGETパラメータ付きでリダイレクトされ る アクセストークンを作る
  12. 12. 9 コールバックURLに指定するために NINGLEでサーバを立てる ningleは軽量ウェブアプリケーションの一つ ページは単なるLispの関数 ここでアクセストークンを設定する
  13. 13. 10 CL-OAUTH越しにTWITTER APIにア クセスする JSONデータが得られるのでcl-jsonでパース ツイートやユーザLispの構造体に入れる
  14. 14. 11 おわり ありがとうございました

×