2017年になってもインターネットはなかなか消えないので、たまにはスクレイピングの練習をしたいと思います。
どういうものがいいでしょうかね。練習ですから、ある程度複雑なサイト……例えば、認証が必要なサイトがいいですね。
というわけで、今回はpixivの小説 R-18ウィークリーランキングをスクレイピングしてみようと思います。
ログインする
ランキングページを表示するためにはログインが必要です。今日はcurlを使ってやってみましょう。
curlは受け取ったcookieをファイルに書いたり、ファイルから読み込んだcookieを送信したりできます。まず、-c
オプションを使って、ログインに必要なセッションを取得しましょう。
curl -c cookie.txt https://accounts.pixiv.net/login > login.html
cookie.txt
の中は下のような感じで、受け取ったcookieが記録されていることがわかります。
# Netscape HTTP Cookie File
# https://curl.haxx.se/docs/http-cookies.html
# This file was generated by libcurl! Edit at your own risk.
#HttpOnly_.pixiv.net TRUE / FALSE 9999999999 PHPSESSID xxxxx
.pixiv.net TRUE / FALSE 9999999999 p_ab_id xxxxx
.pixiv.net TRUE / FALSE 9999999999 p_ab_id_2 xxxxx
フォームには不正なログインを防止するためのパラメータが付いていたりするので、それも取り出します。xmllintがない人は、適当にBeautiful Soupやnokogiriでも使ってください。nkfがなければ手や好きなスクリプト言語でどうぞ。
xmllint --xpath '//form//input[@type="hidden"]/@name' --html login.html | \
sed -e 's/ name=\("\([^"]*\)"\|\'\([^\']*\)\'\)/\2\3\n/g' | \
nkf -WwMQ | tr "=" "%" > keys.txt
xmllint --xpath '//form//input[@type="hidden"]/@value' --html login.html | \
sed -e 's/ value=\("\([^"]*\)"\|\'\([^\']*\)\'\)/\2\3\n/g' | \
nkf -WwMQ | tr "=" "%" > values.txt
さて。全てのパラメータが揃ったので、IDとパスワードをくっつけて送信しましょう。-b
オプションでさっき保存したcookieを使い、-c
オプションで受け取ったcookieを保存します。
echo "pixiv_id" >> keys.txt
echo "password" >> keys.txt
echo YOUR_PIXIV_ID >> values.txt
echo YOUR_PASSWORD >> values.txt
curl -b cookie.txt -c cookie.txt --data (paste -d "=" keys.txt values.txt | tr "\n" "&") https://accounts.pixiv.net/login
リダイレクトを受け入れる-L
オプションを付けていないため、成功すると無が返ってきます。cookie.txt
にdevice_token
があれば、この章の作業は完了です。
ピクシブの最も不要な機能の1つとして、オプトアウト不可のログイン通知メールがあり、これでも成否が分かります。よかったね。
ページを取得する
ここからは簡単です。全てのリクエストはログインしたユーザーの権限で行うことになります。ウィークリーランキングを上から10件取得してみましょう。
curl -L -b cookie.txt "https://www.pixiv.net/novel/ranking.php?mode=weekly_r18" > r18_weekly_ranking.html
xmllint --xpath '//div[@class="novel-right-contents"]//h1[@class="title"]/a/@href' --html r18_weekly_ranking.html | \
sed -e 's/ href=\("\([^"]*\)"\|\'\([^\']*\)\'\)/\2\3\n/g' | \
sed -e "s#^#http://www.pixiv.net#g" | head -n10 > ranking_urls.txt
xmllint --xpath '//div[@class="novel-right-contents"]//li[@class="author"]/a/@data-user_name' --html r18_weekly_ranking.html | \
sed -e 's/ data-user_name=\("\([^"]*\)"\|\'\([^\']*\)\'\)/\2\3\n/g' | head -n10 ranking_authors.txt
上から10件が気に入らなければ、tailしたりオプションを変えたりしてください。
整形する
記事に掲載しやすいように、Markdownの表形式にしてみましょう。
seq 1 10 > numbers.txt
echo '| ID | 小説のURL | 作者名 |' > table.md
echo '|:- |:- |:- |' >> table.md
paste -d '|' numbers.txt ranking_urls.txt ranking_authors.txt | \
sed -e 's/|/ | /g' | sed -e 's/^/| /g' | sed -e 's/$/ |/g' >> table.md
結果はこう。
| ID | 小説のURL | 作者名 |
|:- |:- |:- |
| 1 | http://www.pixiv.net/novel/show.php?id=8195281 | 祭 |
| 2 | http://www.pixiv.net/novel/show.php?id=8194128 | 茉莉花 |
| 3 | http://www.pixiv.net/novel/show.php?id=8198107 | 夏子 |
| 4 | http://www.pixiv.net/novel/show.php?id=8197609 | みとい |
| 5 | http://www.pixiv.net/novel/show.php?id=8196278 | 斎藤 |
| 6 | http://www.pixiv.net/novel/show.php?id=8195245 | なめこ |
| 7 | http://www.pixiv.net/novel/show.php?id=8196089 | 都 |
| 8 | http://www.pixiv.net/novel/show.php?id=8189511 | Kay |
| 9 | http://www.pixiv.net/novel/show.php?id=8195912 | 香子 |
| 10 | http://www.pixiv.net/novel/show.php?id=8189382 | あき |
使う
ランキングのデータ。記事での仮IDと小説URL、作者名を示す。
ID | 小説のURL | 作者名 |
---|---|---|
1 | http://www.pixiv.net/novel/show.php?id=8195281 | 祭 |
2 | http://www.pixiv.net/novel/show.php?id=8194128 | 茉莉花 |
3 | http://www.pixiv.net/novel/show.php?id=8198107 | 夏子 |
4 | http://www.pixiv.net/novel/show.php?id=8197609 | みとい |
5 | http://www.pixiv.net/novel/show.php?id=8196278 | 斎藤 |
6 | http://www.pixiv.net/novel/show.php?id=8195245 | なめこ |
7 | http://www.pixiv.net/novel/show.php?id=8196089 | 都 |
8 | http://www.pixiv.net/novel/show.php?id=8189511 | Kay |
9 | http://www.pixiv.net/novel/show.php?id=8195912 | 香子 |
10 | http://www.pixiv.net/novel/show.php?id=8189382 | あき |
色々読んで引用しながら感想でも書こうと思ったんですが、なんかpixivの調子が悪そうなのでやめました。
おわりに
人生経験豊富な法律用語満載アカウントになりたい。人生経験豊富な法律用語満載アカウントになりたいよ……どうやればあんな風にカッコよく自分のルールを話せるようになれるのか……教えてよ……。
おわりです。今日の完成品はこちら。動かす前にfishを入れてください。