それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

curl とxpath でお手軽スクレイピング

この記事は [クローラー/Webスクレイピング Advent Calendar 2015] の一つとして書きました。

公開遅いけど。ごめんね

この記事の目標

curl コマンドの使い方を覚えつつ、スクレイピングをやっていきます。

この記事で紹介すること

用意するもの

知っておくと便利な知識

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;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 + grep -o でそこそこ便利になりますね。

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としてコピーすればとても簡単です。

f:id:takuya_1st:20151225211705p:plain:w500

chrome からコピーしてきてシェルに貼り付け

ChromeからcURL コマンドとしてコピーしてシェルに貼り付けたら「簡単に」リクエストを再現できる。

Cookieやヘッダもそのまま埋まってくるので、スクレーパー作る時は、Chromeのコピーから始めると便利。

curlCookieの取り扱い

curlcookieを永続したいです。

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 でどんどんページを取っていきます。

xpathcurl コマンドと組み合わせて戦います。

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()"

xpathcurl の組み合わせでそこそこ戦える。

curlxpath ぱぱっとデータ取得

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 を追記