見出し画像

Webスクレイピング勉強④~ランキングサイト掲載情報の自動取得~

引き続きWEBスクレイピングの勉強

目的

下記ランキングサイトから
・情報を取得して
・一覧化&ファイル出力

観光地名とか評価の情報を取得する

1.構造確認

①全体
ランキング全体の作りとして、divタグのclass="u_areaListRankingBox"に1つの観光地が定義されている。

②観光地名
divタグの「class=u_title」で定義されているぽい。

③総合評価
divタグの「class=u_rankBox」で定義されているぽい。

④カテゴリ評価
divタグの「class=u_categoryTipsItem」で定義されているぽい。

2.1つ目の観光地情報を取得

構造を確認出来たら情報を取得する。まずは1つ目だけ取得できることを確認する。

(1)HTML取得

requestsとbeautifulsoupをインストールしてURLからHTML取得

import requests #requestsインポート
from bs4 import BeautifulSoup #beautifulsoupインポート

url = 'https://scraping-for-beginner.herokuapp.com/ranking/' #url指定 
res = requests.get(url) #urlのHTML取得
soup = BeautifulSoup(res.text,'html.parser') #取得自他情報をHTMLタグとして格納

(2)観光地情報取得

①ランキング1位の情報全体を取得
divタグの「class=u_areaListRankingBox」の情報を取得

#観光地名
spots = soup.find_all('div', attrs={'class':'u_areaListRankingBox'}) #ランキング全体を取得

これでランキング全体が取得できたため、この1つ目の要素をとれば1位の情報のみを取得できる。

spot = spots[0] #1つ目の情報を取得

確認すると、確かに1つめの観光地情報がとれてる
以降は、この中から必要な情報を抽出していく。

(3)観光地名取得

観光地名は、spotの中のdivタグ&class = u_title

spot_name = spot.find('div', attrs={'class':'u_title'}) #divタブのu_titleクラスのみ取得

確認すると指定したクラスの値で観光地名が取得できている。
ただこれだと不要な値(頭の1)がついているので、spanタグを除外する。(spanタグのclass=badge)

spot_name.find('span', attrs={'class': 'badge'}).extract() #不要な情報を除外

再度確認すると、確かに除外された

spot_nameのtextを確認すると改行コードがついている

こちらはreplace関数で変換

spot_name = spot_name.text.replace('\n','') #不要な文字を置換

綺麗になった。

(4)総評価取得

総評価も同様に取得する。

spot_evalu = spot.find('div', attrs={'class':'u_rankBox'})

こちらも同様に不要な文字を置換し、かつ少数なので型をfloatに変換

spot_evalu = float(spot_evalu.text.replace('\n',''))

総評価も取得完了!

(5) 各カテゴリ評価取得

カテゴリ評価も取得。

category_Items = spot.find('div', attrs={'class':'u_categoryTipsItem'}) #カテゴリ評価の一覧表を取得

中身を確認

その中からさらにdlタグを抽出する

category_Items = category_Items.find_all('dl')

各カテゴリと点数をリスト化できたため、それぞれ抽出していく

category_Item = category_Items[0] #1つ目の要素を取得
category = category_Item.dt.text #dtタグのテキストを取得(楽しさ) 
rank = category_Item.span.text #spanタグのテキストを取得(4.6)

それぞれ取得できた

これをリストに格納する。

details = {} #リスト定義
details[category] = rank #カテゴリと点数をセットで格納する

同じ要領でfor文で全てのカテゴリと点数を格納する

details = {} #リスト定義
  for category_Item in category_Items: #category_Itemsの値をcategory_Itemに格納
  category = category_Item.dt.text #dtタグのテキストを取得(カテゴリ)
  rank = category_Item.span.text #spanタグのテキストを取得(点数) 
  details[category] = rank  

全カテゴリと点数の組み合わせを格納完了

(6)その他の情報も追加

同様に、事前に取得した観光地名と総評価もリストに追加する。

datum = details #全体のデータを入れるリストをdatumとする
datum['観光地名'] = spot_name.replace('\n','') #観光地名を入れる
datum['評点'] = spot_evalu #評価を入れる

ここまでで、すべての観光地情報がリスト化された。


3.全観光地情報を取得(リスト全体)

まずは先ほどまでの情報を整理
以下のコードで全体のうち、1つ目の観光地情報が取得可能。

import requests #requestsインポート
from bs4 import BeautifulSoup #beautifulsoupインポート

#(1)HTML取得
url = 'https://scraping-for-beginner.herokuapp.com/ranking/' #url指定
res = requests.get(url) #urlのHTML取得
soup = BeautifulSoup(res.text,'html.parser') #取得自他情報をHTMLタグとして格納

#(2)観光地情報取得
spots = soup.find_all('div', attrs={'class':'u_areaListRankingBox'}) #ランキング全体を取得
spot = spots[0] #1つ目の要素のみ取り出す

#(3)観光地名取得
spot_name = spot.find('div', attrs={'class':'u_title'}) #divタブのu_titleクラスのみ取得
spot_name.find('span', attrs={'class': 'badge'}).extract() #不要な情報を除外
spot_name.text
spot_name = spot_name.text.replace('\n','') #不要な文字を置換

#(4)総評価取得
spot_evalu = spot.find('div', attrs={'class':'u_rankBox'})
spot_evalu = float(spot_evalu.text.replace('\n',''))

#(5) 各カテゴリ評価取得
category_Items = spot.find('div', attrs={'class':'u_categoryTipsItem'})
category_Items = category_Items.find_all('dl')
details = {} #リスト定義

for category_Item in category_Items: #category_Itemsの値をcategory_Itemに格納
    category = category_Item.dt.text #dtタグのテキストを取得(カテゴリ)
    rank = category_Item.span.text #spanタグのテキストを取得(点数)
    details[category] = rank  

#(6)その他の情報も追加
datum = details #全体のデータを入れるリストをdatumとする
datum['観光地名'] = spot_name.replace('\n','') #観光地名を入れる
datum['評点'] = spot_evalu #評価を入れる

以下★の行を変更して、全体を取得するように書き換え

import requests #requestsインポート
from bs4 import BeautifulSoup #beautifulsoupインポート

data = [] #★

#(1)HTML取得
url = 'https://scraping-for-beginner.herokuapp.com/ranking/' #url指定
res = requests.get(url) #urlのHTML取得
soup = BeautifulSoup(res.text,'html.parser') #取得自他情報をHTMLタグとして格納

#(2)観光地情報取得
spots = soup.find_all('div', attrs={'class':'u_areaListRankingBox'}) #ランキング全体を取得

#spot = spots[0] #1つ目の要素のみ取り出す
for spot in spots: #★

    #(3)観光地名取得
    spot_name = spot.find('div', attrs={'class':'u_title'}) #divタブのu_titleクラスのみ取得
    spot_name.find('span', attrs={'class': 'badge'}).extract() #不要な情報を除外
    spot_name.text
    spot_name = spot_name.text.replace('\n','') #不要な文字を置換
    
    #(4)総評価取得
    spot_evalu = spot.find('div', attrs={'class':'u_rankBox'})
    spot_evalu = float(spot_evalu.text.replace('\n',''))
    
    #(5) 各カテゴリ評価取得
    category_Items = spot.find('div', attrs={'class':'u_categoryTipsItem'})
    category_Items = category_Items.find_all('dl')
    details = {} #リスト定義
    
    for category_Item in category_Items: #category_Itemsの値をcategory_Itemに格納
        category = category_Item.dt.text #dtタグのテキストを取得(カテゴリ)
        rank = category_Item.span.text #spanタグのテキストを取得(点数)
        details[category] = rank  
    
    #(6)その他の情報も追加
    datum = details #全体のデータを入れるリストをdatumとする
    datum['観光地名'] = spot_name.replace('\n','') #観光地名を入れる
    datum['評点'] = spot_evalu #評価を入れる
    data.append(datum) #★

dataリストに全観光地情報が格納された

4.表形式に変換&ファイル出力

pandasをインポートして、dataframeに読み込む

import pandas as pd
df = pd.DataFrame(data)

入れた結果が以下

表のカラムは以下で取得可能

df.columns

以下の書き方でカラムの並び替えが可能

df = df[['観光地名', '評点', 'アクセス', '楽しさ', '人混みの多さ', '景色']]

確認すると並び替えできている

df.to_csv('観光地.csv', index=False)

データ取得完了。


以上!

この記事が気に入ったらサポートをしてみませんか?