この記事は [クローラー/Webスクレイピング Advent Calendar 2015] の一つとして書きました。
公開遅いけど。ごめんね
この記事の目標
curl コマンドの使い方を覚えつつ、スクレイピングをやっていきます。
この記事で紹介すること
- curl
- curl + grep
- curl -s
- curl + md5sum
- curl + md5sum + mail
- curl + cookie
- curl + cookie + xpath
- curl + xpath + xpath
- シェルスクリプト実行
用意するもの
知っておくと便利な知識
- css2
- css3
- xpath
- jq
js への対応
基本方針は「JSに対応しない」
だって、リクエストヘッダ見てたらわかるもん。
curl コマンドでWEBページを取得する
スクレーパをするまえに curl コマンドを紹介します。
curl コマンドは libcurl をコマンドライン使うものです。 curl コマンドはコンパイルオプション次第で http2 / scp / ssh / ftp などほとんどのファイル転送に対応可能です。 おもにHTTPdサーバー への アクセスするのに使います。
curl コマンドを覚えよう
curl コマンドの基本
curl http://qiita.com
curl コマンドで HTTP HEADを見る
curl -I http://qiita.com
curl コマンドでHTTP 302/301 に追従する
curl -L http://qiita.com
curl で特定のデータを保存する
curl -L http://qiita.com > out.html
ファイルを保存
curl http://cdn.qiita.com/assets/siteid-reverse-9b38e297bbd020380feed99b444c6202.png > out.png
URLのファイル名で保存
curl -O https://i.gyazo.com/f609d81c30b580c9015a890643ecc604.png
サーバーとのやりとりを詳細に表示
curl -v -L http://qiita.com > out.html
進捗率の代わりにプログレスバーを表示
curl -# -O URL
プログレスバーを一切非表示
curl -s URL
これくらいを覚えておけば、ほとんどの場合に対応できます。
なぜcurl なのか?
スクレーパーなのになぜcurl のお話をしているのかというと、スクレイピングを作る上で curl は不可欠なツールなのです。
欲しいコンテンツがメインディシュとしたら、ブラウザはレストラン。プログラム言語はコンビニ、curl は「お箸・フォーク」です。美味しくいただくために不可欠なツールです。ちなみに xpathは取り皿=食器ですね。
curl を用いたスクレイピング
curl+ grep でサイトの情報を取り出す。
基本中の基本です。
curl https://qiita.com | grep title
しかし結果が、、汚い・・・美しくない。
takuya@~/Desktop$ curl -s https://qiita.com | grep '<title>(.+)</title>' 1:<!DOCTYPE html><html xmlns:og="http://ogp.me/ns#"><head><meta charset="UTF-8" /><title>Qiita - プログラマの技術情報共有サービス</title><meta content="width=device-width,initial-scale=1" name="viewport" /><meta content="Qiitaは、プログラマのための技術情報共有サービスです。 プログラミングに関するTips、ノウハウ、メモを簡単に記録 &amp; 公開することができます。" name="description" /><meta content="summary" name="twitter:card" /><meta content="@Qiita" name="t(いかりゃく
curl + grep でサイトの情報を綺麗に取り出す
grep -o オプションを使う
curl https://qiita.com | grep -o '<title>(.+)</title>'
結果はほら綺麗。
$ curl -s https://qiita.com | grep -o '<title>(.+)</title>' <title>Qiita - プログラマの技術情報共有サービス</title>
curl + m5sum
取得した内容をmd5sum にかける
curl -s http://takuya-1st.hatenablog.jp/entries/2015/12/11 | md5sum
これにより取得した内容が同じかどうか検出が可能になる。
脚注 last-modified や e-tag を使うべきなんだろうが、昔から糞みたいなブログ実装が多くて304 Not Modified を返さないサイトが多すぎるんですよ。むかしから妙竹林の代表例はCA
curl + md5sum + mail
サイトに更新があったら通知する。シェルスクリプト
curl + md5sum で更新監視なら、3分で書けるよ。カップ麺待ってる間にできちゃうね。
url="http://localhost/" digest=`curl -s $url | md5sum ` while true ; do current=`curl -s $url | md5sum ` if [[ $digest != $current ]] ; then echo changed!! sendmail ほげほげ digest=$current fi sleep 1 done
サイトが変化したら、MD5の結果が変わるので、その結果を見つけて通知します。
これだと毎秒見に行ってます。むかしブログでJRの運行情報を取得した話を書いた時に「30秒に1度は病的なアクセス頻度」と言われたことがある。クローラーを避けたい管理者はキャッシュを正しく扱ってください。クローラーは違法行為でも攻撃でもありません。「Last-modified-since/ If-none-match」に正しく応答してください。HTTPのキャッシュすら扱えないSI'erはWEB案件にくんな。毎分クローラーを走らせたくらいで攻撃だとメール送ってくる関西電力あんたのことだ。おっと。
ユーザーエージェントを変更する
いくつかのサイトは、ユーザーエージェントによる識別をしているので、私のブラウザの代理をcurl にやらせるので、ユーザーエージェントをブラウザに合わせておく
curl --user-agent "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.48 Safari/537.36" http://www.yahoo.co.jp/
ブラウザのリクエストをCurlでやる
curl にはいろいろと便利な機能があります。 基本的にhttp リクエストは curl で作成できます。
例えば、ブラウザのリクエストと全く同じリクエストを再現するにはChromeの開発ツールでcURLとしてコピーすればとても簡単です。
chrome からコピーしてきてシェルに貼り付け
ChromeからcURL コマンドとしてコピーしてシェルに貼り付けたら「簡単に」リクエストを再現できる。
Cookieやヘッダもそのまま埋まってくるので、スクレーパー作る時は、Chromeのコピーから始めると便利。
curl でCookieの取り扱い
curl でcookieを永続したいです。
WEBページにアクセスするにはほとんどの場合、Cookieによって識別されます。
cookie 保存には -c オプション
curl -c ${保存したいパス} http://www.yahoo.co.jp
Cookieの再利用 には -b オプション
curl -b ${保存済みパス} http://auctions.yahoo.co.jp/
Cookieを前回のセッションから再利用しつつ、次回のために保存
curl -b path -c path http://auctions.yahoo.co.jp/
オプションの -b -c を同時に使います。ファイル名は同じで構いません
注意:path に同じものを記述するかといって省略することはできません。
curl -bc path http://auctions.yahoo.co.jp/ ## これはできない。Cookie使えない
これで、Cookieの問題を気にせずに扱えるようになります。
期限なしのセッションクッキーも保存されます。
オプション -c を使えばsession-cookie も問題なく保存されます。
もし保存したくない時は -j をつけてください。
注意:期限なしとは期限の設定がされてないCookieのことです。「期限なし」を長期間Cookie(通称:永続Cookie)と勘違いしそうですが、期限設定なし=セッションCookie=ページを閉じるまで有効=Windowを閉じるまでです。(=タブを閉じただけでは消えない)
Cookieをどこから取り出すのか。
でも、Form送信してCookie作るのめんどくさい。
Cookieは前述のChrome開発ツールの右クリックから取り出すほか、Chromeのユーザープロファイルから取り出すこととができます。
わたしはChromeからコマンドで取り出すことが多いです。
https://github.com/takuya/chrome-storage
chrome-cookie .yahoo.co.jp | jq .
本題のスクレイピングです。
さてさて、それでは準備も整ったしスクレイピングを始めていきたいと思います。
ここまでで
という武器を一通り揃えました。
スクレイピングするときにもう一つ不可欠な武器があります。それがlibxmlです。
最後の武器 libxml
スクレイピングをする時に欠かせない最終兵器がlibxml です。
libxml に添付のxpath 用コマンドでページ要素を取得
grep では絶対に足りなくなるので、 libxml でXMLを解析が必要です。
HTML も XML として解釈してもらえるのでlibxml はスクレイピングには欠かせない。
ruby nokogiri や python lxml なんかそうですね。
libxml はコマンドからも使えるのです。
libxmlのxmllintコマンドでxpath を実行する
xmllint コマンドではxpath を実行できます。便利!
xmllint --xpath "//nodename" sample.xml
インストール
sudo apt install libxml2-utils
xmllint コマンドでhtml を扱う
xmllint で html を扱うにはhtml オプションをつけます
xmllint --html --xpath "//head/title" sample.html
タイプ量が面倒なので xpath でalias しておきます。
alias xpath="xmllint --html --xpath 2>/dev/null"
エラーメッセージのゴミ箱行きは、まぁ説明のためです。 xpath の基本構文はあとで詳しく書くとして、xpath でどんどんページを取っていきます。
xpath とcurl コマンドと組み合わせて戦います。
curl -s 'http://www.yahoo.co.jp/' | xpath "//head/title" -
3つの武器が揃った
スクレイピングに欠かせない、3種の神器をcurl + libxml で整えました。
処理 | コマンド | |
---|---|---|
ファイル取得 | curl | |
cookie 取り扱い | curl -b path -c path | |
HTML 解析 | xmllint --html --xpath |
それではスクレイピング処理をします。
前置き長すぎ。疲れた。
連続ページ取得をしていきたいと思います。
例えば、yahoo オークションの検索結果ページからリンクを全て抜き出すには
curl -s -L http://j.mp/1YC5mSM | xpath "//h3/a/@href" -
この結果それぞれに対して、ページの詳細を取得して保存する。
curl -s -L http://j.mp/1YC5mSM | xpath "//h3/a/@href" -
さらにxargs で展開して
取得したhref の一覧を、さらにxargs で展開して詳細ページにアクセスします。
curl -s -L http://j.mp/1YC5mSM |xpath "//h3/a/@href" - ¥ | sed 's/href=//g'¥ | sed 's/"//g' |¥ xargs -P0 -d ' ' -I@ curl -v -O -L @
間に挟まるsed が邪魔なので
自作のxpath 関数に書き変えます。
git clone git@gist.github.com:894c5aeabc620344bcea.git cd 894c5aeabc620344bcea cp xpath /usr/local/bin/ chmod +x /usr/local/bin/xpath
さらに省略化
curl -s -L http://j.mp/1YC5mSM | xpath "//h3/a/@href" | xpath "//h1/text()"
curl とxpath ぱぱっとデータ取得
anemone つかえって話なんだろうけど。
selenium ドライバ使えばいいんだろうけど。
ページの解析もシェルでてきた方がタイプ量少なくて便利だよね!!!
もう少し続くんじゃ。
続き→curl+xpath から始めるお手軽スクレイピング(2) - それマグで!
関連資料
grep でマッチした部分だけを取り出す http://takuya-1st.hatenablog.jp/entry/20121112/1352750670
xpath コマンド http://takuya-1st.hatenablog.jp/entry/2014/08/24/031832
2021-11-28
apt install libxml2-utils を追記