akatak blog

プログラム初心者の50代ビジネスマンがセカンドキャリアを目指して働きながらPythonを中心に独学していましたが、昨年IT系企業に転職。新規事業開発の仕事をすることになりました。自らの覚え書きや成果物、感じたことなどを脈絡もなく書き連ねるブログです。

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= [ ] )とエラーを取り込むリスト(errors = [ ])を作っておきましょう。

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')

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

本日はこれにて。