Pythonによる不動産情報のデータ取得&分析(4)【売却物件/Webスクレイピング編】
9月になりましたが、まだまだ、暑い日が続きますね。
Pythonによる不動産情報でデータ取得&分析については、賃貸物件編が一応終わりましたので、今回から売却物件編に進みたいと思います。
前回までの記事は、参考までにこちらにリンクを張っておきます。
売却物件編についても、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')
どうでしょうか。無事データが取り込めましたでしょうか。 取り込んだデータを次回以降、加工・分析していきたいと思います。
本日はこれにて。