物件検索サイト「スーモ」からスクレイピングした物件情報の中から、ハザードマップの危険エリア外の物件だけをGooglemap上などにプロットし可視化するサービスを考えています。
現在の状況ですが、スーモから物件情報はクローリング&スクレイピングできました。
この情報から危険エリア外の物件だけを可視化したいと思っています。
ネット上で調べてみましたが、ハザードマップの危険エリアの位置情報はどうも落とせそうにありませんでした。
ご存じの方がいらっしゃいましたら、ご教授お願い致します。
ちなみにクローリングコードは以下です。
python
1import requests 2#Requestsを使用するとWebサイトの情報取得や画像の収集などを簡単に行うことが出来る 3from bs4 import BeautifulSoup 4#BeautifulSoupはスクレイピングに特化したモジュール 5#htmlファイルをタグ情報から解析し、抽出データを格納したインスタンスを返す。 6import os 7#osモジュール 8import time 9#時刻に関する様々な関数を提供 10#通勤時間20分、40分、60分場合分け 11for folder in 20, 40, 60: 12 # ディレクトリの場合分け 13 dirname = "htmlbox{}".format(folder) 14 #20分以内と40分以内、60分以内の3つのページをそれぞれ別々のフォルダに保存 15 if not os.path.exists(dirname): 16 #pythonでフォルダの存在確認 17 # ディレクトリ作成 18 os.mkdir(dirname) 19 # それぞれの1ページ目をhtml化 20 if folder == 20: 21 base_url = "https://suumo.jp/jj/chintai/ichiran/FR301FC001/?ar=030&ta=13&bs=040&ekInput=00320&tj=20&nk=-1&ct=9999999&cb=0.0&et=9999999&mt=9999999&mb=0&cn=9999999&shkr1=03&shkr2=03&shkr3=03&shkr4=03&fw2=&pc=30" 22 if folder == 40: 23 base_url = "https://suumo.jp/jj/chintai/ichiran/FR301FC001/?ar=030&ta=13&bs=040&ekInput=00320&tj=40&nk=-1&ct=9999999&cb=0.0&et=9999999&mt=9999999&mb=0&cn=9999999&shkr1=03&shkr2=03&shkr3=03&shkr4=03&fw2=&pc=30" 24 if folder == 60: 25 base_url = "https://suumo.jp/jj/chintai/ichiran/FR301FC001/?ar=030&ta=13&bs=040&ekInput=00320&tj=60&nk=-1&ct=9999999&cb=0.0&et=9999999&mt=9999999&mb=0&cn=9999999&shkr1=03&shkr2=03&shkr3=03&shkr4=03&fw2=&pc=30" 26 response = requests.get(base_url) 27 #get()の第一引数にURLを指定するとresponseオブジェクトが取得できる。 28 time.sleep(1) 29 #サーバーに負荷をかけないように間をあける 30 #ファイルに保存 31 with open('htmlbox{}/page1.html'.format(folder), 'w', encoding='utf-8') as file: 32 #with構文は、ファイルの読み込みが必要なコードでよく使われます。 33 #with構文を使うとファイルの読み込みで必要なclose処理を省略することが出来る。 34 file.write(response.text) 35 36 # urlの引き出し 37 soup = BeautifulSoup(response.content, "lxml") 38 39 # 2ページ以降のurlを定義 40 pages = soup.find_all("div", class_="pagination pagination_set-nav") 41 #find_allでdivタグを全て取得 42 pages_text = str(pages) 43 pages_split = pages_text.split('</a></li>\n</ol>') 44 #splitで</a></li>\n</ol>のタグで切り分け 45 num_pages = int(pages_split[0].split('>')[-1]) 46 #2ページ目以降のurlをhtml化 47 for i in range(2, num_pages + 1): 48 next_url = base_url + "&page=" + str(i) 49 #次のページのurlを作成 50 response2 = requests.get(next_url) 51 time.sleep(1) 52 #ファイルに保存 53 with open('htmlbox{}/page{}.html'.format(folder, i), 'w', encoding='utf-8') as file: 54 file.write(response2.text) 55 #検収条件 56 print("{}分圏内の総ページ数".format(folder)) 57 print(num_pages) 58 #実際取れたhtml数と比較 59
スクレイピングコードです。
python
1import requests 2from bs4 import BeautifulSoup 3import os 4import csv 5import pandas as pd 6 7#通学時間20分、40分、60分場合分け 8for folder in 20, 40, 60: 9 if folder == 20: 10 num_html = 1702 #通勤時間が20分以内の取れたhtml数 11 if folder == 40: 12 num_html = 3937 #通勤時間が40分以内の取れたhtml数 13 if folder == 60: 14 num_html = 4580 #通勤時間が60分以内の取れたhtml数 15 for i in range(num_html + 1): 16 #取れたhtml数だけループ 17 if i == 0: 18 #0番目、つまり一番最初はcsvに項目だけ書きこむ 19 with open('sumodata{}.csv'.format(folder), 'w', encoding='CP932',newline="") as file: 20 writer = csv.writer(file) 21 writer.writerow(["subtitle", "location", "station", "times", "years", "heights", 22 "floor", "rent", "admin", "deposit", "gratuity", "madori", "menseki"]) 23 else: 24 with open('htmlbox{}/page{}.html'.format(folder, i), 'r', encoding='utf-8') as file: 25 read = file.read() 26 soup = BeautifulSoup(read, "lxml") 27 cassetteitems = soup.find_all("div", class_="cassetteitem") 28 #soupに入っているlxmlデータからクラスがcassetteitemのdivタグ要素を返す 29 # 建物自体からスクレイピング 30 for cas in range(len(cassetteitems)):#配列cassetteitemsの配列数までループ 31 tbodies = cassetteitems[cas].find_all('tbody')#階・賃料・管理費・敷金・礼金・間取り・専有面積のひとまとまりの情報 32 times1 = cassetteitems[cas].find("ul", class_="cassetteitem_transfer-list")#乗り換え回数・所要時間 33 yearsheights = cassetteitems[cas].find("li", class_="cassetteitem_detail-col3") #築年数 高さ 34 subtitle = cassetteitems[cas].find("div", class_="cassetteitem_content-title").string#物件名 35 location = cassetteitems[cas].find("li", class_="cassetteitem_detail-col1").string#住所 36 station = cassetteitems[cas].find("div", class_="cassetteitem_detail-text").string#最寄り駅 37 times = times1.find("li").string#乗り換え回数・所要時間 38 years = yearsheights.find_all('div')[0].string#築年数 39 heights = yearsheights.find_all('div')[1].string#階数 40 # 一つの建物のうちの部屋数をスクレイピング 41 for tbody in tbodies:#tbodyにtbodiesのデータをひとつづつ取り出す 42 cols = tbody.find_all("td") 43 #colsにtbodyの中のtdタグを全て代入 44 for col, floor1 in enumerate(cols):#インデックス番号, 要素の順に取得できる。 45 if col == 2:#インデックス番号が2の場合 46 floor = floor1.string#floorに物件の階数を代入 47 rent = tbody.find(class_="cassetteitem_price cassetteitem_price--rent").string 48 #リストrentには、物件の家賃を代入 49 admin = tbody.find(class_="cassetteitem_price cassetteitem_price--administration").string 50 #リストadminには、管理費を代入 51 deposit = tbody.find(class_="cassetteitem_price cassetteitem_price--deposit").string 52 #リストdepositには、敷金を代入 53 gratuity = tbody.find(class_="cassetteitem_price cassetteitem_price--gratuity").string 54 #リストgratuityには、礼金を代入 55 madori = tbody.find(class_="cassetteitem_madori").string 56 #リストmadoriには、間取りを代入 57 menseki = tbody.find(class_="cassetteitem_menseki").text 58 #リストmensekiには、専有面積を代入 59 with open('sumodata{}.csv'.format(folder), 'a', encoding='CP932',newline="") as file :#sumodata{}.csvに追記 60 writer = csv.writer(file) 61 writer.writerow([subtitle, location, station, times, years, heights,floor, rent, admin, deposit, gratuity, madori, menseki]) 62 # リストの中身を格納していく 63 #検収条件 64 df = pd.read_csv("sumodata{}.csv".format(folder), encoding="CP932") 65 with open('htmlbox{}/page1.html'.format(folder), 'r', encoding='utf-8') as file: 66 url = file.read() 67 #掲載物件数をスクレイピング 68 soup = BeautifulSoup(url,"lxml") 69 pages = soup.find("div", class_="paginate_set-hit") 70 #変数pagesにヒットした物件情報の数を代入 71 pages_text = str(pages) 72 #変数pagesを文字列型の変換 73 pages_split = pages_text.split('\n') 74 #リストpages_splitに、改行文字で区切った要素を代入 75 pages = pages_split[1] 76 #変数pagesには、「288669<span>件</span>」を代入 77 num_text = pages.split("<span>") 78 #リストnum_textには、<span>で区切った要素を代入 79 num = num_text[0] 80 #変数numには、ヒットした物件数の数値のみを代入 81 if len(num) == len(df): 82 #スクレイピングしたcsvデータの物件数と実際の検索結果物件数が一致しているか確認 83 print("Clear") 84 #もし、一致していた場合、clearを表示 85 else: 86 print("データが欠損") 87 #データが欠損していた場合、データが欠損と表示 88