brown water

ゲームやアニメの感想とかプログラムとか

Beautifulsoupでスクレイピング

BeautifulsoupはHTMLタグを解析して取得してくれるライブラリです。
Pythonから使ってスクレイピングをしたいと思います。
HTTPライブラリのRequestsもインストールしておきます。

インストール

pip install beautifulsoup4
pip install requests

使い方

準備

RequestsでURLレスポンスを取得し、それを使ってBeautifulSoupオブジェクトを作成します。

import requests
from bs4 import BeautifulSoup

url='http://example.com'
res = requests.get(url)
soup = BeautifulSoup(res.text, 'html.parser')

タグ取得

  • ページ内のAタグの先頭のものだけ取得
feed = soup.find('a')
  • 全てのAタグを取得
feeds = soup.find_all('a')
  • 条件を指定して取得
feeds = soup.find_all('a', class_='sample')

Pythonでは「class」は予約後のため、「class_」になるので注意

タグの情報

  • Aタグのhrefを取得
feed = soup.find('a')
print(feed['href'])

または

feed = soup.find('a')
print(feed.get('href'))
  • Aタグで囲まれたテキストを取得
feed = soup.find('a')
print(feed.text)

スクレイピングしてみる

今回はヤフーニュースのトピックのタイトルとリンクの取得を目的とします。 https://news.yahoo.co.jp/topics/top-picks f:id:chaz4:20200202135704j:plain

HTMLソースを解析

ソースを開き、タイトルから追っていくと、liタグのnewsFeed_item_titleクラスが見つかります。
ここの親階層を辿っていくと、newsFeed_itemクラスが1つのニュースのまとまりだと思われます。

全ニュースを取得

全てのnewsFeed_itemクラスを取得

url = 'https://news.yahoo.co.jp/topics/top-picks'
req = requests.get(url)
soup = BeautifulSoup(req.text, 'html.parser')
feeds = soup.find_all('li', class_='newsFeed_item')

タイトルを取得

ループで一つずつ必要な情報を抜き出していきます。

for feed in feeds:
    title = feed.find(class_='newsFeed_item_title')
    if title:
        print(title.text)

1つのニュースの中で、さらにfindを使って今度はnewsFeed_item_titleクラスを探しています。
見つからなかった場合はNoneが返ってくるので判定しながら次に進みます。
textで文字を取得できます。
ここではタイトルのみを抜き出して表示しています。

リンクを取得

Aタグから取得したいところですが、このページではAタグで取得すると範囲が長いため、ゴチャゴチャした長い文字列になってしまいます。
そこで、普通の文字列で取得したいと思います。

正規表現を使いたいのでインポート。

import re

for feed in feeds:
    link = re.search(r'https://news.yahoo.co.jp/pickup/\d+', str(feed))
    if link:
        print(link.group())

文字列として、「https://news.yahoo.co.jp/pickup/数字」を検索しました。
検索で見つかった場合は、groupメソッドに入っています。

まとめ

今までのコードをまとめ、タイトルとリンクをセットで表示します。

import requests
import re
from bs4 import BeautifulSoup

url = 'https://news.yahoo.co.jp/topics/top-picks'
req = requests.get(url)
soup = BeautifulSoup(req.text, 'html.parser')
feeds = soup.find_all('li', class_='newsFeed_item')

for feed in feeds:
    title = feed.find(class_='newsFeed_item_title')
    link = re.search(r'https://news.yahoo.co.jp/pickup/\d+', str(feed))
    if title and link:
        print(title.text,link.group())

これを加工して色々応用出来ると思います。
次回は画像のスクレイピング&ダウンロードをやってみたいと思います。