Quantcast
Browsing Latest Articles All 3 Live
Mark channel Not-Safe-For-Work? (0 votes)
Are you the publisher? or about this channel.
No ratings yet.
Articles:

Pythonによるスクレイピングでニコニコ大百科掲示板を保存してみる

背景

  • ニコニコ大百科の掲示板は一度に30件しか表示できず、ログをまとめて保存する機能もない(よね?)
  • 割と頻繁に削除も入るため、過去の情報をトレースしにくい。

目的

  • 指定した記事の掲示板をスクレイピングし、1レス目から最新レスまでをまとめて取得・保存する。

詳細

  • 記事トップのURLを指定して叩くと全掲示板ログをtxt形式で保存する。ファイル名は「(記事タイトル).log
  • 新規の場合は全取得するが、既に一度保存したものの場合、未取得ID以降のみをターゲットとする。
  • ファイルの結合や一行抜き出しがpythonだけだとめんどいので、一部Bashに任せている。

ソースはこちらから。
https://github.com/we-yu/sb.webscraping

半自動化

  • 都度都度取得しておきたい記事は、以下のようなテキストファイルを用意しておき、usageのコマンドを打つと自動で取得・更新してくれる。
AutoLoadArticleList.txt
# usage
# $ cat AutoLoadArticleList.txt  | grep -vF '#' | xargs -I{} python3 nicopedy_saver.py {}
# Python
https://dic.nicovideo.jp/a/python
# Linux
https://dic.nicovideo.jp/a/linux
# PHP
https://dic.nicovideo.jp/a/php
# メルトリリス
https://dic.nicovideo.jp/a/%E3%83%A1%E3%83%AB%E3%83%88%E3%83%AA%E3%83%AA%E3%82%B9

ニコニコ大百科のPHP問題を解いてみる

ニコニコ大百科のPHPの項目になんか問題があったので解いてみる。

いまいち文意がはっきりしない問題が多いので、そのへんは適当にどうにかしています。
あと問題文の英数字に半角全角が混ざってるのがとてもアレ。

初級編

問1:2つの変数、$val1$val2を、if式を使わずに比較して、大きい値を$largerを格納する式を一行で書いてみてね。

$larger = max($val1, $val2);

ヒントには三項演算子を使えとか書いてあるのだけど、$larger = $val1 > $val2 ? $val1 : $val2;とか書くより普通に標準関数使った方が楽ですね。

問2:改行コードを含む文字列に対し、改行コードに何が含まれているか調べるにはどうしたらよいか答えてね。

echo strpos($text, "\r\n") !== false ? 'CRLF' : ( strpos($text, "\r") !== false ? 'CR' : (strpos($text, "\n") !== false ? 'LF' :'無い'));

なんか題が意図しているものと違う気がしてならない。

問3:変数$objに、配列を使わずに$name,$age,$addressの三種類の値を入れて取り出せるようにしてね。

$obj = new class('安部菜々', 17, 'ウサミン星') {
    public $name, $age, $address;
    public function __construct($name, $age, $address) {
        $this->name = $name;
        $this->age = $age;
        $this->address = $address;
    }
};

echo $obj->name; // 安部菜々

たしかに配列は使ってないけどほぼ同じだろ。これでいいのか?

中級編

問4:小数点2の桁を丸める定義関数、roundmath()を作ってね。ただし、正数、負数どちらにも対応できるようにね。

function roundmath($num){
    return round($num, 1);
}

echo roundmath(12.35); // 12.4

正数、負数どちらにも対応できるようにね

とわざわざ太字で書いてあるんだけど、roundは普通に負数を扱えるので何を意図した主張なのかよくわからず。

問5:任意の行数$columnだけあるテーブル"HOGE"に対するSQLのInsert文で、一行でプレースホルダを埋め込んだ式を作成してみてね。なお、プレースホルダの記号は何を使ってもOKです。

え…これ難しくね?

((new PDO($dsn, $user, $pass))->prepare('INSERT INTO HOGE (id, value) VALUES(:id, :value)'))->execute([':id' => $id, ':value' => $value]);

そんなでもなかった。
行数はINSERTには全く関係ないので、あえて記載している意味がわからない。

問6:$desc_number = function(){ echo $number--;}; この無名関数に少しだけ手を加えて、関数desc_number()を実行するたびに、数を減らしていくようにしてね。なお、$numberには最初に100だけ代入されています。

$desc_number = function () {
    static $number = 100;
    echo $number--;
};

$desc_number(); // 100
$desc_number(); // 99

なんかこれも出題者が考えていた答えとちがう気がする。

上級編

問7:文字連結演算子( . )を使わずに、文字列の中に定数や今日の日付を埋め込んでみてね。

ヒントを見るに題意は変数展開でしょう。

    $d = date('Y年m月d日');
    $os = PHP_OS;
    echo "今日は${d}です。OSは${os}です。";

二重引用符では変数展開できますが、関数や定数は展開できないので1行では書けません。

まあ.を使わずに文字列結合すればいいだけなんですけどね。

printf('今日は%1$sです。OSは%2$sです。',  date('Y年m月d日'), PHP_OS);
echo '今日は', date('Y年m月d日'), 'です。OSは', PHP_OS, 'です。';

ちなみに2行使っていいなら面白い書き方があります。

$i = function ($v) { return $v; };
echo "今日は{$i(date('Y年m月d日'))}です。OSは{$i(PHP_OS)}です。";

参考:PHPで文字列リテラルに式展開

問8:同じページ内で定義関数function hogehoge($val1)function hogehoge($val2)を呼び出せるよようにしてみてね。ただし、クラスのメンバに入れるのは禁止です。

ヒントから察するに名前空間で分けろってことなのだろうか?

namespace A {
    function hogehoge($val1)
    {
        echo 'A:hogehoge' . $val1;
    }
}

namespace B {
    function hogehoge($val2)
    {
        echo 'B:hogehoge' . $val2;
    }
}

namespace {
    \A\hogehoge('A'); // A:hogehogeA
    \B\hogehoge('B'); // B:hogehogeB
}

でもこれ単に\A\hogehoge\B\hogehogeを作ってるだけであって、hogehogeを二つ作っているわけではないよね。

つまり、これが正解。

function hogehoge($val1) {
    echo 'hogehoge' . $val1;
}
hogehoge('A'); // hogehogeA

uopz_del_function('hogehoge');

function hogehoge($val2) {
    echo 'hogehoge' . $val2;
}
hogehoge('B'); // hogehogeB

うん、まあ絶対違うね。

問9:異なる要素数の2つの配列$ary1$ary2を同時にループして、順番に値を取り出したい。foreachを使って取り出してみてね。ただし、NULLを出さないでね。

順番にってのはどういうことだろうか。
$ary1の1番目、$ary2の1番目、$ary1の2番目、$ary2の2番目、って順でいいんかな?
あと余りは後ろにまとめればいいのか?

function array_mix(array $ary1, array $ary2){
    $multipleIterator = new MultipleIterator(MultipleIterator::MIT_NEED_ANY);
    $multipleIterator->attachIterator(new ArrayIterator($ary1), 1);
    $multipleIterator->attachIterator(new ArrayIterator($ary2), 2);
    foreach ($multipleIterator as $v1) {
        foreach ($v1 as $v2) {
            if ($v2 !== null) {
                yield $v2;
            }
        }
    }
}

foreach (array_mix([1, 2], [3, 4, 5, 6]) as $k => $v) {
    echo $v; // 132456
}
foreach (array_mix([1, 2, 3, 4], [5, 6]) as $k => $v) {
    echo $v; // 152634
}

むつかしかった。

問10:一つのメソッドを使うだけで、全10学級、国数英社理のテスト結果に対して、各生徒の偏差値と学年順位、学級順位を返すシステムを作ってね(横暴)。

1メソッド中にだばだば書いていけば特に問題なく実装できますね。
もちろんメンテコストなんてものは度外視だ。

ヒントはトレイトを使えとのこと。トレイト???

動かしてないけどこんなかんじでいけるやろ
class Grades{

    public static function getRank(array $students){
        // 教科毎の母集団作成
        $grades = $ranks = [];
        foreach ($students as $class => $classStudents) {
            foreach ($classStudents as $number => $student) {
                foreach ($student as $grade => $score) {
                    $grades[$grade]['cnt']++;
                    $grades[$grade]['total'] += $score;
                    $ranks[$grade][$class . '_' . $number] = $score;
                }
            }
        }

        // 順位
        foreach ($ranks as $subject => $grades) {
            $cnt = 1;
            arsort($grades);
            foreach ($grades as $grade => $score) {
                [$class, $number] = explode('_', $grade, 2);
                $students[$class][$number][$subject . '_rank'] = $cnt++;
            }
        }

        // 偏差値とか。疲れたのであとよろ
        return $students;
    }
}

$students = [ /* [クラス=>[学生番号=>[成績]]] */
    1 => [
        1 => [
            'Japanese' => 100,
            'English' => 90,
            'Mathematics' => 80,
            'Sociaty' => 70,
            'Science' => 60,
        ],
        ...
    ],
    ...
];

$result = Grades::getRank($students);

むしろトレイトをどう使えばいいのかわからなかった。

感想

設問が曖昧でよくわからない問題があるのを別にしても、明らかに出題者が想定してない解法を書いてしまってる問いが多々あるわけですがまあこんなものでどうでしょう。

ニコニコ大百科解析事始め ~提供されるデータをJSONして触る~

ニコニコ大百科データセットを使う

ニコニコ大百科データセットは IDR で公開されているニコニコ大百科の2008~2014年の記事とその記事へのコメントを集めたデータセットです。

知識抽出をはじめとする自然言語系の研究に向いていますが、Wikipedia のようにおとなしいデータセットではなく、かなり癖のあるデータセットとなっています。

例えばニコニコ大百科にある文は半分近くが主語が欠けている文章となっていますし、必ずしも文体が統一されているわけでもないですし、AAなんかも入っていたりします。

今回はこのデータセットの解析をしてみたいなーと思ってくれる 面白い人を求めて簡単な前処理のツールとともにデータの中身を紹介していきます。

提供されているニコニコ大百科を前処理する

提供されているデータは ちょっと特殊なCSVで、適切な前処理を施すことで標準のCSVに変形することが出来ます。
また、HTMLはいくつかのタグが煩くて解析の都合上少し面倒になります。
このため

  1. CSVを前処理する
  2. ニコニコ大百科の記事(HTML)をJSONに変形する
  3. ちらっと眺めてみる

をこの記事ではやってみようと思います。

前処理

前処理のために必要な環境として大事なのはメモリではなくディスク容量です。うっかり 50GB しか余剰容量がないと、前処理がエラーで落ちます。

また Python を使うなら CPU やメモリも多いほうが良いです。というか Pandas のパフォーマンスがあんまり…

データ利用の申請

https://www.nii.ac.jp/dsc/idr/nico/nicopedia-apply.html

こちらから申請をします。申請をすると、少なくとも数日以内にダウンロードのための URL が頂けるので保管しておきましょう。

圧縮ファイルをダウンロードして展開する

URL からダウンロードしてこんな感じで適用に展開して下さい。

.
└── nico-dict
    └── zips
        ├── download.txt
        ├── head
        │   ├── head2008.csv
        │   ├── ...
        │   └── head2014.csv
        ├── head.zip
        ├── res
        │   ├── res2008.csv
        │   ├── ...
        │   └── res2014.csv
        ├── res.zip
        ├── rev2008.zip
        ├── rev2009
        │   ├── rev200901.csv
        │   ├── rev200902.csv
        │   ├── rev200903.csv
        │   ├── ...
        │   └── rev200912.csv
        ├── rev2009.zip
        ├──...
        ├── rev2013.zip
        ├── rev2014
        │   ├── rev201401.csv
        │   └── rev201402.csv
        └── rev2014.zip

レポジトリのクローン

元々遅延評価や前処理の容易さからClojure (Lisp)を使って解析していたのですが、Pythonで解析できるように出来るだけ加工をしない HTML->JSON を行うためのツールを作りました。

https://github.com/MokkeMeguru/niconico-parser

からクローンして下さい。

git clone https://github.com/MokkeMeguru/niconico-parser

CSV を整形する。

https://github.com/MokkeMeguru/niconico-parser/blob/master/resources/preprocess.sh 

zips/preprocess.shへコピーして

sh preprocess.sh

して下さい。このファイルはCSVのエスケープを現代の仕様に修正するために必要な処理です。
(裏話:こいつの処理はかなりテストをしていますが、ひょっとするとバグがあるかもしれません。万が一バグがあったらコメントを下さい。)

記事ヘッダ情報をデータベースに保存する

ニコニコ大百科データセットは、大きく分けて
1. ヘッダ(記事ID、タイトル、タイトルの読み、カテゴリなど)
2. 記事本文
3. 記事へのコメント

になっています。この内 1. については簡単にデータベース化出来る程度の量なのでデータベースにしてしまします。

必要なファイルはhttps://github.com/MokkeMeguru/niconico-parser/blob/master/resources/create-table.sqlhttps://github.com/MokkeMeguru/niconico-parser/blob/master/resources/import-dir.shです。
これらを zips/head/<file>となるように配置して

sh import-dir.sh

として下さい。すると header.dbという sqlite3 の db が得られます。

試しにアクセスしてみましょう。

sqlite3 headers.db
sqlite3 > select * from article_header limit 10
 ...> ;
 1|ニコニコ大百科|ニコニコダイヒャッカ|a|20080512173939
 4|カレー|カレー|a|20080512182423
 5|初音ミクにオリジナルソング「貴方に花を 私に唄を」を歌わせてみた。|\N|v|20080719234213
 9|ゴーゴーカレー|ゴーゴーカレー|a|20080512183606
 13|本格的 ガチムチパンツレスリング|\N|v|20080513225239
 27|頭がパーン(P)┗(^o^ )┓三|\N|v|20080529215132
 33|【初音ミク】『少し楽しくなる時報』【アレンジ曲】|\N|v|20080810020937
 37|【 SYNC.ART'S × U.N.オーエンは彼女なのか? 】 −Sweets Time−|\N|v|20080616003242
 46|ニコニコ動画流星群|\N|v|20080513210124
 47|ハイポーション作ってみた。|\N|v|20090102150209

ニコニコ大百科感が出ていて、Wikipediaにはない知識が得られそうな匂いがしますね。

HTML->JSON!

ニコニコ大百科の記事の大きなの問題点を挙げるとするならば、変なタグが多いということを挙げることが出来ます。
Wikipediaとは異なり、整形のための <br>タグや <span>タグなどが溢れており、文を取り出そうとすると結構苦労する、というのが個人的な手応えでした。
(また AA なんかはほぼお手上げな状態です。AAのためのタグを作って…)

HTMLを解析するのに楽なのが DSL(domain-specific language) を使った方法です。有名なものだと Kotlin のHTML解析のツールがあります。

今回はLispを使って簡単に処理させてみました。詳しいコードは…まあ良いでしょう()…

lein preprocess-corpus -r /path/to/nico-dict/zips

とまあこんな感じで実行して下さい。(Jar実行の場合はこちらから(求バグ報告))
10~15 分くらいで 20~30GB くらいディスクを食べ切ります。

中身をちらっと見てみましょう。

head -n 1 rev2008-jsoned.csv 
1,"{""type"":""element"",""attrs"":null,""tag"":""body"",""content"":[{""type"":""element"",""attrs"":null,""tag"":""h2"",""content"":[""概要""]},{""type"":""element"",""attrs"":null,""tag"":""p"",""content"":[""ニコニコ大百科とは(省略)である。""]}]}",200xxxxxxxx939,[],ニコニコ大百科,ニコニコダイヒャッカ,a

1項目ずつ説明すると
1. 記事ID
2. JSON化+前処理した記事
3. 記事更新日
4. ページ内に含まれているリンク (<a>タグ)のリスト
5. タイトル
6. タイトルのよみ
7. カテゴリ ("a"=単語 "v"=動画 "i"=商品 "l"=生放送 "c"=多分コミュニティ記事(仕様書にないカテゴリです))

今回はJSON化+前処理の効力はあんまり紹介できないですが、例えば <p>ほげ<span/>ほげ<br/>ばー</p>みたいなのが扱いやすくなっているのと、グラフへ持ち込んだり Snorkelのようなツールを適用しやすくなっていることを挙げることが出来ます。

ちょっと統計してみる

前処理ツール作ったよ!だけではあんまりにもつまらないので、ちょっと統計みたいなことをやってみましょう。
データ処理といえば Python + Pandas らしいので、Python + Pandas を使って調べてみることにします。(とはいえPandasは処理がめっちゃ重いとか遅いとかなので、本格的な解析をするなら別のツールを使って下さい。)

以下 Jupyter Notebook のように進めていきます。

依存関係のインポート

importpandasaspdimportjsonfrompathlibimportPathfrompprintimportpprint

グローバル変数の宣言

環境ごとに変えて下さい。

############################
# グローバル変数 (適宜変更します) #
############################
# CSVのヘッダ
header_name=('article_id','article','update-date','links','title','title_yomi','category''')dtypes={'article_id':'uint16','article':'object','update-date':'object','links':'object','title':'object','title_yomi':'object','category':'object'}# サンプルの CSV
sample_filepath="/home/meguru/Documents/nico-dict/zips/rev2014/rev201402-jsoned.csv"sample_filepath=Path(sample_filepath)# サンプルの CSVs
fileparent=Path("/home/meguru/Documents/nico-dict/zips")filepaths=["rev2014/rev201401-jsoned.csv","rev2014/rev201402-jsoned.csv","rev2013/rev201301-jsoned.csv","rev2013/rev201302-jsoned.csv","rev2013/rev201303-jsoned.csv","rev2013/rev201304-jsoned.csv","rev2013/rev201305-jsoned.csv","rev2013/rev201306-jsoned.csv","rev2013/rev201307-jsoned.csv","rev2013/rev201308-jsoned.csv","rev2013/rev201309-jsoned.csv","rev2013/rev201310-jsoned.csv","rev2013/rev201311-jsoned.csv","rev2013/rev201312-jsoned.csv",]filepaths=filter(lambdapath:path.exists(),map(lambdafpath:fileparent/Path(fpath),filepaths))##################

前処理済みCSVを読み込むための関数の定義

defread_df(csvfile:Path,with_info:bool=False):"""read jsoned.csv file
    args:
    - csvfile: Path
    a file path you want to read
    - with_info: bool
    with showing csv's information
    returns:
    - df
    readed data frame
    notes:
    if you call this function, you will got some log message
    """df=pd.read_csv(csvfile,names=header_name,dtype=dtypes)print('[Info] readed a file {}'.format(csvfile))ifwith_info:df.info()returndfdefread_dfs(fileparent:Path,csvfiles:List[Path]):"""read jsoned.csv files
    args:
    - fileparent: Path
    parent file path you want to read
    - csvfiles: List[Path]
    file paths you want to read
    returns:
    - dfl
    concated dataframe
    note:
    given.
        fileparent = \"/path/to\"
        csvfiles[0] = \"file\"
    then.
        search file <= \"/path/to/file\"
    """dfl=[]forfpathinfilepaths:dfi=pd.read_csv(fileparent/fpath,index_col=None,names=header_name,dtype=dtypes)dfl.append(dfi)dfl=pd.concat(dfl,axis=0,ignore_index=True)returndfl

サンプルに 1 ファイル読み込んで眺める

今回はHTML内のリンク (<a>タグ) が記事の種類ごとにどんな風な散らばりを示しているのかを眺めてみることにします。

df=read_df(sample_filepath,True)# [Info] readed a file /home/meguru/Documents/nico-dict/zips/rev2014/rev201402-jsoned.csv
# <class 'pandas.core.frame.DataFrame'>
# RangeIndex: 6499 entries, 0 to 6498
# Data columns (total 7 columns):
# article_id     6499 non-null int64
# article        6499 non-null object
# update-date    6499 non-null int64
# links          6499 non-null object
# title          6491 non-null object
# title_yomi     6491 non-null object
# category       6491 non-null object
# dtypes: int64(2), object(5)
# memory usage: 355.5+ KB

とりあえずこのファイルそのものは 6.5k の記事があることが確認できました。

次にリンクの数を計算するために、JSON化されたリンク情報をパースします。

# 生データの確認
df['links'][0]# => '[{"type":"element","attrs":{"href":"http://wwwxxxxhtml"},"tag":"a","content":["高知xxxxサイト"]}]'
dfs=pd.DataFrame()dfs['links']=df['links'].map(lambdax:len(json.loads(x)))dfs['links'][0]# => 1

簡単に統計を取ってみましょう。

dfs['category']=df['category']dfsg=dfs.groupby('category')dfsg.describe()#            links                                                      
#            count       mean         std  min  25%   50%    75%     max
# category                                                              
# a         5558.0  41.687298  209.005652  0.0  0.0   2.0  11.00  2064.0
# c           36.0  54.305556  109.339529  0.0  2.0   2.0  38.25   376.0
# i            4.0   7.500000    5.507571  2.0  3.5   7.0  11.00    14.0
# l          786.0  22.760814  106.608535  0.0  0.0   2.0   9.00  1309.0
# v          107.0  32.887850   46.052744  0.0  3.0  11.0  37.00   153.0

"a"=単語 "v"=動画 "i"=商品 "l"=生放送 "c"=コミュニティ記事 ですから、平均的に見れば コミュニティ記事のリンクが多いことになります。
しかし中央値や最大値を見ると単語記事についてはより詳しく見てみる(分類してみる)必要がありそうだと観察できますね。

サンプルデータを増やして確認してみる

6k 記事だけではちょっと物足りないので、データを増やしてみましょう。

dfl=read_dfs(fileparent,filepaths)# >>>         article_id                                            article  ...             title_yomi category
# 0             8576  {"type":"element","attrs":null,"tag":"body","c...  ...                  カベキック        a
# [223849 rows x 7 columns]
dfls=pd.DataFrame()dfls['links']=dfl['links'].map(lambdax:len(json.loads(x)))dfls['category']=dfl['category']dflsg=dfls.groupby('category')dflsg.describe()#              links
#              count       mean         std  min  25%  50%   75%     max
# category
# a         193264.0  32.400566  153.923988  0.0  0.0  2.0  10.0  4986.0
# c           1019.0  34.667321   77.390967  0.0  1.0  2.0  34.0   449.0
# i            247.0   6.137652    6.675194  0.0  1.0  3.0  10.0    28.0
# l          24929.0  20.266477  100.640253  0.0  0.0  1.0   5.0  1309.0
# v           3414.0  14.620387   22.969974  0.0  1.0  6.0  16.0   176.0

全体を通してみると、動画のリンク数の低下に伴った、生放送と動画のリンクの平均値が逆転していることが確認できます。また単語記事のリンク数の振れ幅が大きすぎる点は 1 サンプルの場合と同じく確認できます。また直感に反するものとしては、 単語記事は平均値よりも第3四分位が小さいという結果が得られています。

以上の結果から少なくとも記事の種類ごとにリンク数は結構変わっていることがわかり、それぞれ個別に性質を観察してから研究したほうが良さそうだ、という気持ちになることができると思います。(ここからどのように研究して結果を出すかは見ている人に投げます)

記事のリンク数と記事サイズは相関があるのか

前の実験から特に単語記事について分散が大きいことが確認できたと思います。この原因として 普段ニコニコ大百科を眺めている経験と勘から、記事サイズとリンク数の相関というのが思いつきました。なのでJSON化したデータの文字数を記事サイズとみなしてパッと相関を調べてみます。

dfts.corr()#                  links  article_size
# links         1.000000      0.713465
# article_size  0.713465      1.000000

とまあ少なくとも強い正の相関はありそうです。

もうちょっと踏み込むとこんな感じになります。

# 単語記事について
dfts[dfts['category']=="a"].loc[:,["links","article_size"]].corr()#                  links  article_size
# links         1.000000      0.724774
# article_size  0.724774      1.000000
# コミュニティ記事について
dfts[dfts['category']=="c"].loc[:,["links","article_size"]].corr()#                links  article_size
# links        1.00000       0.63424
# article_size 0.63424       1.00000
# 商品記事について
dfts[dfts['category']=="i"].loc[:,["links","article_size"]].corr()#                  links  article_size
# links         1.000000      0.254031
# article_size  0.254031      1.000000
# 生放送記事について
dfts[dfts['category']=="l"].loc[:,["links","article_size"]].corr()#                 links  article_size
# links         1.00000       0.58073
# article_size  0.58073       1.00000
# 動画記事について
dfts[dfts['category']=="v"].loc[:,["links","article_size"]].corr()#                  links  article_size
# links         1.000000      0.428443
# article_size  0.428443      1.000000

News

Webに公開されている記事を解析するためのCLIを開発しました。

lein parse-from-web -u https://dic.nicovideo.jp/a/<contents-title>

のようにしてJSON化した記事データを獲得することが出来ます。獲得例は レポジトリを見て下さい。

但しこれは 相手のサーバに負荷をかけるので、ちょっとツールを試してみる、などの目的に使って下さい。間違っても大学のIPから絨毯爆撃スクレイピングかますような真似はしないで下さい。

Browsing Latest Articles All 3 Live