akatak’s blog

プログラム初心者の50代ビジネスマンがセカンドキャリアを目指して働きながらPythonを中心に独学しています。自らの覚え書きや感じたことなどを脈絡もなく書き連ねるブログです。

Pythonによる不動産情報のデータ取得&分析(4)【売却物件/Webスクレイピング編】

9月になりましたが、まだまだ、暑い日が続きますね。

Pythonによる不動産情報でデータ取得&分析については、賃貸物件編が一応終わりましたので、今回から売却物件編に進みたいと思います。

前回までの記事は、参考までにこちらにリンクを張っておきます。

akatak.hatenadiary.jp

akatak.hatenadiary.jp

akatak.hatenadiary.jp

売却物件編についても、Suumoさんからデータ取得を行いたいと思います。マンションの中古物件に特定して分析を行っていきますので、今回は目黒区の中古物件データを取得するために、以下のサイトの情報を取得しましょう。

# SUUMO 中古マンション 目黒区
url = 'https://suumo.jp/jj/bukken/ichiran/JJ010FJ001/?ar=030&bs=011&ta=13&jspIdFlg=patternShikugun&sc=13110&kb=1&kt=9999999&mb=0&mt=9999999&ekTjCd=&ekTjNm=&tj=0&cnb=0&cn=9999999&srch_navi=1'

まずは、トップページの情報を取得します。

result = requests.get(url, timeout=10)
c = result.content
soup = BeautifulSoup(c, "html.parser")

続いて、ページ数を取得しましょう。ページ数に基づき、全てのページのURLのリストを作成します。

# ページ数を取得
s = soup.find("div", {"class": "pagination pagination_set-nav"})
num_pages = int(s.find_all("a")[-2].string)

# 全てのページのURLを作成
urls = []
urls.append(url)
for i in range(num_pages-1):
    pg = str(i+2)
    url_page = url + '&pn=' + pg
    urls.append(url_page)

さて、賃貸物件と同様にデータを取り込むリスト(data= [ ] )とエラーを取り込むリスト(erraors = [ ])を作っておきましょう。

data = []
errors = []

ここで、各ページ毎にURLを取得し、必要なデータをスクレイピングしていきます。 エラーが起きた時のデータの位置を把握するために、kという箱を用意し、ナンバリングしていきます。また、エラーが発生した際にスクリプトを実行し続けるとともに、どこでどんなエラーが発生したのか把握するため、try〜exceptを使います。

for url in urls:
    k = 0
    try:

    # ここにエンジン部分を記載します。
        
    except Exception as e:
        errors.append([e, url, k, subtitle])
        pass

さて、ここからが本番です。エンジン部分を作っていきます。 各ページ毎にデータを取得して、物件毎のデータをunitsに保管します。

result = requests.get(url)
c = result.content
soup = BeautifulSoup(c, "html.parser")
summary = soup.find("div",{'id':'js-bukkenList'})
units = summary.find_all("div",{'class':'property_unit'})

次に、unitsに保管された物件データを一つ一つ取り出して、必要なデータを取得していきます。 賃貸物件の場合と異なり、今回は各物件のページだけですと、データが限られていますので、そのページから更に詳細なデータが記載されているページに移動してデータを取得します。ですので、以下の通り、詳細ページへのリンク、データ取得を行っておきます。

# 物件詳細情報へのリンク
h2 = unit.find('h2', {'class':'property_unit-title'})
a = h2.find('a')
href = a.get('href')
link = 'https://suumo.jp' + href + 'bukkengaiyo/'

result_child = requests.get(link, timeout=10)
c_child = result_child.content
soup_child = BeautifulSoup(c_child, "html.parser")
summary_child = soup_child.find_all('tbody', {'class':'vat tal'})

その上で、各変数にデータを取り込んでいきます。実は、ここが個別ではうまく取り込めなかったりして、テクニカルには大変なのですが、最終形だけ掲載いたします。リフォームの箇所のみうまくテキストが抽出できず、リスト形式にしていますが、ご了承ください。将来的には何とかしたいと思いますが、今はリストの中身よりも、リフォームの有無のみ取り上げたいので、中途半端ですが許容いただければと思います。

# 新着、価格更新等の情報
try:
    info = unit.find('span',{'class':'ui-label ui-label--cta1 ui-label--cta4'}).string
except:
    pass

# 物件名
subtitle = unit.find('dd',{'class':'dottable-vm'}).string

# 価格
price = unit.find('span',{'class':'dottable-value'}).string

# 住所
location = unit.find_all('dd')[2].string

# 最寄駅
station = unit.find_all('dd')[3].string

# 専有面積
area = unit.find_all('dd')[4].contents[0].split('m')[0]

# 間取り
floor_plan = unit.find_all('dd')[5].string

# バルコニー
balcony = unit.find_all('dd')[6].contents[0].split('m')[0]

# 築年月
yrs = unit.find_all('dd')[7].string

# link
link = unit.find('h2',{'class':'property_unit-title'}).a.get('href')

# 管理費
kanrihi = summary_child[0].find_all('td')[5].string.strip('\r\n\t')

# 修繕積立費
shuzenhi = summary_child[0].find_all('td')[6].string.strip('\r\n\t')

# 物件階
stair = summary_child[0].find_all('td')[14].string.strip('\r\n\t')

# 方角
direction = summary_child[0].find_all('td')[15].string.strip('\r\n\t')

# リフォーム
reform = summary_child[0].find_all('td')[16].contents

# 総戸数
total_units = summary_child[1].find_all('td')[2].string.strip('\r\n\t')

# 構造・階建て
structure = summary_child[1].find_all('td')[3].string.strip('\r\n\t')

# 権利形態
right_form = summary_child[1].find_all('td')[5].string.strip('\r\n\t')

# 用途地域
usage_district = summary_child[1].find_all('td')[6].string.strip('\r\n\t')

# 駐車場
parking = summary_child[1].find_all('td')[7].string.strip('\r\n\t')

1件ずつデータを取得して、都度リストに加えていきます。

data.append([info, subtitle, price, location, station, area, floor_plan, balcony, yrs, link, kanrihi, shuzenhi, stair, direction, reform, total_units, structure, right_form, usage_district, parking])

最終的に、dataリストをデータフレームに変換して、タイトルを付けて、csvファイルとして保存します。エラーリストも同じく保存しておきましょう。

# data listを DataFrameに変換
df = pd.DataFrame(data, columns=['情報','物件名','価格','住所','最寄駅','専有面積','間取り','バルコニー','築年月','リンク','管理費', '修繕積立費','物件階', '方角','リフォーム','総戸数', '構造・階建て','権利形態','用途地域','駐車場'])

# csvファイルとして保存
df.to_csv('Data/suumo_used_mansion.csv', sep = ',',encoding='utf-8')

# ついでに errors fileも保存
df_errors = pd.DataFrame(errors)
df_errors.to_csv('Data/errors_used_mansion.csv', sep = ',', encoding='utf-8')

どうでしょうか。無事データが取り込めましたでしょうか。 取り込んだデータを次回以降、加工・分析していきたいと思います。

本日はこれにて。