前回の記事で、千葉県の賃貸物件の賃料予測を実行するところまで行いました。
d-s.hatenablog.com
しかし、データ取得のところで課題がいくつかあったため、今回データ取得(スクレイピング)のやり直しです。
コードはまとめて最下部に記載します。
前回はshokosakaさんの参考記事にのっとりPythonでスクレイピングしましたが、予告通りRで完結させました。
データ取得
今回も、スクレイピング対象は下記のとおりです。
千葉県内で任意に選んだ市のSUUMO掲載賃貸物件データを取得
・市川市 ・浦安市 ・柏市 ・鎌ヶ谷市 ・白井市 ・千葉市
・流山市 ・習志野市 ・船橋市 ・松戸市 ・八千代市
前回は白井市のデータも取得していましたが、物件数が少なかったため今回は対象から外します。
また、間取りは単身者向けを前提に、ワンルーム・1K・1DK・1LDKでフィルターをかけます。
その他フィルター条件は特にかけていません。
追加事項
前回と大きく違うところは、「物件の構造」「向き」「駐車場有無」等物件にかかる詳細情報を多数盛り込んだことです。
おさらいになりますが、下の写真の通り「詳細を見る」をクリックした先にある・・・
この画面、詳細情報にアクセスしてデータを取得してきています。
実はまだ松戸市のデータのみスクレイピング真っ最中なのですが、いかんせん物件に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)
}
}
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])
urls <- c()
urls <- c(urls, url)
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) {
count <- count+1
print(count)
tar_html <- read_html(url, encoding = 'utf-8')
tar_url_list <-
tar_html %>%
html_nodes(xpath = "//a") %>%
html_attr("href") %>%
as_data_frame() %>%
filter(grepl("/chintai/jnc_", .$value))
l <- nrow(tar_url_list)
count2=0
for (j in 1:l) {
Sys.sleep(5)
count2 <- count2+1
print(l+'-'+count2)
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)