SeleniumでWebスクレイピング(4) さまざまな要素のデータを取得

SeleniumでWebスクレイピング(4) さまざまな要素のデータを取得


次は、様々な要素が含まれる、より一般的なサイトからデータを取得していきます。



サイトの構造の把握と抽出

同じような記事枠が繰り返されているサイト(例:ホテル予約サイト)を考える。


一項目の取り出し

idが付与されているときはid、なければうまく特定できそうなclass名を使って取り出す。

同名のclassが複数あった場合、find_element_by_class_nameで取り出されるのは最初の1つ目である。

elem_contents = browser.find_element_by_class_name('u_ContentsBox')
elem_title = elem_contents.find_element_by_class_name('u_title')
elem_title.text
'1\nタイトル1'


取り出したデータのフォーマットが整えられていない場合は、splitを使うのが便利。

elem_title = '1\nタイトル1'
elem_title.split('\n')[1]
'タイトル1'


文字列以外を取り出した場合は、型変換しておくと後で楽。

int(value) # 整数

float(value) # 小数

import datetime
sdate = '2021-01-23 04:56:01'
date = datetime.datetime.strptime(sdate, '%Y-%m-%d %H:%M:%S')
date # datetime.datetime型


複数項目の取り出し

  • 複数項目が並んでいる大枠記事は多くの場合なにがしかのタグで区切られ、class名がついていることが多いため、必ずそのキーを使ってデータを取り出す。
  • 記事内の各データは、上記と組み合わせた条件で値を取り出す。


find_elements_by_class_nameを使って、配列で取り出す。

elem_contents = browser.find_elements_by_class_name('u_ContentsBox')

この場合、戻り値は配列が返る。


いくつ取り出せたかは、len関数を使う。

len(elem_contents)
10


欲しい個数が取り出せているのを確認したら、for文で回してやるとよい。

titles = []
elem_contents = browser.find_element_by_class_name('u_ContentsBox')
for elem_content in elem_contents:
    elem_title = elem_content.find_element_by_class_name('u_title')
    titles.append(elem_title.text.split('\n')[1])

これで配列titlesにタイトルのみを格納できた。


各項目内の複数行リスト

各項目内に複数行のリストがある場合、forの二重ループで回すとよい。

categories = []
for elem_title in elems_rankingbox:
    _ranks = []
    score = elem_title.find_element_by_class_name('u_categoryTipsItem')
    scores = score.find_elements_by_class_name('is_rank')
    for s in scores:
        _ranks.append(float(s.text))
    categories.append(_ranks)
print(categories)
[[4.6, 4.5, 4.9, 4.2], [4.6, 4.5, 4.9, 4.2], [4.5, 4.4, 4.8, 4.1], [4.4, 4.4, 4.8, 4.0], [4.4, 4.3, 4.7, 4.0], [4.3, 4.3, 4.7, 3.9], [4.2, 4.2, 4.6, 3.8], [4.2, 4.2, 4.6, 3.8], [4.1, 4.1, 4.5, 3.7], [4.0, 4.1, 4.4, 3.6]]


Pandasのオブジェクトにする

Pandasに入れることで、前回記載したCSV出力をはじめ、データ分析を行うPandasの機能を使えるようになります。


二次元データフレームに一次元配列を追加

import pandas as pd
df = pd.DataFrame()
df['title'] = titles;
df['values'] = ranks;
df


二次元データフレームに二次元配列を追加

すでに二次元配列を作っていれば、DataFrameの引数に渡すだけ。

df_categories = pd.DataFrame(categories)
df_categories.columns = ['title1', 'title2', 'title3', 'title4'] # カラムタイトルを付ける場合
df_categories


2つのデータフレームを結合

df = pd.concat([df, df_categories], axis=1)


CSV書き出し

df.to_csv('output.csv', index=False)


複数ページにまたがる記事の取得

多くの場合、URLのクエリでpage=1,2,3,...やp=1,2,3,...となっていることが多い。

https://url/to/the/page/?page=1

のような形。


formatメソッドで{}の部分に値を代入できる。

'https://url/to/the/page/?page={}'.format(1)
'https://url/to/the/page/?page=1'


これらを使ってfor文で回し、各ページでデータを取得していけばよい。

for page in range(1, 4): # 1~3ページ目
    url = 'https://url/to/the/page/?page={}'.format(page)
    print(url)
https://url/to/the/page/?page=1
https://url/to/the/page/?page=2
https://url/to/the/page/?page=3

このurlを使ってbrowser.get(url)して、各ページごとにデータ取得すればよいですね。