Pythonで複数のリストを同時にfor文で回す

`zip`を使います。


あるサイトの記事一覧から、`BeautifulSoup4`を使いURLとタイトルのリストを取得します。
目的は`['url>>>title', 'url>>>title']`という、URLとタイトルを`>>>`で接続したリストを作りたい。

以下のようにaタグの要素にタイトルが記載されているタイプのページなら...

```python

import requests, bs4

res = requests.get('https://qiita.com/takuto_neko_like')
posts = bs4.BeautifulSoup(res.text, 'html.parser').select('.u-link-no-underline')
print(posts)
```
変数`posts`には`<class 'bs4.element.Tag'>`が入っており、posts[0]などとして個別にアクセスするとhtmlのaタグの内容を見られる。

```:aタグの要素にタイトルが記載されている
[<a class="u-link-no-underline" href="/takuto_neko_like/items/52c6c52385386544aa62">herokuで悩んだところ</a>, <a class="u-link-no-underline" href="/takuto_neko_like/items/c5791f267e0964e09d03">新着記事を取得するツールを作った</a>, <a class="u-link-no-underline" href="/takuto_neko_like/items/93b3751984e5e3fd3670">fishの動きが遅すぎた  gitのトラブル</a>, <a class="u-link-no-underline" href="/takuto_neko_like/items/62aeb4271614f6f0347f">Plotlyで作るグラフをDjangoで使う</a>, <a class="u-link-no-underline" href="/takuto_neko_like/items/c9c80ff453d0c4fad239">【Python】super()を使ってオーバーライドする理由</a>, <a class="u-link-no-underline" href="/takuto_neko_like/items/14e92797fa2b23a64adb">【Python】多重継承で継承するものは何？</a>, <a class="u-link-no-underline" href="/takuto_neko_like/items/6cf9bade3d9515a724c0">【Python】@classmethod及びデコレータとは？</a>, <a class="u-link-no-underline" href="/takuto_neko_like/items/aed9dd5619d8457d4894">【Python】*args **kwrgs って何だろう</a>, <a class="u-link-no-underline" href="/takuto_neko_like/items/bb8d0957347636b5bf4f">【Bootstrap】スクロールしてもnavbarを固定して表示する方法と、その際の留意点及び解決法</a>]

```
それぞれのaタグの内容は`<class 'bs4.element.Tag'>` = Tagオブジェクトというものなので、str()で文字列型に変換することで`.find()`で`タグ名や属性名などを指定して取得したインデックスを使い、URL部分・タイトル部分の文字列だけを抽出できるようになる。

```python:urlとtitleを整形

    for post in posts:
        # URLを抽出
        index_first = int(str(post).find('href=')) + 6
        index_end = int(str(post).find('">'))
        url = (str(post)[index_first : index_end])
        # タイトルを抽出
        index_first = int(str(post).find('">')) + 2
        index_end = int(str(post).find('</a'))
        title = (str(post)[index_first : index_end].replace('\u3000', ' '))

        url_title_set.append(f"{url}>>>{title}")
```
などとすれば、出来上がり。


ただ、**aタグの要素としてタイトルが記載されていないタイプ**のサイトもよくあります。
例えば画像とタイトルから成るカードとして記事情報が表示され、カード全体にリンクが貼ってあるパターン

```html:例

    <div class='card'><a href='#' class='link'>
        <div class='image'><img src='#'></div>
        <div class='title'>タイトル</div>
        </a>
    </div>
```
このような場合、bs4の`.select`でクラス`card`を指定すると、cardクラスが適用されているdivタグ内を取得できます。そこからaタグのhref情報、titleクラスdivの要素を取得したい。

実際のコードではより多くの要素が重なっているので、親要素から.findで特定の文字列を探し出そうとすると、若干面倒くさい。

以下のようにそれぞれを個別に取得しました。

```python3

posts_links = bs4.BeautifulSoup(res.text, 'html.parser').select('.link')
posts_titles = bs4.BeautifulSoup(res.text, 'html.parser').select('.title')
```

先程のコード`urlとtitleを整形`でpostsリストをfor文で回して`Tagオブジェクトに個別にアクセスしていきますが、今回はリストが２つあります。２つのリストを同時にfor文で回して、それぞれのリストから取得したurlとtitleを結合。その後新たなリストに格納したい。

このように、複数のリストを同時にfor文で回したいときは、`zip`を使います。

```python

now_posts_link_title_set = []

for (posts_link, posts_title) in zip(posts_links, posts_titles):
        index_first = int(str(posts_link).find('href=')) + 6
        index_end = int(str(posts_link).find('">'))
        posts_link_set = (str(posts_link)[index_first : index_end])

        index_first = int(str(posts_title).find('h2')) + 3
        index_end = int(str(posts_title).find('</h2'))
        posts_title_set = (str(posts_title)[index_first : index_end].replace('\u3000', ' ')) # 空白置換
        now_posts_link_title_set.append(f"{posts_link_set}>>>{posts_title_set}")
```


２つより多くても大丈夫

```python
for (a, b, c, d) in zip(a_list, b_list, c_list, d_list)
```

リストの要素数に差がある場合は、多い方が無視されます

```python
aa = [1,2,3,4,5]
bb = ['a', 'b', 'c']

for (a, b) in zip(aa, bb):
  print(f'{a} : {b}')

# 結果
1 : a
2 : b
3 : c
```

便利