『Pythonによるスクレイピング＆機械学習』　学習メモ

## はじめに
『Pythonによるスクレイピング＆機械学習』の第1章から第3章までの学習メモ。スクレイピングに関するトピックは1章から3章まで。4章目以降が機械学習のパート。

## 第1章
### 1-1.データのダウンロード

#### urllibライブラリーとは
URLを扱うモジュールを集めたパッケージ。以下、メソッドの例。

- urlretrieve()・・・データを直接ダウンロードする（ローカルにファイルが保存される）
- urlopen()・・・メモリー上に取得する。ftpで取得したい場合、urlopen()に渡すパラメータのhttps://をftp://に変更するだけでよい

getパラメータ付きでリクエストを送信したい場合は、辞書型変数でkey/valueのパラメータデータを作成。

urllib.parseモジュールを使って変数をurlエンコード。エンコードした変数をurl文字列に追加（間に"?"を忘れない）。

コマンドライン引数を得るにはsysモジュールをimportする。

### 1-2.BeautifulSoupでスクレイピング

#### BeautifulSoupとは
HTMLやXMLを解析するライブラリー。データのダウンロードはできない。ダウンロードしたい場合はurllibを使う。

#### pipとは
pythonのパッケージ管理システム。

####PyPIとは
Python Package Indexの略。

####HTMLの要素取得方法は色々ある
- ドット(.)を使って<html>タグから階層をたどる
- find()メソッドを使い、idで探す
- find_all()メソッドを使い、パラメータで指定された要素全てを取得する
- cssセレクターを使う

HTMLの構成、cssの基本が分かっていれば、基本的にどんなデータでも取得が可能。ただしページ構成が変わったときは修正が必要。

### 1-3.CSSセレクターについて

例：青空文庫の夏目漱石のページ
https://www.aozora.gr.jp/index_pages/person148.html

作品リスト先頭のliタグに対し、cssセレクターで取得した結果は以下の通り。

body > ol:nth-child(8) > li:nth-child(1)

nth-child(n)・・・n番目の要素、の意味

作品ページを見ると、\<ol>タグは他に使用していないため、そういう場合はol:nth-child(8)の部分は省略できる。

エレガントなCSSセレクターを書ければ、一発で特定の要素を取り出すことができる。

<font color="MediumBlue">**セレクターの書式を覚えるのが肝。正規表現を覚えるのと同じ**</font>

find()メソッドは、複数の条件を一度に指定できるのが特徴。

正規表現と組み合わせて要素を抽出することも可能。

### 1-4.リンク先を丸ごとダウンロード

\<a>タグのリンク先が相対パスだった場合、urllib.parse.urljoin()メソッドを使って絶対パスに変換する。

丸ごとダウンロードするには、リンク先を再帰的にダウンロードする必要がある。

正規表現を使うには、reモジュールをimportする。

## 第2章
### 2-1.ログインの必要なサイトからダウンロード

クッキーを利用したアクセスにはrequestsというパッケージが便利。

requests.session()メソッドでセッションを開始する。

ログイン時に送信しているデータ等を調べるには、ブラウザの開発者ツールを利用する。

開発者ツールの「Network」タブから確認。送信したフォームデータを見るには、「Header」タブの「Form Data」を確認。

### 2-2.ブラウザーを経由したスクレイピング

Webブラウザーを遠隔操作するツールとしては「Selenium」が有名。

ヘッドレス（画面表示なし）でコマンドラインから利用すれば、ブラウザがいちいち立ち上がることもない。

Chrome、Firefox、Opera等のほか、iOSやAndroidのブラウザーも操作可能。

seleniumでアクセスした場合、ブラウザーでアクセスしたのと同じことになるのでsessionの管理がいらない。

seleniumを使えば、かなり色々なことができる。ブラウザーで人が操作することの大抵のことは自動でできる。

さらに、excute_script()メソッドを使えば、任意のjsを実行させることが可能。

#### seleniumのメリット
- HTMLページ内のDOM要素も自由に操作できる
　→取得したい要素と無関係な装飾要素を事前に除去しておく、といった使い方が可能
- ページ内のJavascript関数を好きなタイミングで呼び出せる
　→ページ内の任意のデータを取得できる

### 2-3. スクレイピング道場

Wikipediaはクローリング禁止なので直接スクレイピングはNG。代わりにダンプデータを入手できるサイトがあるのでそのデータを利用する。

```python

for row in result:
    print("," .join(row))
```

#### BeautifulSoupのメソッドについて
- find_all()・・・メソッドにリストを与えてやると、複数のタグを一気に取得することができる。
- find_elements_by_css_selector()・・・"elements"と**複数形**なので、一度に複数の要素を取得する
- find_element_by_css_selector()・・・"element"と**単数形**なので、一度に1つの要素のみを取得する。複数取得するつもりでこっちのメソッド呼び出すと、文法的にはエラーではないが期待した動きにはならないので要注意

browser.save_screenshot()メソッドを使えば、スクリーンショットも撮れる。ヘッドレスモードで操作している場合、実際の画面がどうなっているかを知りたい時に便利。

スクレイピングは、実際にテストしてみないと分からない部分も多い。実際の画面（HTML)を解析しながら、どういう操作が可能か考える。

<font color="MediumBlue">**サイトの構造を把握することが重要。また、CSSの知識も必要。**</font>

### 2-4. Web APIからのデータ取得

#### Web API（Web Application Programming Interface）とは？
あるサイトが備えている機能を、外部からも利用できるように公開したもの。HTTP通信でやり取りを行い、XMLやJSON形式でデータを取得する。

Web APIは、運用側の都合で仕様変更が発生する可能性があることを意識する。

#### format()メソッド
文字列の一部を可変値として後から変更できる。

（例）

``` python

str = "hogehoge{name}fugafuga"
str.format(name="Eric Clapton")
```

#### lambda式とは？
**関数名 = lambda 引数:処理内容**
という書式で書ける関数。
（例）

``` python

k2c = lambda k: k - 273.5
```

### 2-5. cronと定期的なクローリング

macOSやLinuxでは「cron（クロン、クーロン）」というデーモンプロセスを利用。Windowsでは「タスクスケジューラー」を利用。

#### デーモン（daemon）とは？
UNIX系OSでメインメモリ上に常駐して特定の機能を提供するプログラム。 利用者の操作とは無関係に処理を行うバックグラウンドプロセスの一種。

**主な定期実行処理**

1. データ収集
2. バックアップ、ログ退避
3. 死活監視

cronの設定は「crontab」コマンドを実行し、そこで開かれたファイルを編集。macでcronを編集するならnanoエディタが便利。

### 2-6. Scrapyを使ったスクレイピング

#### Scrapyとは？
クローリングとスクレイピングを行うフレームワーク。

**基本的な作業の流れ**

1. scrapyコマンドを使ってプロジェクトを作成
2. Spiderクラスを記述してクロールとデータの取得処理を作成
3. コマンドラインからscrapyを実行

Spiderクラスを継承したサブクラスを作成する。置き場所はspidersディレクトリ。

#### Spiderクラスの主なメソッド

- parse()・・・データを取得した後に行う本文の解析処理を記述
- css()・・・CSS セレクターを使ってDOM要素を抽出
- extract()・・・そこに含まれる複数の要素をリスト形式で取得
- extract_first()・・・結果に含まれる最初の要素を返すメソッド

scrapy実行コマンド例

```
scrapy crawl soseki --nolog
```

「--nolog」を記述すると動作ログ省略。付けないと動作ログがコンソールに出力される。

メソッドの戻り値はyield。returnではなくyieldで返すルールになっている。
※yieldの意味：産する、もたらす、生む、引き起こす

#### scrapyシェルとは？
インタラクティブにScrapyを実行できるシェル。CSSセレクターで正しくデータ取得できるかを検証する際に便利。

### 2-7. Scrapyで夏目漱石の全作品をダウンロードしよう

Spiderクラスのサブクラスを作成するコマンド。

```
scrapy genspider soseki3 www.aozora.gr.jp
```

parse()メソッドが、start_urlsで指定したURL取得後に自動的に呼ばれる。

リンク先のページを取得するにはresponse.follow()メソッドを使う。

ファイルをダウンロードするには、scrapy.Request()メソッドを使う。callbackパラメータに、処理完了後のメソッドを指定できる。

### 2-8. ScrapyとSeleniumで動的Webサイトをダウンロード

Scrapyは、ミドルウェアを導入して機能を拡張することができる。その仕組を導入して、Seleniumを組み込むことができる。

**指定時のフォーマット**
（プロジェクトディレクトリ名）.（ミドルウェアファイル名）.（ミドルウェアのクラス名）

``` python

# ミドルウェア登録の例
custom_settings = {
    "DOWNLOADER_MIDDLEWARES": {
        "sakusibbs.selenium_middleware.SeleniumMiddleware": 0
    }
}
```

start_requests()メソッドは、リクエスト直前に自動で実行される処理を定義するメソッド。


## 第3章
### 3-1. Webのデータはさまざまのフォーマット

Web上に流通しているデータは大別するとテキストデータとバイナリデータの2種類。

- テキストデータ
フォーマット例：テキストファイル、XML、JSON、YAML、CSV
テキストデータは文字コードとエンコードを意識してプログラムを組む必要がある。

- バイナリデータ
フォーマット例：画像（png, jpeg, gifなど）、Excel形式
テキストデータに比べデータサイズが小さい。

書籍にある、横浜市の防災関連データのURLが変更になっているので注意。2020/10/22時点では以下。
https://www.city.yokohama.lg.jp/kurashi/bousai-kyukyu-bohan/bousai-saigai/bosai/data/data.files/0006_20180911.xml

BeautifulSoupでXMLの解析をする場合、大文字はすべて小文字に変換されるので注意。

（例）

```xml

<LocationInformation>
	<Type>地域防災拠点</Type>
	<Definition>被災した住民の避難生活の場所、情報受伝達、備蓄機能を備えた拠点です。</Definition>
	<Name>生麦小学校</Name>
	<Address>神奈川県横浜市鶴見区生麦四丁目15-1</Address>
	<Lat>35.49547584</Lat>
	<Lon>139.6710972</Lon>
	<Kana>ナマムギショウガッコウ</Kana>
	<Ward>鶴見区</Ward>
	<WardCode>01</WardCode>
</LocationInformation>
```

上記データで、「LocationInformation」を取得したい場合、以下のようになる。

誤：soup.find_all("LocationInformation"):
正：soup.find_all("locationinformation"):

エクセルファイルを扱う時は、openpyxlのほか、xlrdをインストールする。

### 3-2. データベースについて

pythonでは様々なDBに対応している。SQLiteは標準ライブラリに組み込まれており、sqlite3をimportすればすぐ使える。

書籍P160の<ラインマーカー＞ は誤表記。

MySQLを使うには事前にインストールが必要。Linux環境ならapt-getでインストール。MacやWindowsなら、MySQLの管理ツール「phpMyAdmin」もバンドルされているMAMPをインストールするのが便利。

SQLの可変項目の指定方法の違い。

- SQLite・・・？
- MySQL・・・%s

#### MongoDBとは
ドキュメント型データベースのひとつ。リレーショナル・データベース管理システム（RDBMS)は、CREATE TABLEを使ってスキーマ定義が必要だが、ドキュメント型データベースはスキーマ定義が不要。

#### TinyDBとは
ドキュメント志向データベースを利用するためのライブラリー。MongoDBより手軽にpythonから利用できる。（MongoDBは、MongoDB自体のインストールが必要だが、TinyDBはpipを使ってパッケージインストールすれば使えるから）

ある程度の規模のデータを扱うなら、MongoDBのほうが向いている。