python3でのweb scrapingメモ

#はじめに
pythonでweb scrapingをやってみたく色々調べているのですが、内容をメモとしてまとめておこうと思います。

##利用するライブラリ

BeautifulSoupとRequestsを利用する

- 参考記事：[【Python】BeautifulSoupとRequestsでURLから本文を取得する](https://www.y-shinno.com/get-text-by-url/)

##pythonの実行結果をatom上で確認する方法
「script」というパッケージを使用

- 参考記事：[【解説】PythonをAtom上で実行する方法](https://daigodiary.com/archives/1426)

コード実行のショートカットは`Ctrl+Shift+B`（windowsの場合）

## BeautifulSoupに関するメモ

- parserには色々と種類があるらしい
    - 参考記事：[beautifulsoup4入門 htmlをパース、スクレイピングする](https://www.python.ambitious-engineer.com/archives/981#BeautifulSoup)
    - 違いは正直あまり良く分からない（一応速度に違いがあるらしい）
    - 大体のサンプルコードで`html.parser`を利用しているからそれでいいんじゃないかな笑

- 文字列の取得はget_text()
    - 参考記事：[10分で理解する Beautiful Soup](https://qiita.com/Chanmoro/items/db51658b073acddea4ac#%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B)
    - 改行/空白をトリミングしたり、要素名を指定した取得なども出来る
    - 要素を指定することで、特定の文字列を取得することも出来る
        - 例えば、`.i.get_text()`と指定すれば、`<i>`要素で囲まれた部分のみ取得する
        - 参考：[公式レファレンス](https://www.crummy.com/software/BeautifulSoup/bs4/doc/#get-text)
- `get('href')`でhref属性を取得することが出来る
    - 参考記事：[【Python】BeautifulSoupでhrefの値を取得する【スクレイピング】](https://naruport.com/blog/2019/12/27/bs4-href/)

##requestsに関するメモ
参考記事：[Requests の使い方 (Python Library)](https://qiita.com/sqrtxx/items/49beaa3795925e7de666)

- httpリクエストのメソッドに対応した関数がある
- レスポンス内容をテキスト形式で取得する（`.text`）とバイナリー形式で取得する（`.content`）のパターンがある

##UnicodeEncodeErrorについて

以下のサンプルコードをwindows環境で実行しようとするとエラーが出た

```
from bs4 import BeautifulSoup
import requests as req

url = 'https://www.y-shinno.com/vgg16-finetuning-uecfood100/'
html = req.get(url).content
soup = BeautifulSoup(html, 'html.parser')
text = soup.find(class_='entry-content').get_text()
print(text)
```

返ってきたエラー

```
UnicodeEncodeError: 'cp932' codec can't encode character '\xa0' in position 1710: illegal multibyte sequence
```

調べてみると、python内部の文字列のエンコード方式とwindowsの標準エンコード方式のバッティングによって発生するらしい。

- 参考記事：[(Windows) Python3でのUnicodeEncodeErrorの原因と回避方法](https://qiita.com/butada/items/33db39ced989c2ebf644)

解決策としては以下の記事に記載のコードをimport時に記載することで解決
（解決までにかなり時間がかかった...）

- 参考記事：[Pythonで日本語のエンコードエラーが発生したときの対応策](https://hodalog.com/about-unicodeencodeerror-using-japanese-in-python-code/)

```
import io,sys
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
```

windowsにおいてpythonで日本語を扱う際はこれを入れておく方がいいかな？（間違ってたら指摘ください笑）

##要素を取得してスクレイピングする方法
`find()` or `select()`を使えばよい

- 参考記事
    - [WebスクレイピングのためのCSSセレクタの基本](https://gammasoft.jp/support/css-selector-for-python-web-scraping/)
    - [Beautiful Soup のfind_all( ) と select( ) の使い方の違い](https://gammasoft.jp/blog/difference-find-and-select-in-beautiful-soup-of-python/)


注意：class属性をディベロッパーツールで調べる時に、ソースコードをそのままコピペするだけでは上手くいかないケースがある

例

```
<div class="l-mt10 text-ellipsis__body--2lines contents-list__item-name">あいうえお</div>
```

このclass属性を指定してselectしようとした時に

```
soup.select(".l-mt10 text-ellipsis__body--2lines contents-list__item-name")
```

では動かなくて

```
soup.select(".l-mt10.text-ellipsis__body--2lines.contents-list__item-name")
```

でないといけない（分かりずらい...）

##selectで取得した配列から文字列だけトリミングする方法
`get_text()`と`for～in～`を組み合わせる（for文ってこうやって使うのか！）

例

```
print([t.get_text() for t in text])
```

こういう感じで配列の各要素に対してfor文で順次`get_text()`していった結果を出力すればよい。

##pythonでJSONを扱う場合
取得した要素をjson配列にしたアウトプットしたい場合、`json`モジュールと`operator`モジュールの`itemgetter`を利用し、for文を回して順次配列化していけばよい

###jsonモジュールについて
参考記事：

- [PythonでJSONを扱うための方法を解説](https://techplay.jp/column/558)
- [Pythonでjson dumpsを使いこなそう！encoding、foramt、datetime](https://www.sejuku.net/blog/79338)

関数の区別がややこしい...

- json.load(): 処理の結果としてファイルのJSONを辞書型に変換して返却する
- json.loads(): プログラム上に文字列として取得済みのjsonを辞書型に変換して読み込む
- json.dump(): 辞書型の値をJSONに変換してファイルに出力する
- json.dumps(): 辞書型の値を文字列型に変換して出力する


###operatorモジュールのitemgetterについて
軽く見ただけなので、参考資料のみ記載

- 参考資料：[Pythonにおけるitemgetter()の利用方法を現役エンジニアが解説【初心者向け】](https://techacademy.jp/magazine/26352)

###pythonにおける配列の扱い方
軽く見ただけなので、参考資料のみ記載

- 参考資料：[python 配列基礎はこれで完璧！便利なメソッド多数紹介](https://udemy.benesse.co.jp/development/python-work/python-list.html)