銀行員 RとPythonに出会う

Rネタを中心に、いろいろと更新していきます

~続・不動産とファイナンス・賃貸物件入居者編(1)~「機械学習を使って東京23区のお買い得賃貸物件を探してみた」を千葉県で再度やってみる(Rでスクレイピング)

 前回の記事で、千葉県の賃貸物件の賃料予測を実行するところまで行いました。

d-s.hatenablog.com

 

しかし、データ取得のところで課題がいくつかあったため、今回データ取得(スクレイピング)のやり直しです。

コードはまとめて最下部に記載します。

前回はshokosakaさんの参考記事にのっとりPythonスクレイピングしましたが、予告通りRで完結させました。

 

データ取得

今回も、スクレイピング対象は下記のとおりです。

千葉県内で任意に選んだ市のSUUMO掲載賃貸物件データを取得

市川市 ・浦安市 ・柏市 ・鎌ヶ谷市 白井市 ・千葉市

流山市 ・習志野市 ・船橋市 ・松戸市 ・八千代市

 

前回は白井市のデータも取得していましたが、物件数が少なかったため今回は対象から外します。

また、間取りは単身者向けを前提に、ワンルーム・1K・1DK・1LDKでフィルターをかけます。

その他フィルター条件は特にかけていません。

 

追加事項

前回と大きく違うところは、「物件の構造」「向き」「駐車場有無」等物件にかかる詳細情報を多数盛り込んだことです。

おさらいになりますが、下の写真の通り「詳細を見る」をクリックした先にある・・・

f:id:d_s:20180828225321p:plain

 

この画面、詳細情報にアクセスしてデータを取得してきています。

f:id:d_s:20180828225236p:plain

f:id:d_s:20180828225502p:plain

実はまだ松戸市のデータのみスクレイピング真っ最中なのですが、いかんせん物件に1件1件アクセスしてデータを取得する関係で、スクレイピングマナーとしてスリープ時間を設けるととてつもない時間がかかります。

 

それで、取得したデータは以下のようなものになります。

サンプルで3物件見てみます。

 (変数名は適当でかっこ悪いですが。。。)

1 2 3
name アスピリアベルフルール Leaf(リーフ)103号室 Leaf01030号室
rent1 6.7 7.3 7.6
rent2 4200 3800 3500
shiki_rei -/6.7 -/7.3 -/7.6
hoshoukin - - -
shikibiki_shoukyaku - - -
layout 1LDK 1LDK 1LDK
area 44.67 44.13 44.13
direction 南西 南西 南西
type アパート アパート アパート
age 6 6 6
access1 新京成線/前原駅歩3分 JR武蔵野線/船橋法典駅歩10分 JR武蔵野線/船橋法典駅歩10分
access2 JR総武線/津田沼駅歩16分 JR総武線/西船橋駅バス17分(バス停)上山町歩6分 -
access3 京成本線/京成津田沼駅歩29分 東京メトロ東西線/西船橋駅バス17分(バス停)上山町歩6分 -
detail_layout 洋7.6LDK10.7 洋13LDK6.0 洋6LDK13.0
construction 木造 鉄骨 鉄骨
floor_heigth 1階/2階建 1階/2階建 1階/2階建
car 敷地内8640円 敷地内7560円 敷地内7560円
jouken 二人入居可 二人入居可/子供可/事務所利用不可 二人入居可
kosuu - - 8戸

 

ちゃんと、詳細情報が取れていますね。

あとは、これの前処理をしていって、再度基礎分析を行ってから予測に入っていきます。

 

本日のコード 

urlは適宜打ち換えて試してみてください。

時間がかなりかかるので、小規模で試してみると良いかもしれません。

また、スクレイピングの途中http Error500、http Error400に見舞われることがありましたが、気にせず再度実行して情報を取ってきています。

更に、データ取得中にあるページでHTMLの構造が変わる?のか、2パターンのHTMLを考慮に入れる必要があることに気づきました。

おそらくPythonで欠損になった物件はこれが原因かもしれません。

ですが、根本はよくわかっていません。

原因、回避の仕方等わかる方がいらっしゃいましたらご教授下さい。

(スクレイピングは初心者のためハードコーディングです)

library(rvest)

library(tidyverse)

library(readr)



##### 念のため文字列連結を簡単にする関数を定義しておく

"+" <- function(e1, e2) {

  if (is.character(c(e1, e2))) {

    paste(e1, e2, sep = "")

  } else {

    base::"+"(e1, e2)

  }

}



#URL(ここは各自入れ替えて。例は千葉市の賃貸住宅情報 検索結果の1ページ目・フィルター:ワンルーム。1K、1DK、1LDK)

#url <- 'https://suumo.jp/jj/chintai/ichiran/FR301FC001/?ar=030&bs=040&pc=30&smk=&po1=25&po2=99&shkr1=03&shkr2=03&shkr3=03&shkr4=03&ta=12&sa=01&cb=0.0&ct=9999999&md=01&md=02&md=03&md=04&et=9999999&mb=0&mt=9999999&cn=9999999&fw2='



fix_url <- 'https://suumo.jp'



df_all <- data_frame()





#データ取得

page <- read_html(url)



#ページ数を取得

pages <-  html_nodes(page, 'body') %>%

  html_nodes('div.pagination.pagination_set-nav') %>%

  html_text(trim = TRUE) %>%

  str_split('
|
|	')

pages <- as.integer(pages[[1]][4])



#URLを入れる配列

urls <- c()



#1ページ目を格納

urls <- c(urls, url)



#2ページ目から最後のページまでを格納

for (i in rep(1:pages)){

  pg = as.character(i+1)

  url_page = url + '&pn=' + pg

  urls <- c(urls, url_page)

}



count=0

#各ページで以下の動作をループ

for (url in urls) {

  # if (count==2) {

  #   break

  # }

  count <- count+1

  print(count)

  

  # データ取得

  tar_html <- read_html(url, encoding = 'utf-8')

  tar_url_list <- 

    tar_html %>% 

    html_nodes(xpath = "//a") %>% # aタグに格納されている

    html_attr("href") %>% # href属性のデータを取り出す

    as_data_frame() %>% 

    filter(grepl("/chintai/jnc_", .$value)) # 「詳細を見る」は"/chintai/jnc_"~で構成

  

  ## 詳細結果の数

  l <- nrow(tar_url_list)

  ## ここから各詳細結果へアクセスし、データを取得する 

  count2=0

  for (j in 1:l) {

    Sys.sleep(5) 

    count2 <- count2+1

    print(l+'-'+count2)

    

    ## 詳細結果へのURLを指定し、データを取得

    tar_url <- fix_url + tar_url_list$value[j]

    tar_html_tmp <- read_html(tar_url)

    

    name <- tar_html_tmp %>% 

      html_node('.section_h1-header-title') %>%

      html_text() %>%

      str_replace("
			","")

    

    rent1 <- tar_html_tmp %>%

      html_node(xpath = '//*[@id="js-view_gallery"]/div[1]/div[2]/div[2]/div/div[2]/div/div[1]/div/div[1]') %>%

      html_text() %>%

      str_replace("
										",'') %>%

      str_replace("万円",'')

    

    rent2 <- tar_html_tmp %>%

      html_node(xpath = '//*[@id="js-view_gallery"]/div[1]/div[2]/div[2]/div/div[2]/div/div[1]/div/div[2]/div/div[2]') %>%

      html_text() %>%

      str_replace('
												','') %>%

      str_replace("円",'')

    

    shiki_rei <- tar_html_tmp %>%

      html_node(xpath = '//*[@id="js-view_gallery"]/div[1]/div[2]/div[2]/div/div[2]/div/div[2]/ul/li[1]/div/div[2]') %>%

      html_text() %>%

      str_replace('
													
													','') %>%

      str_replace('

													','') %>%

      str_replace('

													
													','') %>%

      str_replace('
												','') %>%

      str_replace("万円",'')



    hoshoukin <- tar_html_tmp %>%

      html_node(xpath = '//*[@id="js-view_gallery"]/div[1]/div[2]/div[2]/div/div[2]/div/div[2]/ul/li[2]/div/div[2]') %>%

      html_text() %>%

      str_replace('
													
													','') %>%

      str_replace('

													','') %>%

      str_replace('

													
													','') %>%

      str_replace('
												','') %>%

      str_replace("万円",'')

    

    shikibiki_shoukyaku <-  tar_html_tmp %>%

      html_node(xpath = '//*[@id="js-view_gallery"]/div[1]/div[2]/div[2]/div/div[2]/div/div[2]/ul/li[3]/div/div[2]') %>%

      html_text() %>%

      str_replace('
													
													','') %>%

      str_replace('

													','') %>%

      str_replace('

													
													','') %>%

      str_replace('
												','') %>%

      str_replace("万円",'')



    if (is.na(rent1)){

      rent_table <- tar_html_tmp %>% 

        html_nodes('div.property_view_note-list') %>%

        html_nodes('span') %>%

        html_text()

      

      rent1 <- rent_table[1] %>%

        str_replace('万円','')

      

      rent2 <- rent_table[2] %>%

        str_replace('管理費・共益費:','') %>%

        str_replace('円','')

      

      shiki_rei <- (rent_table[3] +'/'+ rent_table[4]) %>%

        str_replace('敷金:','') %>%

        str_replace('礼金:','') %>%

        str_replace('万円','')

      

      hoshoukin <- (rent_table[5]) %>%

        str_replace('保証金:','') %>%

        str_replace('万円','')

      

      shikibiki_shoukyaku <- (rent_table[6]) %>%

        str_replace('敷引・償却:','') %>%

        str_replace('万円','')

      

    }

    

    

    detail_tbl1 <- tar_html_tmp %>%

      html_nodes('.property_view-detail') %>%

      html_nodes('td') %>%

      html_text()

    address <- detail_tbl1[1]

    layout <- detail_tbl1[3]

    area <- detail_tbl1[4] %>% 

      str_replace("m2",'')

    floor <-  detail_tbl1[6] %>% 

      str_replace("階",'')

    direction <- detail_tbl1[7]

    type <- detail_tbl1[8] 

    age <- detail_tbl1[5] %>% 

      str_replace("築",'') %>%

      str_replace("年",'') 



    if (is.na(address)){

    address <- tar_html_tmp %>% 

      html_nodes(xpath = '//*[@id="js-view_gallery"]/div[1]/div[2]/div[3]/div[2]/div[2]/div/div[2]/div') %>%

      html_text() %>%

      str_replace("
									","")

    layout <- tar_html_tmp %>% 

      html_nodes(xpath = '//*[@id="js-view_gallery"]/div[1]/div[2]/div[3]/div[1]/div/div[2]/ul/li[1]/div/div[2]') %>%

      html_text() %>%

      str_replace("
											","")

    area <- tar_html_tmp %>% 

      html_nodes(xpath = '//*[@id="js-view_gallery"]/div[1]/div[2]/div[3]/div[1]/div/div[2]/ul/li[2]/div/div[2]') %>%

      html_text() %>%

      str_replace("
											","") %>%

      str_replace("m2","")

    direction <- tar_html_tmp %>% 

      html_nodes(xpath = '//*[@id="js-view_gallery"]/div[1]/div[2]/div[3]/div[1]/div/div[2]/ul/li[3]/div/div[2]') %>%

      html_text() %>%

      str_replace("
											","")

    type <- tar_html_tmp %>% 

      html_nodes(xpath = '//*[@id="js-view_gallery"]/div[1]/div[2]/div[3]/div[1]/div/div[2]/ul/li[4]/div/div[2]') %>%

      html_text() %>%

      str_replace("
											","")

    age <- tar_html_tmp %>% 

      html_nodes(xpath = '//*[@id="js-view_gallery"]/div[1]/div[2]/div[3]/div[1]/div/div[2]/ul/li[5]/div/div[2]') %>%

      html_text() %>%

      str_replace("
											","") %>%

      str_replace("築","") %>%

      str_replace("年","")

    }



    access_tbl <- tar_html_tmp %>%

      html_nodes('.property_view-detail') %>%

      html_nodes('td') %>%

      html_nodes('div') %>%

      html_text()

    if (sum(is.na(access_tbl))==1|length(access_tbl)==0) {

      access_tbl <- tar_html_tmp %>% 

        html_node('.property_view_detail.property_view_detail--train') %>%

        html_nodes('.property_view_detail-text') %>%

        html_text()

    }

    if (length(access_tbl) == 0){

      access1 <- '-'

      access2 <- '-'

      access3 <- '-'

    } else if (length(access_tbl) == 1){

      access1 <- access_tbl[1]

      access2 <- '-'

      access3 <- '-'

    }else if (length(access_tbl) == 2){

      access1 <- access_tbl[1]

      access2 <- access_tbl[2]

      access3 <- '-'

    }else if (length(access_tbl) == 3){

      access1 <- access_tbl[1]

      access2 <- access_tbl[2]

      access3 <- access_tbl[3]

    }  

    

    detail_tbl2 <- tar_html_tmp %>% 

      html_nodes('.data_table.table_gaiyou') %>%

      html_nodes('td')

  

    detail_layout <- detail_tbl2[1] %>% 

      

      

      html_text() %>%

      str_replace("
						","")

    

    construction <- detail_tbl2[2] %>% 

      html_text() %>%

      str_replace("
						","")

    

    floor_heigth <- detail_tbl2[3] %>% 

      html_text()

    

    car <- detail_tbl2[6] %>% 

      html_text()

    

    jouken <- detail_tbl2[9] %>% 

      html_text()

    

    kosuu <- detail_tbl2[12] %>% 

      html_text()

    

    temp.DF <- data.frame(name, rent1, rent2, shiki_rei, hoshoukin,

                  shikibiki_shoukyaku, layout, area, direction,

                  type, age, access1, access2, access3, detail_layout,

                  construction, floor_heigth, car, jouken, kosuu)

    df_all <- rbind(df_all, temp.DF)

  }  

}

write.csv(df_all, "各々のPATHを入力", quote=T, row.names = F)