PythonでHTMLの読み取りをする方法

#使用している環境

##環境について
今回の記事で紹介するpythonのコードを実行する環境は

+ Windows10
+ Visual Studio 2019
+ Python3.7 (64bit)

となります。
他の環境では詳細が異なる場合があります。

##参照ライブラリ
標準でインストールされているライブラリ以外に

+ bs4

というライブラリをインストールする必要があります。
このライブラリはHTMLファイルから読み取るための関数が定義されています。
Visual Studio2019のトップ画面から

「ツール」→「Python」→「Python環境」

でPython環境画面を開きます。
![VS画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531515/f79610bf-b1ce-a73f-ad40-ad3d413a1ce4.png)


Python環境画面からPowerShellのコンソールを開きます。
PowerShellのコンソール画面で

```
pip3 install beautifulsoup4
```
というコマンドをたたきます。つぎのメッセージが返ってくると成功です。

```
Defaulting to user installation because normal site-packages is not writeable
Collecting beautifulsoup4
  Using cached beautifulsoup4-4.9.3-py3-none-any.whl (115 kB)
Requirement already satisfied: soupsieve>1.2; python_version >= "3.0" in c:\users\sakamoto\appdata\roaming\python\python37\site-packages (from beautifulsoup4) (2.1)
Installing collected packages: beautifulsoup4
Successfully installed beautifulsoup4-4.9.3
WARNING: You are using pip version 20.1.1; however, version 21.0.1 is available.
You should consider upgrading via the 'c:\program files (x86)\microsoft visual studio\shared\python37_64\python.exe -m pip install --upgrade pip' command.
```

##プロジェクトのフォルダ構成
今回はHtmlAnalysisプロジェクトを作ります。

+ HtmlAnalysis\Python環境\Python環境 ← ここにライブラリが入っています。
+ HtmlAnalysis\HtmlAnalysis.py 
+ HtmlAnalysis\sample.html ← 今回読み取るHTMLファイル
+ その他

#コードを触ってみる
今回扱うHTMLファイルは

```html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="utf-8" />
    <title></title>
</head>
<body>
    <ul>
        <li class="p1">a</li>
        <li class="p2">b</li>
    </ul>
    <ul>
        <li class="p1">c</li>
        <li class="p2">d</li>
    </ul>
    <ul>
        <li class="p1">e</li>
        <li class="p2">d</li>
    </ul>
</body>
</html>
```

です。このなかのa,b,c,d,eを読み取っていきます。
##HTMLの読み取り
まずは簡単な例を挙げます。HTMLファイルをそのままコンソールに表示してみましょう。

```python

import bs4 #ライブラリbs4をインポートする

#bs4で定義された関数を使ってsample.htmlを読み取る
soup = bs4.BeautifulSoup(open('sample.html',encoding = 'utf-8'),'html.parser')

#sample.htmlをコンソールに出力
print(soup)
```
これを実行すると

```console
﻿﻿<!DOCTYPE html>

<html lang="ja">
<head>
<meta charset="utf-8"/>
<title></title>
</head>
<body>
<ul>
<li class="p1">a</li>
<li class="p2">b</li>
</ul>
<ul>
<li class="p1">c</li>
<li class="p2">d</li>
</ul>
<ul>
<li class="p1">e</li>
<li class="p2">d</li>
</ul>
</body>
</html>
```

となります。このコードに追記したり、改造をしたりして欲しい情報を抜き出します。

## ulタグの子要素のみを取得
htmlのなかのulタグの子要素は

```python

element = soup.find_all('ul')
```
と取得します。ちなみにタグはulタグに限らず、divタグなどでも大丈夫です。

```py

print(element)
```
を実行すると

```
[<ul>
<li class="p1">a</li>
<li class="p2">b</li>
</ul>, <ul>
<li class="p1">c</li>
<li class="p2">d</li>
</ul>, <ul>
<li class="p1">e</li>
<li class="p2">d</li>
</ul>]
```
各ulタグを一つの要素として格納された配列になっていることがわかります。
配列の各要素にforループでアクセスします。

```py

for index in element: #elementの各要素をindex変数としてループを回す。
   # 子要素を取得
   # 子要素を取得
   # 子要素を取得  
```

この変数indexからタグに囲まれた要素を取得します。

### 属性名から子要素の取得

```py
soup.find_all(class_ = 'p1')
soup.find_all(id_ = 'id属性名')
```
のようにクラス属性やid属性名から指定することも可能です。
これで

```
[<li class="p1">a</li>, <li class="p1">c</li>, <li class="p1">e</li>]
```
のように取得できます。正直こうした方が楽な気もしますが、、、
HTMLの構造などでどちらの方法にするか決定してください

## 子要素を取得する関数: contents
contents関数を説明します。これは取得したタグの子要素を配列に格納して返す関数です。

```py

print(index.contents)
```
をforループで回すと。

```

['\n', <li class="p1">a</li>, '\n', <li class="p2">b</li>, '\n']
['\n', <li class="p1">c</li>, '\n', <li class="p2">d</li>, '\n']
['\n', <li class="p1">e</li>, '\n', <li class="p2">d</li>, '\n']
```
と３つあるulタグの中身が要素ごとに分割され配列に格納されています。
ちなみに

```
\n
```
は改行コードです。実際にsample.htmlを見返していただくと、改行されています。
1個目の配列に対応するHTMLファイルに着目します。

```html
<ul> #ここで改行
  <li class="p1">a</li> #ここで改行
  <li class="p2">b</li> #ここで改行
</ul>
```
この改行もひとつの要素として扱われています。

###方法1 奇数番目のみの要素を取り出す。

```py

i = 0
while(i < len(index.contents)):
   if(i%2 == 1):
       print(index.contents[i])
   i = i + 1
```
のように奇数番目の要素だけを取り出します。

```
<li class="p1">a</li>
<li class="p2">b</li>
<li class="p1">c</li>
<li class="p2">d</li>
<li class="p1">e</li>
<li class="p2">f</li>
```

###方法2 HTMLファイルを少し改造します。

```html
<ul><li class="p1">a</li><li class="p2">b</li></ul>
```
のようにすれば改行コードも配列に紛れ込みません。

##要素のテキストを取り出す関数get_text()

これはliタグの子要素の**テキスト**を取り出す関数です。

```python
lielement = index.contents[i].get_text()
print(lielement)
```
で中身を見ると

```
a
b
c
d
e
f
```

とできました。