title: ピクシブの小説ランキングをスクレイピングする
author: Amane Katagiri
summary: 法律用語満載5000兆トントラック
date: 2017-05-27T15:43:00+09:00
modified: 2017-05-29T13:45:00+09:00
category: tech
license: CC BY 4.0
rating: sfw
ai_summary: この記事は、pixivの小説R-18ウィークリーランキングを対象に、curlやxmllintなどのシェルコマンドを用いてスクレイピングを行う方法を解説しています。ログイン時のクッキー管理や隠しパラメータの抽出、取得したデータのMarkdown形式への整形といった一連の手順を具体的に紹介。認証が必要なサイトをコマンドラインツールのみで操作する、実践的なスクレイピングの練習工程をまとめています。
ai_keywords: スクレイピング, pixiv, curl, シェルコマンド, ログイン認証, クッキー, xmllint, R-18, ランキング取得, Markdown

[TOC]

2017年になってもインターネットはなかなか消えないので、たまにはスクレイピングの練習をしたいと思います。

どういうものがいいでしょうかね。練習ですから、ある程度複雑なサイト……例えば、認証が必要なサイトがいいですね。

というわけで、今回は[pixiv](https://www.pixiv.net/)の[小説 R-18ウィークリーランキング](https://www.pixiv.net/novel/ranking.php?mode=weekly_r18)をスクレイピングしてみようと思います。

# ログインする

ランキングページを表示するためには[ログイン](https://accounts.pixiv.net/login)が必要です。今日は[curl](https://curl.haxx.se/)を使ってやってみましょう。

curlは受け取ったcookieをファイルに書いたり、ファイルから読み込んだcookieを送信したりできます。まず、`-c`オプションを使って、ログインに必要なセッションを取得しましょう。

```shell
curl -c cookie.txt https://accounts.pixiv.net/login > login.html
```

`cookie.txt`の中は下のような感じで、受け取ったcookieが記録されていることがわかります。

```text
# 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](http://xmlsoft.org/xmllint.html)がない人は、適当に[Beautiful Soup](https://www.crummy.com/software/BeautifulSoup/)や[nokogiri](http://www.nokogiri.org/)でも使ってください。nkfがなければ手や好きなスクリプト言語でどうぞ。

```shell
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を保存します。

```shell
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件取得してみましょう。

```shell
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の表形式にしてみましょう。

```shell
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
```

結果はこう。

```markdown
| 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の調子が悪そうなのでやめました。

# おわりに

人生経験豊富な法律用語満載アカウントになりたい。人生経験豊富な法律用語満載アカウントになりたいよ……どうやればあんな風にカッコよく自分のルールを話せるようになれるのか……教えてよ……。

おわりです。今日の完成品は[こちら](https://gist.github.com/amane-katagiri/7dce3d9627c1cb53583b1d5d32efd02b)。動かす前にfishを入れてください。
