[成長日記:2日目]Yahoo!ニュースの最新記事見出しとurlをスクレイピングしてtxtファイルに出力

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">今日はWebスクレイピング初学者がとりあえず通るという道「Yahoo!ニュースのトップページの見出しをスクレイピング」をやった。</p>&mdash; ゆーさん (@fukannk0423) <a href="https://twitter.com/fukannk0423/status/1289923303373549568?ref_src=twsrc%5Etfw">August 2, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

Webスクレイピングのやり方をググるとだいたいどのサイトも[Yahoo!ニュース](https://news.yahoo.co.jp/)を例に出して記事見出しを取得するコードを紹介している。
そんなWebスクレイピング初学者がとりあえず通るというプログラムを組んでみた。

### requestsでWebページの情報を取得
詳しい使い方は分からないので、これさえ覚えておけばデータが取得できるというコマンドを覚え書きしておく。

- `requests`<br>
`get()`メソッドでurlを指定することでWebページのデータをまるっと取得することができる。

```Python
import requests
html = requests.get('https://news.yahoo.co.jp/')
```

`html`という変数を用意してそこに代入しておくのが慣例みたい。

`requests.get()`の第一引数にurlを指定すると`Response`オブジェクトが取得できる。
`Response`オブジェクトはさまざまな属性を持っているが、`content`属性でWebページのソースコードと同じような内容を取得できる。
（参照：https://note.nkmk.me/python-requests-usage/ ）

今回は`requests`で取得した`content`属性の`Response`オブジェクトをPythonの標準ライブラリである`html.parser`でパースして`BeautifulSoup`で抽出する。

```Python
from bs4 import BeautifulSoup
soup = BeautifulSoup(html.content, "html.parser")
```

こちらは`soup`という変数に代入しておくのが慣例みたい。

##### ところでパースとは？
HTMLのタグや属性などを解析して機械が読めるデータにしておくこと

### なんぞや？？という方向け（主にぼくのため）のまとめ
<b>今までのコードをコピペすると
`soup`という変数に指定したurlのソースコードみたいなものが入る。</b>

<br>
次はお楽しみのスクレイピング。取得したデータからいらない部分を削ぎ落とし、欲しい情報だけを抜き出していく。

### BeautifulSoupでスクレイピング
- `BeautifulSoup`<br>
HTMLファイルから欲しい情報だけを抜き出すために使うライブラリ

さっき取得した変数`soup`の中身は、ページのソースコードみたいな内容になっていて余計なものがたくさん入っているので、いらない情報をscrape(削ぎ落とす)する。

##### ～スクレイピングの理想的な流れ～
- 欲しい情報がHTMLのどこに収納されているか調べるために、ページのソースを表示し、コーヒーを淹れながらゆっくりと眺める。
- そのうち、欲しい情報の近くにのみ存在するHTMLのタグや属性に気付く。
- それらを`select()`や`find()`メソッドを用いて抜き出して整理する。
- 結果を.txtや.csvで出力してスクレイピング完了
- 出来上がったファイルを眺めてニヤニヤする

##### ～初心者に突き付けられる現実～
- まずソースコードが長すぎて欲しい情報を見失う
- 情報の位置を特定するための手がかりがつかめない
- 仕方がないので\<td>や\<p>などの汎用的なタグを一括で抜き出す
- 膨大なHTMLタグに囲まれたちっぽけな情報を見て軽く絶望する
- テキストだけ抜き出そうと思っても`.text`は複数の要素を抜き出せませんとPythonに怒られてしょげる
- その処理のために`for`文を勉強することになる
- なんとかして`.text`で抜き出したリストを作成するが、欲しい情報が何番目の要素に入っているか分からない
- 整理するためにさまざまなリストの扱い方を勉強することに
- 課題が派生していき本来の目的を見失い、生ける屍と化す

##### ま、この辺は軽い冗談ですけども
プログラミングは本当に時間泥棒ですなあ。。。

##### 実際に行ったこと
- 今回欲しい情報は、「Yahoo!ニュースの最新記事見出しとそのurl」なので、まずはその情報がHTMLのどこに収納されているかを調べる。
- [Yahoo!ニュース](https://news.yahoo.co.jp/)のトップページを開いて、右クリック→「ページのソースを表示」でソースコードを表示
- 眺めていると、主要記事の見出しやリンクは`<li class="topicsListItem">`のタグの中に入っていることに気付いたので、`select()`で抽出
- テキスト部分とurl部分を抜き出すためにfor文を使う

##### 書いたスクリプト

```Python
extract = soup.select(".topicsListItem")  #class="topicsListItem"を含むタグの中身を抽出

for i in extract:
    print(i.text)  #タグの中身の文章だけを抽出してforで取り出す。

#国内1300人超感染 連日千人超
#お盆帰省「今週判断」西村氏
#帰省だけ自粛は矛盾?識者見解
#都のコロナ死者 平均年齢79歳
#琵琶湖で遊泳 31歳男性死亡
#雌雄半々? 珍クワガタに驚き
#復活V「笑える日くると信じ」
#俳優の立石涼子さん死去 68歳

for i in extract:
    print(i.find('a')['href'])  #<a href="">の中身のリンクだけを抽出してforで取り出す。

#https://news.yahoo.co.jp/pickup/6367239
#https://news.yahoo.co.jp/pickup/6367235
#https://news.yahoo.co.jp/pickup/6367234
#https://news.yahoo.co.jp/pickup/6367237
#https://news.yahoo.co.jp/pickup/6367241
#https://news.yahoo.co.jp/pickup/6367243
#https://news.yahoo.co.jp/pickup/6367233
#https://news.yahoo.co.jp/pickup/6367238
```

見出しのテキストと記事リンクを取得できた(2020.8.2とかのニュースなのでリンク切れしてます)。

~~`zip()`関数を使うとこれらをまとめて取得することができる。~~
>2021.1.14追記
半年ほど経って自分の記事を見直してたら恥ずかしいミスをしてたのでここは訂正します。
同じリストに対する処理なので、zip使う必要ないですね。
zip関数は異なったリストなどから並行に処理をしたい時に使う関数です。
下記のコードもzip使わない形に編集しました。

ついでに`open()`関数を使ってtxtファイルを開き、`.write()`で書き込んでおく。
`open()`したら`.close()`しておくのを忘れないように。

```Python
f = open('yahootopicnews.txt', 'w', encoding='utf-8')

for i in extract:
    txt = i.text + ' ' + i.find('a')['href']
    print(txt)
    f.write(txt + '\n')

f.close()

#国内1300人超感染 連日千人超 https://news.yahoo.co.jp/pickup/6367239
#お盆帰省「今週判断」西村氏 https://news.yahoo.co.jp/pickup/6367235
#帰省だけ自粛は矛盾?識者見解 https://news.yahoo.co.jp/pickup/6367234
#都のコロナ死者 平均年齢79歳 https://news.yahoo.co.jp/pickup/6367237
#琵琶湖で遊泳 31歳男性死亡 https://news.yahoo.co.jp/pickup/6367241
#雌雄半々? 珍クワガタに驚き https://news.yahoo.co.jp/pickup/6367243
#復活V「笑える日くると信じ」 https://news.yahoo.co.jp/pickup/6367233
#俳優の立石涼子さん死去 68歳 https://news.yahoo.co.jp/pickup/6367238
```


<br>
<br>

これでYahoo!ニュースの主要記事の見出しとリンクをまとめてtxtファイルに出力することができた。
毎朝取得して自分のメールアドレスに送ったりできたら面白いかもですね。


##### 結論
スクレイピングは取ってきたデータをどう処理するかが一番の楽しみどころであり処理の仕方は腕が問われますね。クレバーにやれるようになりたいなと思いました。