saddleの記録

saddleの記録

自転車に乗ってどこかに行った記録を残します

コミケに始発で行けるお得な物件をPythonを使って探そう #3 賃料相場比較編

#2でコミケに始発で行ける駅の特定ができたので,今回はその中で賃料相場の安いエリアを探します。
saddlenreport.hatenablog.jp
saddlenreport.hatenablog.jp

23区の賃料相場

まず東京23区の一人暮らし物件の賃料相場を見てみます。対象はワンルームと1Kの物件です。
Pythonを使って,#1で出力した賃貸データcsvから箱ひげ図を作りました。Pythonを使うと箱ひげ図の作成が驚くほど簡単でした。

f:id:saddle93:20200405144602p:plain
東京23区の賃料相場と物件数
港区千代田区中央区が高く,足立区葛飾区あたりが安いという予想通りの結果になりました。港区に家賃120万円くらいの外れ値があるので見てみます。
f:id:saddle93:20200405161834p:plainf:id:saddle93:20200405161923p:plain
Blooming西麻布 001号室
住宅じゃなさそう…テナントをワンルームとして掲載しているようです。
葛飾区にもひとつだけぶっ飛んだ外れ値があるので見てみます。
f:id:saddle93:20200405162349p:plainf:id:saddle93:20200405162443p:plain
サンルーチェ 葛飾区柴又
柴又にある普通の1Kのように見えて家賃102万円!これはどうかんがえてもおかしいですね。おそらく誤植です。102万円の家賃に対して管理費5000円がアンバランスです。
外れ値が大きくて見づらいので拡大します。
f:id:saddle93:20200405145021p:plain
東京23区の賃料相場と物件数
中央値順(オレンジライン)に並べ替えています。都心で一人暮らしするには最低でも家賃6万円は見ておかないといけないということがわかります。また,物件数は新宿区がぶっちぎりで多いですね。「新宿区市」というものが混ざっていますが,これは新宿区市ヶ谷の住所が処理の中で「市」で区切られてしまった弊害です。今回は目をつぶってほしい。
比較のために名古屋市の相場を見てみます。
f:id:saddle93:20200405145650p:plain
名古屋市の賃料相場と物件数
三大都市圏の一角とはいえ,東京に比べるとだいぶ安いです。
では最も賃料相場が高い東京都港区をさらに細かく字ごとに見ていきます。
f:id:saddle93:20200405150419p:plain
東京都港区の賃料相場と物件数
北青山がぶっちぎりで高い。次いで元赤坂が高いですが,そもそも元赤坂って住めるんですね。元赤坂は赤坂御用地のはず…
f:id:saddle93:20200405150820p:plain
若干住宅用地がありそう
港区民の肩書が欲しい人は三田で家を探しましょう。
このようにいろんな単位で賃料相場を見ることができるようになりました。

コミケに始発で行ける駅で最も安いエリアはどこか

東京23区に加え,西東京市(保谷駅),千葉県内京葉線沿線,京浜東北線埼玉神奈川県沿線の賃貸データをマージしてひとつの賃貸データファイルにします。約100,000件の物件データをもつファイル(約35MB)になりました。その100,000件の物件データから,最寄り駅が国際展示場駅に5:43までに到着できる駅に絞ります。ここでいう最寄り駅は,物件情報に3つ書いてある最寄り駅の1番目の駅を指します。この絞り込みもPythonを使ってやりました。

f:id:saddle93:20200405153414p:plain
27%近くまで絞れた
ではまず賃料相場が高い駅TOP20
f:id:saddle93:20200405155158p:plain
高賃料相場駅TOP20
西武新宿駅がトップですがそもそも物件数がないので参考になりません。そこそこ物件数があるところだとトップは御成門,浜松町のエリアでした。要は港区です。
次に賃料相場が安い駅40
f:id:saddle93:20200405160946p:plain
安賃料相場駅TOP40
検見川浜,南船橋蘇我京葉線の駅がTOP3を占めました。物件数がそこそこあるところで見ると,蘇我保谷葛西臨海公園,蕨がどうも安そう。蘇我保谷は当初の予想通りでしたが,葛西臨海公園は意外でした。さすが江戸川区
でも最低でも家賃は5万円見ておかないといけなさそうです。保谷ですでに中央値が5万円を上回っています。ちなみに山手線内の駅で最も安いのは西日暮里駅でした。

結論

コミケに始発で行ける駅で賃料相場が安いのは,
蘇我駅保谷駅葛西臨海公園駅蕨駅
でした。

次はさらにこの駅からお得な物件を探してみます。

コミケに始発で行けるお得な物件をPythonを使って探そう #2 コミケ駅別始発到着時刻調査編

#1に続き,今回はコミケに始発で行ける駅を特定します。
saddlenreport.hatenablog.jp

同じくwebスクレイピングを使用しますが,前回とは少しやり方が異なります。
終結果だけ見たい人は「首都圏の各駅から始発で国際展示場に何時に着けるか」までとんでください。

やりたいこと

  • 調べたい駅の一覧のcsvを読み込む
  • その駅から「国際展示場駅」まで始発で行くときの出発時刻と到着時刻と運賃の取得
  • 到着時刻が早い順に並べ替え
  • 結果の出力

調べたい駅の一覧のcsvの作成

以下のようなcsvを用意します
f:id:saddle93:20200401222412p:plain
そのまま駅名を羅列します。路線別にまとめて並べています。複数路線が乗り入れる駅は路線の数分重複しています。こうすることで,初電の列車がどこ始発なのかがわかりやすくなります。(例えば京浜東北線南行初電は南浦和駅始発)
このときなんの文字コードで書いたかを確認しておく必要があります。駅データの一覧は以下のサイトからフリーでダウンロードできるので活用しました。このデータはutf-8で書かれています。
ekidata.jp

コード

コード自体は短くまとめることができます。

from bs4 import BeautifulSoup
from selenium import webdriver
import csv
import pprint
import pandas as pd
from pandas import Series, DataFrame
import time
import sys
import unicodedata

sta =[]

filename = 'sotetsu'
csvname = filename + '.csv'

for cols in csv.reader(open(csvname), delimiter=','):
    val = cols[0]
    sta.append(val)

fare = []
deptime = []
arrtime = []

# Chrome用ドライバー読込
v_browser = webdriver.Chrome('D:\python\chromedriver.exe')
# 路線検索サイトを開く
v_browser.get('http://transit.yahoo.co.jp')

for i in range(len(sta)):

    # サイトの出発駅の場所を特定
    v_sfrom = v_browser.find_element_by_id("sfrom")
    # 出発駅を入力
    v_sfrom.send_keys(sta[i])
    # サイトの到着駅の場所を特定
    v_sto = v_browser.find_element_by_id('sto')
    # 到着駅を入力
    v_sto.send_keys('国際展示場')
    #始発を選択
    radioButton = v_browser.find_element_by_id("tsFir");
    radioButton.click();

    v_sto.submit()

    # 運賃を取得し、円を取り除く
    v_fare = v_browser.find_element_by_class_name('fare').text.replace('円','')
    # 運賃からカンマを取り除く
    v_fare_int = v_fare.replace(',','')
    #出発時刻を取得
    v_deptime_0 = v_browser.find_elements_by_class_name('time')
    v_deptime_1 = v_deptime_0[1].text.split('→')
    v_deptime = v_deptime_1[0]
    #運行に異常がある場合,[!]が出るので削除
    if '[!]' in v_deptime:
        v_deptime = v_deptime.replace('[!]','')


    #到着時刻を取得
    v_arrtime = v_browser.find_element_by_class_name('mark').text

    print(str(i+1) + '/' + str(len(sta)))
    print(sta[i])
    print(v_fare_int)
    print(v_deptime)
    print(v_arrtime)

    fare.append(v_fare_int)
    deptime.append(v_deptime)
    arrtime.append(v_arrtime)

    #プログラムを10秒間停止する(スクレイピングマナー)
    time.sleep(10)

    v_browser.get('http://transit.yahoo.co.jp')

# ブラウザを閉じる
v_browser.close()


#各配列をシリーズ化
sta = Series(sta)
fare = Series(fare)
deptime = Series(deptime)
arrtime = Series(arrtime)

output_df = pd.concat([sta,deptime,arrtime,fare], axis=1)
output_df.columns=['出発駅','出発時刻','到着時刻','運賃']
output_df = output_df.rename_axis('MyIdx').sort_values(['到着時刻','MyIdx'])

output_df.to_csv(filename + '_res.csv', sep = '\t',encoding='utf-16')

print('csv出力完了')

上記のコードは自分で作成した相鉄線の駅一覧のデータシート"sotetsu.csv"を読み込んで始発到着時刻を調べるプログラムになっています。
やっていることは

  1. 駅データの読み込み
  2. Chromeドライバの読み込みとYahoo乗り換えサイトオープン
  3. 条件を設定して検索,結果の取得を駅数分繰り返し
  4. ブラウザを閉じて結果をcsv出力

となっています
経由地を設定したいときは以下のコードを追加します

    #サイトの経由駅の場所を特定
    v_svia1 = v_browser.find_element_by_id('svia1')
    #経由駅を入力
    v_svia1.send_keys('新木場')

JR総武中央緩行線の出力結果です

f:id:saddle93:20200402145148p:plain
JR総武中央緩行線の各駅から始発で国際展示場駅に何時に到着できるか
中野~秋葉原の各駅と両国からだと,国際展示場駅に5:43(りんかい線新木場始発)に到着できます。秋葉原と両国の間の浅草橋からだと到着できないのが面白いポイントです。

経由駅の設定による結果の差

いろんな路線でこの処理をしていて気づいたのは,経由駅の設定の仕方で結果が変わってしまうことです。当然だろうと思うかもしれないですが,「経由駅を設定しない検索結果」よりも「経由駅を設定した検索結果」のほうが到着時刻が早くなるケースがありました。
以下に京浜東北線の2つの処理結果を示します。

f:id:saddle93:20200402150056p:plain
経由駅設定なしの結果
f:id:saddle93:20200402150146p:plain
経由駅を「新木場」としたときの結果
南浦和~品川の各駅は同じ5:43着の結果となっていますが,新木場を経由地に設定することで大井町桜木町の各駅からも5:43着が可能になるという結果になりました。これは正直意図しない結果でした。Yahoo路線検索の始発検索は,本当に早く到着できる乗り換えを表示するわけではないそうです。
試しに,大井町から国際展示場で始発検索を2パターンやってみると,
f:id:saddle93:20200402150912p:plain
上が通常検索,下が新木場経由検索
経由地を設定すると10分も早く到着できます。まあ1時間早く出てまで10分先に到着したいか,という話なのですが,コミケ始発組にとって10分は大きな差です。
このように経由地の設定の仕方で到着時刻が変わってしまい,「本当の始発」の特定が現状難しいです。他にゆりかもめを考慮して豊洲経由にすると,また結果が変わります。じゃあ全部新木場経由で検索すればいいじゃないか,と思うかもしれませんがそうすると本来大崎始発に乗れる駅の特定が難しくなります。
これを解決するには経由駅を複数パターン用意してそれぞれ検索し,最も早く到着できるものを記録する,という手段が考えられます。処理時間が数倍になるので自分はやっていません。もしもっとスマートな方法があったら教えてください。

首都圏の各駅から始発で国際展示場に何時に着けるか

以下が調査結果です。青が5:43より前に到着,赤が5:43に到着,緑が5:53までに到着できる駅になります。(2020年3月ダイヤ改正後)

f:id:saddle93:20200402153037p:plain
2020年3月ダイヤ改正
図はinkscapeを使って自作しました。京浜東北線,中央線,京葉線有楽町線沿いが早く到着できる傾向になっています。5:43に到着できる一番遠い駅は保谷蘇我でしょうか。
ちなみに2019年版と比較してみたところ,高円寺~三鷹の各駅がダイヤ改正で始発繰り下げにより5:43に到着できなくなりました。他にも始発繰り下げの影響を受けているところがありました。

問題点

同じ駅名をもつ駅に対応できていません。例えば日吉(東急東横線と山陰線)や霞が関(日比谷線東武東上線)など。
これはまず駅データのマスターから同一駅名を抽出して,辞書的な役割をさせてうまく区別させる必要がありそうです。気が向いたらやってみます。

以上です。
次はいよいよコミケに始発で行ける賃料相場の安い駅を特定します。

コミケに始発で行けるお得な物件をPythonを使って探そう #1 物件情報取得編

物件を探すにあたって,まずは物件情報を一通りそろえなければなりません。そこで,まずはWebスクレイピングでSuumoから物件情報を取得して,csvに書き出します。
以下の記事を参考にしました。
www.analyze-world.com

ベースのコードはこの記事のコードです。そこに少し手を加えました。

前処理

必要なライブラリをインポートして,Suumoのページ数を取得。

#必要なライブラリをインポート
from bs4 import BeautifulSoup
import urllib3
import re
import requests
import pandas as pd
from pandas import Series, DataFrame
import time
import sys
import unicodedata

#URL(賃貸住宅情報 検索結果の1ページ目)
print('URLを入力してください')
url=input()
#url = 'https://suumo.jp/jj/chintai/ichiran/FR301FC001/?ar=030&bs=040&ta=14&sc=14101&sc=14102&sc=14103&sc=14109&cb=0.0&ct=9999999&et=9999999&md=04&md=06&md=07&cn=9999999&mb=0&mt=9999999&shkr1=03&shkr2=03&shkr3=03&shkr4=03&fw2=&srch_navi=1'

print('出力ファイル名を入力してください(拡張子不要)')
csvname=input()


#データ取得
result = requests.get(url)
c = result.content

#HTMLを元に、オブジェクトを作る
soup = BeautifulSoup(c,"html.parser")

#物件リストの部分を切り出し
summary = soup.find("div",{'id':'js-bukkenList'})
#print(summary.prettify())

#ページ数を取得
body = soup.find("body")
pages = body.find_all("div",{'class':'pagination pagination_set-nav'})
pages_text = str(pages)
pages_split = pages_text.split('</a></li>\n</ol>')
pages_split0 = pages_split[0]
pages_split1 = pages_split0[-3:] #4桁ページ数には非対応
pages_split2 = pages_split1.replace('>','')
pages_split2 = pages_split2.replace('"','')
pages_split3 = int(pages_split2)
print(str(pages_split3) + 'pages')

ここで入力するSuumoのURLは,検索結果の最初の1ページ目のものです。
 f:id:saddle93:20200317225502p:plain

f:id:saddle93:20200317225546p:plain
相場を見るにはあまり条件を絞りすぎないほうがよい
これで検索ボタンを押して最初に出てきたページのURLを入力します。そのあと,ページ下部にあるページ遷移ボタンの末尾(「次へ」の左にある数字)を読んで,全ページ数を取得します。

次にURLのリストを作ります。

#URLを入れるリスト
urls = []

#1ページ目を格納
urls.append(url)

#2ページ目から最後のページまでを格納
for i in range(pages_split3-1):
    pg = str(i+2)
    url_page = url + '&page=' + pg
    urls.append(url_page)


#print(urls)

name = [] #マンション名
address = [] #住所
pref = [] #都道府県
city = [] #市
ward = [] #区
town = [] #それ以下
#ad_num = [] #番地
locations0 = [] #立地1つ目(最寄駅/徒歩~分)
loc0_rosen =[]
loc0_sta =[]
loc0_bus=[]
loc0_foot = []
locations1 = [] #立地2つ目(最寄駅/徒歩~分)
loc1_rosen =[]
loc1_sta =[]
loc1_bus = []
loc1_foot = []
locations2 = [] #立地3つ目(最寄駅/徒歩~分)
loc2_rosen =[]
loc2_sta =[]
loc2_bus = []
loc2_foot = []
age = [] #築年数
height = [] #建物高さ
floor = [] #階
rent = [] #賃料
admin = [] #管理費
others = [] #敷/礼/保証/敷引,償却
floor_plan = [] #間取り
area = [] #専有面積
detail_urls=[] #詳細URL
rent_tot=[] #合計賃料

Suumoの検索結果の2ページ目以降はURL末尾に"&page=2"とついているだけなので,手動でこれをつけてやってあとはfor文を回してあげます。あとは取得するデータを格納する空のリストを準備します。もっとスマートな方法があったら教えてください。

住所の取得

次に物件の住所を取得します。あとで解析がしやすいように,都道府県,市区町村,政令区,字以下で分けました。

#各ページで以下の動作をループ
for url in urls:
    #物件リストを切り出し
    result = requests.get(url)
    c = result.content
    soup = BeautifulSoup(c)
    summary = soup.find("div",{'id':'js-bukkenList'})

    #マンション名、住所、立地(最寄駅/徒歩~分)、築年数、建物高さが入っているcassetteitemを全て抜き出し
    cassetteitems = summary.find_all("div",{'class':'cassetteitem'})

    #各cassetteitemsに対し、以下の動作をループ
    for i in range(len(cassetteitems)):
        #各建物から売りに出ている部屋数を取得
        tbodies = cassetteitems[i].find_all('tbody')
        #print(tbodies)
        room_number=len(tbodies)

        #マンション名取得
        subtitle = cassetteitems[i].find_all("div",{
            'class':'cassetteitem_content-title'})
        subtitle = str(subtitle)
        subtitle_rep = subtitle.replace(
            '[<div class="cassetteitem_content-title">', '')
        subtitle_rep2 = subtitle_rep.replace(
            '</div>]', '')

        #住所取得
        subaddress = cassetteitems[i].find_all("li",{
            'class':'cassetteitem_detail-col1'})
        subaddress = str(subaddress)
        subaddress_rep = subaddress.replace(
            '[<li class="cassetteitem_detail-col1">', '')
        subaddress_rep2 = subaddress_rep.replace(
            '</li>]', '')

        #住所から都県抜き出し
        if '県' in subaddress_rep2:
            temp_address1=subaddress_rep2.split('県',1)
            pref_temp1=temp_address1[0]+'県'
        elif '都' in subaddress_rep2:
            temp_address1=subaddress_rep2.split('都',1)
            pref_temp1=temp_address1[0]+'都'

        #住所から市町村と東京特別区を抜き出し
        if '市' in temp_address1[1]:
            temp_address2=temp_address1[1].split('市',1)
            city_temp1=temp_address2[0]+'市'
        elif '区' in temp_address1[1]:
            temp_address2=temp_address1[1].split('区',1)
            city_temp1=temp_address2[0]+'区'
        elif '町' in temp_address1[1]:
            temp_address2=temp_address1[1].split('町',1)
            city_temp1=temp_address2[0]+'町'
        elif '村' in temp_address1[1]:
            temp_address2=temp_address1[1].split('村',1)
            city_temp1=temp_address2[0]+'村'

        #住所から政令指定都市の区を抜き出し
        if '区' in temp_address2[1]:
            temp_address3=temp_address2[1].split('区',1)
            ward_temp1=temp_address3[0]+'区'
            temp_address4=temp_address3[1]
        else:
            ward_temp1 = None
            temp_address4 = temp_address2[1]

        #字の抜き出し
        uni = unicodedata.east_asian_width(temp_address4[-1])
        if uni == 'F':
            town_temp1=temp_address4[:-1]
        else:
            town_temp1=temp_address4


        #部屋数だけ、マンション名と住所を繰り返しリストに格納(部屋情報と数を合致させるため)
        for y in range(len(tbodies)):
            name.append(subtitle_rep2)
            address.append(subaddress_rep2)
            pref.append(pref_temp1)
            city.append(city_temp1)
            ward.append(ward_temp1)
            town.append(town_temp1)

かなりパワープレーみたいな書き方になっています。例えばこの書き方だと,都城市市原市のような地名に対応できません。全部対応させようするとかなり長いコードになりそうな気がしたので,今回はここまでにしました。

立地・築年数・建物高さの取得

駅から徒歩〇分や駅からバスで△分徒歩◇分のような立地と築年数と建物高さを取得します
Suumoの立地表記はだいたい以下2つの様式です。

ですがたまにイレギュラーがあります。Suumoの表記の仕方に特に決まりはないようで,例えば

のように書かれていることもあります。宇須ってなんだよと思いましたが,宇都宮線横須賀線を表しているようです。こういうイレギュラーがあるだけであとの解析が面倒になります。他に「車で〇分」だったりそもそも路線を書かずバス路線系統と停留所しか書かれていないものもありました。

       tempcassette=cassetteitems[i]
       #立地を取得
        sublocations = cassetteitems[i].find_all("li",{
            'class':'cassetteitem_detail-col2'})
        #立地は、1つ目から3つ目までを取得(4つ目以降は無視)
        for x in sublocations:
            cols = x.find_all('div')
            for i in range(len(cols)):
                text = cols[i].find(text=True)
                if text != None:
                    split01 = text.split('/',1)
                    subloc_rosen = split01[0]
                    if '歩'  in split01[1]:
                        split02 = split01[1].split(' 歩',1)
                        if ' バス' in split02[0]:
                            split03 = split02[0].split(' バス', 1)
                            subloc_sta = split03[0]
                            print(split03[1])
                            split04 = split03[1].split('分', 1)
                            subloc_bus = split04[0]
                        else:
                            subloc_sta = split02[0]
                            subloc_bus = None
                        subloc_foot = split02[1]
                        subloc_foot = subloc_foot.strip('分')
                    else: #歩きじゃない場合は削除
                        subloc_rosen = None
                        subloc_sta = None
                        subloc_bus = None
                        subloc_foot = None
                else:
                    subloc_rosen = None
                    subloc_sta = None
                    subloc_bus = None
                    subloc_foot = None

                for y in range(len(tbodies)):
                    if i == 0:
                        locations0.append(text)
                        loc0_rosen.append(subloc_rosen)
                        loc0_sta.append(subloc_sta)
                        loc0_bus.append(subloc_bus)
                        loc0_foot.append(subloc_foot)
                    elif i == 1:
                        locations1.append(text)
                        loc1_rosen.append(subloc_rosen)
                        loc1_sta.append(subloc_sta)
                        loc1_bus.append(subloc_bus)
                        loc1_foot.append(subloc_foot)
                    elif i == 2:
                        locations2.append(text)
                        loc2_rosen.append(subloc_rosen)
                        loc2_sta.append(subloc_sta)
                        loc2_bus.append(subloc_bus)
                        loc2_foot.append(subloc_foot)

        #築年数と建物高さを取得
        #なぜか仮で別の変数に入れ直さないとうまくいかない
        age_and_height = tempcassette.find('li', class_='cassetteitem_detail-col3')
        _age = age_and_height('div')[0].text
        _height = age_and_height('div')[1].text
        if _age == '新築':
            _age = _age.replace('新築','0')
        else:
            _age = _age.strip('築')
            _age = _age.strip('年')

        for i in range(room_number):
            age.append(_age)
            height.append(_height)

歩きを伴わない立地は後の処理で面倒になりそうだったので削除しました。
新築は0年に置き換え,すべて数値型で扱えるようにします。
住所と同様に同じ建物の部屋数分だけ配列に追加します。
このとき,なぜかtempcassetteという仮の別の変数に入れ直さないと動きませんでした。結局原因はわかっていません。

賃料など部屋ごとのステータスの取得

最後に部屋ごとの各ステータスを取得します。

    #階、賃料、管理費、敷/礼/保証/敷引,償却、間取り、専有面積が入っているtableを全て抜き出し
    tables = summary.find_all('table')


    #各建物(table)に対して、売りに出ている部屋(row)を取得
    rows = []
    for i in range(len(tables)):
        rows.append(tables[i].find_all('tr'))

    #各部屋に対して、tableに入っているtext情報を取得し、dataリストに格納
    data = []
    for row in rows:
        for tr in row:
            cols = tr.find_all('td')
            if len(cols) != 0:
                _floor0 = cols[2].text
                _floor0 = re.sub('[\r\n\t]', '', _floor0)
                if _floor0 == '-':
                    _floor = '1'
                else:
                    split_fl = _floor0.split('-')
                    _floor = _floor0[0].strip('階')

                _rent_cell = cols[3].find('ul').find_all('li')
                _rent = _rent_cell[0].find('span').text
                _rent = _rent.replace(u'万円',u'')
                _admin = _rent_cell[1].find('span').text
                if _admin == '-':
                    _admin = _admin.replace('-','0')
                else:
                    _admin = _admin.strip('円')
                    _admin = int(_admin)/10000

                _rent_tot = float(_rent) + float(_admin)
                _rent_tot = round(_rent_tot,2)
                _deposit_cell = cols[4].find('ul').find_all('li')
                _deposit = _deposit_cell[0].find('span').text
                _reikin = _deposit_cell[1].find('span').text
                _others = _deposit + '/' + _reikin

                _floor_cell = cols[5].find('ul').find_all('li')
                _floor_plan = _floor_cell[0].find('span').text
                _area = _floor_cell[1].find('span').text
                _area = _area.replace(u'm2',u'')

                _detail_url = cols[8].find('a')['href']
                _detail_url = 'https://suumo.jp' + _detail_url

                text = [_floor, _rent, _admin, _others, _floor_plan, _area, _detail_url, _rent_tot]
                data.append(text)

    for row in data:
        floor.append(row[0])
        rent.append(row[1])
        admin.append(row[2])
        others.append(row[3])
        floor_plan.append(row[4])
        area.append(row[5])
        detail_urls.append(row[6])
        rent_tot.append(row[7])

    print(len(data))
    print(url + '完了')
    #プログラムを10秒間停止する(スクレイピングマナー)
    time.sleep(10)

部屋ごとにステータス欄のhtmlコードを配列に格納し,それを分解して各ステータスを指定の配列に追加していきます。
敷金礼金は数値化していません。必要になったらしようかなと思っています。

出力処理

csvに出力します。

#各リストをシリーズ化
name = Series(name)
address = Series(address)
pref = Series(pref)
city = Series(city)
ward = Series(ward)
town = Series(town)
locations0 = Series(locations0)
loc0_rosen = Series(loc0_rosen)
loc0_sta = Series(loc0_sta)
loc0_bus = Series(loc0_bus)
loc0_foot = Series(loc0_foot)
locations1 = Series(locations1)
loc1_rosen = Series(loc1_rosen)
loc1_sta = Series(loc1_sta)
loc1_bus = Series(loc1_bus)
loc1_foot = Series(loc1_foot)
locations2 = Series(locations2)
loc2_rosen = Series(loc2_rosen)
loc2_sta = Series(loc2_sta)
loc2_bus = Series(loc2_bus)
loc2_foot = Series(loc2_foot)
age = Series(age)
height = Series(height)
floor = Series(floor)
rent = Series(rent)
admin = Series(admin)
others = Series(others)
floor_plan = Series(floor_plan)
area = Series(area)
detail_urls = Series(detail_urls)
rent_tot = Series(rent_tot)

suumo_df = pd.concat([name, pref,city, ward,town, loc0_rosen,loc0_sta,loc0_bus,loc0_foot,loc1_rosen,loc1_sta,loc1_bus,loc1_foot,loc2_rosen,loc2_sta,loc2_bus,loc2_foot, age, height, floor, rent, admin,rent_tot, others, floor_plan, area, detail_urls], axis=1)

suumo_df.columns=['マンション名','都県','市区町村','区','字','立地1_路線','立地1_駅','立地1_バス','立地1_徒歩[分]','立地2_路線','立地2_駅','立地2_バス','立地2_徒歩[分]','立地3_路線','立地3_駅','立地3_バス','立地3_徒歩[分]',\
'築年数','建物の高さ','階層','賃料料[万円]','管理費[万円]','合計賃料[万円]', '敷/礼/保証/敷引,償却','間取り','専有面積[m2]', '詳細URL']

suumo_df.to_csv('resdata/' + csvname + '.csv', sep = '\t',encoding='utf-16')

print('csv出力完了')

シリーズ化するのが面倒です。一括でできるコマンドはないのか…
文字コードUTF-16で,タブ区切りで出力していますが特に意味はないです。参考にした記事を書いた方がそうしていたからです。

これで以下のようなcsvを出力することができます。

f:id:saddle93:20200401215852p:plain
東京都練馬区の例
試しに東京都中央区の一番賃料が高い1Kの物件を見てみましょう
f:id:saddle93:20200401224720p:plain
STUDIOと書いてあるが…
f:id:saddle93:20200401224841p:plain
KDXレジデンス日本橋人形町 日比谷線人形町徒歩3分で家賃月113万円!
どういう層に需要があるんでしょうか…

一連の処理の問題として感じられたのは以下の通り

  • すべての市区町村名に対応できない
  • 立地表記ゆれに対応できない
  • 処理中にネット回線が不安定になると処理失敗になる
  • 少ないページ数に対応できない

上2つは前述のとおりです。
3つ目に関して,非常に多くの物件を取得しようすると長い時間がかかります。その途中でネットの回線が不安定になると,処理が止まりいままでの処理がなかったことになります。これは一番最後にcsv出力する仕様になっているためです。
4つ目は,ページ数取得がうまくいきません。以下のページ番号リンクの「...」の右の番号を参照しているからです。「...」が現れないケースはページ数を取得できません。
f:id:saddle93:20200401162039p:plain
また,1回だけですが,処理中に物件が消されて最初に取得したページ数より少ないページになってしまうケースがありました。これは非常にレアケースなので無視しました。

以上です。次はコミケに始発で行ける駅を特定します。

コミケに始発で行けるお得な物件をPythonを使って探そう #0

いまは年度末の引っ越しシーズンですが,コミケに真剣なオタクにとっては「コミケに始発で行ける」というのは引越における重要なファクターです。今回,Pythonを使ってコミケに始発で行けるお得な物件を機械的に探してみました。

f:id:saddle93:20191230062203j:plain

6:00でこの人の量(C97)

バックグラウンド

背景としては,大きく2つ

  • 最近会社でPythonを使い始めそうな雰囲気があるので,家でまずPythonを触ってみようと思い立ったこと
  • 自分の引越が近いこと

自分の会社はゴリゴリの機械系メーカーなのでIT技術とはほど遠い人材が多いです。VBAは使える人がそこそこいるけど,Pythonはほとんどいない,といった状況です。最近会社で開発しているツールにPythonを導入しだしているので,個人的に始めてみようと思いました。

題材探しをしている中で以下の記事を見つけ,見よう見まねで始めてみました。

www.analyze-world.com

 

ちなみにPythonの環境を整えたのは2019年11月なので,まだPython歴5か月程度です。

コミケの始発については以下の記事を参考にしてください。

https://azumichannel.com/comike-sihatu-saisoku-1/

 

物件探しプロセス

おおまかなプロセスとしては以下の通りです

  1. WebスクレイピングでSuumoから物件情報を取得する
  2. WebスクレイピングでYahoo乗り換えから国際展示場(有明)に始発で到着できる駅を取得する
  3. 物件情報から始発で行ける駅でフィルタをかけて,賃料の安い駅を特定する
  4. 非優越ソートで賃料の安い駅付近のお得な物件を見つける

1に関してはすでにやっている人がいるので,それを参考にしつつ,自分が使いやすいように機能を加えました。

2は,ひたすら繰り返しYahoo乗り換え検索で時間を調べて,時刻を取得します。

3は始発で行ける駅の中で最も賃料相場が安い駅を特定します。

4はいまいち方法を確立できていないのですが,非優越ソートまたは機械学習?を使ってお得な物件を見つけてみます。

賃料相場は以下のように箱ひげ図で見ることにしました。

f:id:saddle93:20200317221639p:plain

江東区の1Kの駅別賃料相場(箱ひげ図)

当たり前ですが,ビッグサイトに近いエリアは賃料相場が高いことがわかります。14~15万円/月の賃料を払える能力は自分にはありません。

 

物件探しについて全4+1記事でまとめるつもりです。現時点で3までできています。4まで行くかどうかは時間と気力次第。

国道339号線 龍泊ラインを走る

自転車ツアラーやロードバイクホビーライダーだと「好きな国道はどこか」という話題になることがあると思います。そんなとき,なんと答えますか

1号線や7号線のような景色が良いところがある幹線国道,425号線や439号線のような有名な酷道を答える人が多い印象です。そもそも好きな道はあるけど国道の番号なんて覚えてないよという人が大半ですが。

自分の一番好きな国道は国道339号線です。そこそこ走ってる人でもどこだよって言われることが多いです。その手に詳しい人だと階段国道が連想されると思います。

今回はこの国道339号線を実際に走ったレポートとともに紹介します。

国道339号線とは

Wikipediaには以下のように書かれています。

青森県弘前市から津軽平野を北上して五所川原市を経由し、津軽半島北端の津軽海峡に至る延長約127キロメートル (km) の一般国道の路線で、主な通過地は、南津軽郡藤崎町北津軽郡板柳町、鶴田町、五所川原市中泊町大字中里、同町大字小泊である。津軽半島の中央部を南北に縦断する道路で、半島北部は日本海側に道路が沿っており、龍飛崎と小泊を結ぶ区間は通称「竜泊ライン(たつどまりライン)」とよばれる。東津軽郡外ヶ浜町龍飛の龍飛岬附近に、階段と歩道で構成された車両通行不能区間があり、「階段国道」の名で特に知られる[1][2]。

国道339号 - Wikipedia

もっと有名なのは階段国道です。また龍飛岬に行く人がおそらく必ず走る道です。

DSC04885

階段国道 荷物積載した自転車ではキツいと判断

ツーリングでわざわざ通るようなところではないので,走ったことがある人は少ないかと思います。北海道に向かうサイクリング部員はだいたい青森か八戸からフェリーに乗るか,下北半島を走って大間を目指します。龍飛岬を目指す人でもアクセスしやすい東岸から行く人が多いです。

しかし,ダイナミックな道路と景色は津軽半島西岸にありました。

龍泊ライン

走ったのは2016年夏です。横手,由利本荘市大潟村深浦町を経由して五所川原市から龍飛を目指したツーリングで走りました。実際には十三湖までひとつ西側の県道12号を走ったので,国道339号線で走ったのはそれより北から外ヶ浜町三厩までです。

DSC04789

十三湖

県道12号は車も少なく道もそこそこ広く走りやすかったです。

十三湖を過ぎると国道339号線は海沿い,というか海にへばりつくような道になります。

DSC04809

▲海沿い国道でもここまで海の際にある国道はなかなかない

中泊町の小泊地区では美味しい海鮮料理が安く食べられます。自分は「小泊おさかな海岸」というところで食べました。

DSC04814

▲ボリュームも十分

 この小泊地区を過ぎるといよいよ本番,民家もなくなり壮大な自然を感じることができます。

DSC04819

▲青と緑のコントラストが個人的にすごく好き

DSC04829

▲文字通り道がへばりついている

龍飛岬に近づいてくると,断崖絶壁すぎて海沿いに道路が建設できなかったのか,山を登り始めます。この登りはかなりきついですが,ところどころ登りながら日本海を望むことができます。

DSC04850

DSC04853

道路のピークは眺瞰台というところで,ここからの眺めも格別です。こんなに海が近いのに標高が500m近くあります。

DSC04867

▲龍飛岬と津軽海峡,その先の北海道まで

ここまで山と海が融合した景色は初めてだったので,非常に感動した記憶があります。なお,冬季はこの区間(龍飛岬から小泊地区まで)は通行止めです。

DSC04871

▲北海道を見ながら龍飛岬へ下る

前を走るローディーは龍泊ラインを一緒に走った人です。最後の眺瞰台への登りがキツすぎて一緒に押してました。

龍飛岬と青函トンネル記念館

龍泊ラインは車も人も全然いませんが,龍飛岬まで来ると人がそこそこ多くなります。この岬の直下を青函トンネルが貫いています。また,青函トンネルの工事の基地でもあったため,記念館があります。青函トンネルの建設経緯、工法や津軽海峡の地質など学ぶことができます。実際のトンネルの大きさも展示で体感できます。

DSC04876

この青函トンネル記念館,できてからかなりの年月が経っています。青函トンネル紹介ビデオに出てくるモグラのキャラクターのおじいさん,お父さん,子供がいるんですが,そのモグラのキャラクターの子供がビデオ内で国鉄民営化を見たことがあると言っていたので,自分より年上でした。そろそろビデオを作り直したほうがいいんじゃないでしょうか。

DSC04894

青函トンネルは34名もの犠牲の上に完成した

国道の終点と青函トンネル入口

 国道の終点は外ヶ浜町三厩という地区にあります。この三厩はかつて青函トンネルができる前,北海道に渡るフェリーが出ていました。そのため,ところどころその遺構が残っており,雰囲気があります。そういうかつて栄えた跡が個人的に好きです。

DSC04895

▲突然この看板を境に国道280号線になる

DSC04896

▲かつて三厩と北海道の福島町を結んでいた東日本フェリー

こういった看板が錆びついても残っていたのがすごい印象的でした。この三厩福島航路が残っていたら,道南エリア松前のあたりのツーリングの幅が広がったのかと思います。

この近くに青函トンネルの入口があります。公共交通機関での到達は困難です。バイパスからさらに白道を行ったところにあります。

 広場は最近整備されたのかきれいでした。青函トンネル入口は自転車ツーリングでは行くのに労力がかからない反面,ちょっと話のネタになるので是非。

DSC04904

▲トンネルから列車が出る直前にトンネル坑口に雲ができる

 

以上,国道339号線のレポートでした。津軽半島西海岸,すごく良いので是非行ってみてください。個人的に青森県が好きなので,今後も自転車で走って開拓しようと思います。

DSC04945

 

 

BIKE24でTHULEの車載サイクルキャリアを買った

この度自動車を購入するにあたって,せっかくなので車載サイクルキャリアを購入しようと思いました。やはり有名で評価も高いのがTHULEです。

www.thule.com

基本的にルーフにサイクルキャリアを搭載するには

  • 車種別KIT
  • フット
  • バー
  • サイクルキャリア本体

の4点セットが必要です。自分の車にはどのKITとフットが合うのかはTHULEのHPで確認できます。しかし,これら定価で買うとめちゃめちゃ高いんです。なので,なんとかして安く手に入れたいと思い,まわりのユーザーに聞いてみました。

CRCでトータル5万円くらいで揃えたという人がいたので,CRCを見てみたらもう取り扱いをしていないらしい。どうやら2017年の夏くらいに爆安で売り出してそれっきりみたいです。

Amazonとか楽天で出てくる国内代理店はサイクルキャリア本体だけで2.5万くらいで高め。

海外通販だと2018年夏時点でBikeinnが最安でした。しかし,日本への送料で2万円くらい取られるっぽくて結局高い。そこで見つけたのがBIKE24です。

BIKE24はフットとKITは扱っていないようだったので,サイクルキャリア本体Proride 598とWingbar969を注文しました。

www.bike24.com

www.bike24.com

Proride2つとWingbar1pair,送料梱包料60ユーロを含めて339,54ユーロでした。日本円にして45,000円くらいです。

フットはヤフオクで中古で8,000円,KITはAmazonで6000円くらいで買いました。

つまりトータルで6万円くらいで揃えることができました。

届くまでのプロセスはこんな感じ。

f:id:saddle93:20180917200610p:plain

9/5に注文して,9/7に発送,それから10日後に届きました。国際交換局あたりのトラッキングが全くないので不安になるところもありましたが,どっかいってしまうこともなく無事に届きました。BIKE24は初めて利用しましたが,WiggleやCycling Expressに敵わないにしても海外通販では優良なほうではないでしょうか。

取り付け説明書は文字が非常に少なく,基本絵で示されています。ハサミやメジャーを使用しました。2人で作業して約1時間かかりました。取り付け後自転車を載せて家の周りを試しに走り,問題がないことを確認しました。

現時点でも特に異常はなく使えています。フレームサイズによってはボトルゲージが干渉して載せられないということもありました。(ボトルゲージを外して対応した)

f:id:saddle93:20190115221816j:plain

 

【フィンランド自転車ツーリング】8, 9日目 サンタクロースエクスプレス乗車記・ヘルシンキを自転車で走る

前の記事からだいぶ間が空いてしまいましたが,フィンランド自転車ツーリングの最後の記事です。

 サンタクロースエクスプレス

DSC06871

▲InterCity274が正式な列車名 

 サンタクロースエクスプレスとはヘルシンキとRovaniemiの間を結ぶ夜行列車です。およそ東京から大阪までの距離を約12時間かけて走ります。1日2往復でRovaniemi発は18時と21時となっており,利用しやすい時間に走っています。

チケットはVRのホームページで買えますが,寝台はPCからでないと買えません。というのも,寝台券を購入するときに座席を選ぶのですが,その選ぶ画面がスマートフォンでは動作しませんでした。

座席の種類は大きく分けて普通の座席,個室座席,寝台相部屋,寝台個室です。シャワーやトイレつき個室もあります。その順番に値段も高くなります。自分は寝台個室で23,000円くらいでした。日本のB寝台と同じくらいです。

普通座席の様子も見ましたが,さながらムーンライトながらのようで観光利用にはおすすめしません。

チケットを買うと登録したメールアドレスにQRコードが送られてきます。それを車掌さんに見せればOKです。他の日本人ツアー客はみんな予約画面を印刷してきていて,日本の紙媒体文化を垣間見ました。

DSC06878

▲個室寝台

DSC06882

▲タオルやお水のサービスもあります

編成が長い上,自転車を載せる車両がどこだかわからないので,入線時はしっかりとホームで自転車にまたがり,入ってくる列車の自転車マークを探してそれに向かって走ります。予約した寝台が自転車車両と遠いと延々列車内を歩くことになります。予約時に決済直前の画面で自転車を載せる車両が何号車かがわかるので,そこで一旦キャンセルして近い車両に予約しなおすというテクニックを帰国してから見つけました。

食堂車もあり,特に何も買わずに乗っても大丈夫ですが,割と混んでいます。

DSC06894

売店

田舎の線形のいい線路では200km/h以上で走るので,12時間はどう考えてもかかりません。いろんな駅で時間調整を行っていました。ヘルシンキ駅3kmくらい手前の操車場の待避線で,45分くらい止まっていたのにはビックリしました。それでも定時で到着です。

DSC06898

ヘルシンキ駅到着

動力集中方式(機関車と客車)で走るので,騒音や振動もなく快適でした。

8, 9日目 自転車でヘルシンキ散策

結論から言うと,冬のヘルシンキは自転車に乗るのには適していません。 

ヘルシンキで2日間自転車で散策する予定でしたが,1日目でこれに気付き2日目は自転車を捨てて観光してました。

石畳+凍結という高難易度の路面,踏み荒らされて凸凹に凍った路肩や歩道,充実したトラム網といった理由から,自転車に乗る必要がありませんでした。たいていのスポットはトラムで行けます。郊外は地下鉄+バスで行けます。市内のほとんどの交通機関に乗れるフリーパスがすごく安いのでおすすめです。

DSC07168

▲フリーパスはアプリをダウンロード→クレジットカードを登録→購入で終わり。時間制のフリーパスなので使い勝手が良い。

というわけで行った観光地をいくつか紹介します。

DSC06972

スオメンリンナの要塞

戦争で実際に使われていた要塞です。アニメ ブレイブウィッチーズの舞台となっています。要塞までは渡船で行けます。渡船は当然のように砕氷船です。

DSC07006

▲船によって砕かれた氷が浮いている

DSC07047

▲デザイン美術館

フィンランドはデザインの国で有名なので行ってみました。デザインの考え方や歴史について学ぶことができます。英語でも説明が書かれているので理解できます。

DSC07058

フラットデザインの考え方

DSC07105

▲Löyly Helsinki

観光客向け公衆サウナです。というか普通にインターネットで調べてもこういう観光客向けしかヒットしません。男女共同で水着を着て入るタイプのサウナです。ビールも飲めるし,水風呂と称して凍結した海にも入れます。

DSC07107

▲更衣室入口

フィンランドサウナを調べるにあたり,コミケでこちらのサークルの同人誌を購入して参考にさせていただきました。実際にいろんなヘルシンキのサウナに行ってレポートをしています。インターネットではヒットしにくい公衆サウナもレポートされているのでぜひ。

curry-sauna.hatenablog.com

DSC07193

HJKヘルシンキの公式ショップ

DSC07078

▲海は凍結して公園のようになっており,市民の憩いの場になっていた

DSC07229

DSC07203

▲そこらじゅうにトラムが走っている

いろいろな行先のトラムが同じ線路を走っているので,例えば東京メトロとかで迷ってしまう人にはつらいかもしれない。

DSC07264

▲トラムの路線図

他にも観光スポットには行きましたが,そういうことはガイドブックのほうが参考になると思うので書きません。

ヘルシンキ Vantaa空港から同じくfinnairでセントレアへ帰りました。帰りの飛行機輪行はペダルを外しませんでしたが,特にトラブルはありませんでした。空港のカウンターでこんなソフトな梱包では預かれない的なことを言われましたが,往きはこれで預けたと言ったら預かってもらえました。

Vantaa空港は保安検査通過後のほうが,ショップが充実しているのでさっさと保安検査場を通過するのをお勧めします。

DSC07302

DSC07313

 

以上でフィンランド自転車ツーリングは完結です。治安もいいしなにより冬は空気が気持ちいいのでぜひ冬のフィンランドへ自転車で行ってみてください。