100日後にエンジニアになるキミ - 71日目 - プログラミング - スクレイピングについて2

昨日までのはこちら

[100日後にエンジニアになるキミ - 70日目 - プログラミング - スクレイピングについて](https://qiita.com/otupy/items/f53e2e7d16adf80b5acf)

[100日後にエンジニアになるキミ - 66日目 - プログラミング - 自然言語処理について](https://qiita.com/otupy/items/5828ac7450c5ba8d6931)

[100日後にエンジニアになるキミ - 63日目 - プログラミング - 確率について1](https://qiita.com/otupy/items/0196897ae4d2134794fa)

[100日後にエンジニアになるキミ - 59日目 - プログラミング - アルゴリズムについて](https://qiita.com/otupy/items/f1a5e81633b868f3b5ed)

[100日後にエンジニアになるキミ - 53日目 - Git - Gitについて](https://qiita.com/otupy/items/0abaad82a7f3fea73f1f)

[100日後にエンジニアになるキミ - 42日目 - クラウド - クラウドサービスについて](https://qiita.com/otupy/items/d1765f1541a104ed6133)

[100日後にエンジニアになるキミ - 36日目 - データベース - データベースについて](https://qiita.com/otupy/items/7af17635d576677606dc)

[100日後にエンジニアになるキミ - 24日目 - Python - Python言語の基礎1](https://qiita.com/otupy/items/6d1e5453f530e07b7aec)

[100日後にエンジニアになるキミ - 18日目 - Javascript - JavaScriptの基礎1](https://qiita.com/otupy/items/2f71d5f9c754b29d9555)

[100日後にエンジニアになるキミ - 14日目 - CSS - CSSの基礎1](https://qiita.com/otupy/items/61a97863f6df14171994)

[100日後にエンジニアになるキミ - 6日目 - HTML - HTMLの基礎1](https://qiita.com/otupy/items/cd2315dcb38671cfded0)

今回はスクレイピングの続きです。

## 通信について

Python言語でスクレイピングを行なっていきます。
スクレイピングでは通信を伴いますので
通信の仕組みを知っておく必要があります。

WEBサイトは世界中のサーバー上に置かれています。
WEBにおいて基本的にサーバとのやりとりは`HTTP（HyperText Transfer Protocol)`という`プロトコル(通信規約)`を用いて行い

ブラウザからサーバへの要求を`リクエスト`
サーバからブラウザへの応答を`レスポンス`と呼んでいます。


WEB上での基本的なやりとりはリクエスト/レスポンス(R/R)で成立しており
基本的にはテキストメッセージを交換することにより、実現されています

**サイト検索の例**
ブラウザから検索ツールで検索を実行`リクエスト`
サーバは要求に対して結果を返答`レスポンス`
レスポンスを元にブラウザは検索結果を表示


`HTTP通信`には、いくつかの仕様があり、リクエストの送り方が複数あります。

**GET通信**

GETはURLにパラメータを付加してリクエストします


例：
http://otupy.com?p=abc&u=u123
?以降はパラメータでパラメータは`キー=値`を`&`つなぎにしたものです。

**POST通信**

POSTはBodyに含めてリクエストします

http://otupy.com

リクエストBody
`param:p:ab,u:u123`

**POSTとGETの使い分け**
通信自体はブラウザーでは適切な通信方法を選んで行うが
プログラムでは通信方法を指定する必要があります。

### リクエスト

ブラウザーなどからWEBサイトのサーバーへの要求をリクエストと言っています。

ブラウザでWebページを開く際、ブラウザはサーバに下記のような要求メッセージを送信します。

GETの例：

```
リクエストヘッダ
GET http://www.otupy.com/ex/http.htm HTTP/1.1
Host: www.otupy.com
Proxy-Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8
Referer: https://www.google.co.jp/
Accept-Encoding: gzip, deflate
Accept-Language: ja,en-US;q=0.9,en;q=0.8
```

POSTの例：

```
リクエストヘッダ：
POST /hoge/ HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Content-Length: 22
Cache-Control: max-age=0
Origin: http://localhost:8080
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,/;q=0.8
Referer: http://localhost:8080/hoge/
Accept-Encoding: gzip, deflate, br
Accept-Language: ja,en-US;q=0.8,en;q=0.6

リクエストボディ：
name=hoge&comment=hoge
```

リクエストは`ヘッダ`と`ボディ`部があり、通信方法によってどのような情報を詰めて送信しているのかが変わります。

そのため、プログラムでアクセスする際にも適切な情報を詰めてリクエストをしてあげる必要があります。

### プログラムでのアクセス

早速スクレイピングを試してみましょう。

Pythonでは`requests`と言うライブラリで通信を行うことができます。

```python

import requests
```

アクセス先のWEBサイトが必要なのでそれを指定して`GET`で通信を行います。
`requests.get(URL)`

```python
url = 'http://www.otupy.net/'
res = requests.get(url)
print(res)
```
<Response [200]>

通信の結果`レスポンス`が返ってきます。
通信に成功していれば、アクセス先の情報が取得できます。

当然通信ですので失敗することもあります。

### 通信結果(レスポンス)

通信の結果`レスポンス`はいくつかのステータスコードに別れます。
200番台は通信が成功していますが、400,500番台は
通信に失敗をしているので、URLの打ち間違いや、相手型のサーバーにアクセスできる状況であるのかを確認する必要があります。

| 分類 | 番号 | メッセージ | 説明 |
|:--|--:|:--|:--|
| 情報 | 100 | Continue | 処理を継続しています。続きのリクエストを送信してください。 |
| 情報 | 101 | Sitching Protocols | Upgrade ヘッダで指定したプロトコルに変更して再要求してください。 |
| 成功 | 200 | OK | 成功しました。 |
| 成功 | 201 | Created | Location ヘッダで指定した場所に新しいコンテンツが作成されました。 |
| 成功 | 202 | Accepted | 要求は受理されました。ただし処理は完了していません。 |
| 成功 | 203 | Non-Authoritative Information | 応答ヘッダはオリジナルサーバーが返したものとは異なりますが、処理は成功です。 |
| 成功 | 204 | No Content | コンテンツはありませんが、処理は成功しました。 |
| 成功 | 205 | Reset Content | 要求を受理したので、現在のコンテンツ（画面）を破棄してください。。 |
| 成功 | 206 | Partial Content | コンテンツを一部のみ返却します。 |
| 転送 | 300 | Multiple Choices | コンテンツ入手方法について複数の選択肢があります。 |
| 転送 | 301 | Moved Permanently | Location ヘッダで指定された別の場所に移動しました。 |
| 転送 | 302 | Found | Location ヘッダで指定された別の場所に見つかりました。そちらを見てください。 |
| 転送 | 303 | See Other | Location ヘッダで指定された他の場所を見てください。 |
| 転送 | 304 | Not Modified | 更新されていません。If-Modified-Since ヘッダを用いた場合に返却されます。 |
| 転送 | 305 | Use Proxy | Location ヘッダで指定したプロキシを使用してください。 |
| 転送 | 306 | (Unused) | 未使用。 |
| 転送 | 307 | Temporary Redirect | 別の場所に一時的に移動しています。 |
| クライアントエラー | 400 | Bad Request | 要求が不正です。 |
| クライアントエラー | 401 | Unauthorized | 認証されていません。 |
| クライアントエラー | 402 | Payment Required | 支払いが必要です。 |
| クライアントエラー | 403 | Forbidden | アクセスが認められていません。 |
| クライアントエラー | 404 | Not Found | 見つかりません。 |
| クライアントエラー | 405 | Method Not Allowed | 指定したメソッドはサポートされていません。 |
| クライアントエラー | 406 | Not Acceptable | 許可されていません。 |
| クライアントエラー | 407 | Proxy Authentication Required | プロキシ認証が必要です。 |
| クライアントエラー | 408 | Request Timeout | リクエストがタイムアウトしました。 |
| クライアントエラー | 409 | Conflict | リクエストがコンフリクト（衝突・矛盾）しました。 |
| クライアントエラー | 410 | Gone | 要求されたコンテンツは無くなってしまいました。 |
| クライアントエラー | 411 | Length Required | Content-Length ヘッダを付加して要求してください。 |
| クライアントエラー | 412 | Precondition Failed | If-... ヘッダで指定された条件に合致しませんでした。 |
| クライアントエラー | 413 | Request Entity Too Large | 要求されたエンティティが大きすぎます。 |
| クライアントエラー | 414 | Request-URI Too Long | 要求された URI が長すぎます。 |
| クライアントエラー | 415 | Unsupported Media Type | サポートされていないメディアタイプです。 |
| クライアントエラー | 416 | Requested Range Not Satisfiable | 要求されたレンジが不正です。 |
| クライアントエラー | 417 | Expectation Failed | Expect ヘッダで指定された拡張要求は失敗しました。 |
| サーバーエラー | 500 | Internal Server Error | サーバーで予期しないエラーが発生しました。 |
| サーバーエラー | 501 | Not Implemented | 実装されていません。 |
| サーバーエラー | 502 | Bad Gateway | ゲートウェイが不正です。 |
| サーバーエラー | 503 | Service Unavailable | サービスは利用可能ではありません。 |
| サーバーエラー | 504 | Gateway Timeout | ゲートウェイがタイムアウトしました。 |
| サーバーエラー | 505 | HTTP Version Not Supported | このHTTPバージョンはサポートされていません。 |

### プログラムでの通信結果の確認

さてプログラムで通信の結果を確認してみましょう。

`レスポンス変数.status_code`
でステータスコードを確認できます。

```python

url = 'http://www.otupy.net/'
res = requests.get(url)
print(res.status_code)
```
200

もし200番でなければ通信が失敗しているのでWEBサイトの情報取得は出来ていないことになります。

200番の場合は通信が成功しているのでWEBサイトから取得した情報を見ることができます。

通信の結果を変数に格納しているので、様々な内容を見ることが出来ます。

リクエストURL
`レスポンス変数.url`

ステータスコード
`レスポンス変数.status_code`

レスポンスボディをテキスト形式で取得
`レスポンス変数.text`

レスポンスボディをバイナリ形式で取得
`レスポンス変数.content`

クッキー
`レスポンス変数.cookies`

エンコーディング情報を取得
`レスポンス変数.encoding`

ここから先は取得したテキスト情報を使って必要な情報に切り分けていきます。

```python
# レスポンスをバイナリ形式で取得して文字に変換して表示(1000文字分)
print(res.content[0:1000].decode('utf-8'))
```
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
....

### カスタムヘッダー

リクエストを行う際にはリクエストヘッダとボディ部に情報を詰めてリクエストすることができます。

GET通信でヘッダを指定してリクエストするには下記のように行います。

`requests.get(url, headers=辞書型のヘッダデータ)`

ヘッダ情報として`ユーザーエージェント`を変更してアクセスするにはこのように指定します。

```python
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36 '}
res = requests.get(url, headers=headers)
```

GET通信でパラメータを変更して通信する場合は以下のように指定します。

`requests.get(url, params=辞書型のパラメータデータ)`

```python
params = {'key1': 'value1', 'key2': 'value2'}
res = requests.get(url, params=params)
```


POST通信でリクエストボディ部に情報を詰めてリクエストするには下記のように行います。

`requests.get(url, data=辞書型のボディデータ)`

```python
payload = {'send': 'data'}
res = requests.post(url, data=payload)
```

## まとめ

スクレイピングに必要な通信の仕組みを抑えておき情報取得が出来るようになっておこう。明日はこの続きで取得した情報から必要な情報を抜き出すところに入っていきます。

君がエンジニアになるまであと29日

## 作者の情報
乙pyのHP：
http://www.otupy.net/

Youtube：
https://www.youtube.com/channel/UCaT7xpeq8n1G_HcJKKSOXMw

Twitter：
https://twitter.com/otupython