南びわ湖エリア情報

草津市・守山市・栗東市周辺の情報を発信していきます

pythonでスクレイピング(beautifulsoup 応用編)

pythonスクレイピング(beautifulsoup)について、独学を進めます。

f:id:minamibiwako:20210315175726p:plain

前回の pythonでスクレイピング(beautifulsoup 基礎編)の続きです。

PC作業環境

OS: windows 8.1

pythonインストールできた状態なら

この記事の .pyファイルとバッチファイルをコピペして、バッチファイルをダブルクリックすれば動作確認できますので、ぜひ試してみて下さい!

理解する必要はありません。

pythonを自分のPCにインストール

②.pyファイル(pythonコード)を自分のPCの作業フォルダにコピペ

③バッチファイルを自分のPCの作業フォルダにコピペ

④バッチファイルをダブルクリックで、パイソンコードが実行されて出力結果をゲット!

これだけでパイソンの概要が習得できます。①~④で分からないところがあれば、以前の記事を確認してみて下さい。それでも分からないときは以下のツイッター(独学推奨ツイート)のリプ欄で質問して下さいね。なるべく回答できるようにします。

 

pythonコードのインデント(tab)が、うまく表示できていません。

forループの下に、インデントを付けているtab情報が消えていますので注意願います !

改善できるように、はてなブログの「 \t 表示」について確認中です。  

 

改善ができるまでは、、、

pythonコードをコピペするだけでは動きません。(tabある場合)

for文など、tabのインデントを追加するだけで動きます!

 

 

目次

 

引き続き、この動画シリーズで独学を進めていきます。

不動産情報の取得 PART1 

 

ページ1~ 増やしていくときの書き方

f:id:minamibiwako:20210325152930p:plain

 

bsでパース

f:id:minamibiwako:20210326142040p:plain

 

パース(解析)結果の使い方

f:id:minamibiwako:20210326142454p:plain



pythonコード parse_html_005.py 

# coding: shift_jis
import io,sys
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')

my_url = "https://suumo.jp/chintai/shiga/sc_kusatsu/?page={}"
target_url = my_url.format(1)
print("@@@@@@@@@@_1")
print("htmlを取得するurl")
print(target_url)

import requests
my_html = requests.get(target_url)

print("@@@@@@@@@@_2")
print("htmlを取得したurl")
print(my_html.url)

print("@@@@@@@@@@_3")
#print("取得したhtml(長いので先頭の12行のみ表示)")
my_file = open("./output.txt", "w", encoding="utf-8")
print(my_html.text, file=my_file)
my_file.close()

'''
複数行にわたるコメントアウトはトリプルクォーテーションで!
「read_table」は行頭にタブがあるとエラー出る(pandas.errors.ParserError: Error tokenizing data. C error: Expected 1 fields in line 20, saw 2)
data = pd.read_table("output3.txt")
よって「read_html」を試したが、lxmlがインポートされていないとエラー出る(ImportError: lxml not found, please install it)
「read_html」はリストでheadが使えるテキスト属性じゃないよとエラー出る(AttributeError: 'list' object has no attribute 'head')
よって「read_table」を使うことに戻し、タブを空白に置換してエラーを回避(目視確認のためだけなので暫定対策)
'''

print("@@@@@@@@@@_4")
# ファイルを開く
my_file = open("./output1.txt", "w", encoding="utf-8")
with open("./output.txt", "r", encoding="utf-8") as f:
# 一行ずつ読み込む
for my_data1 in f:
# TAB を 空白へ置換(strip で white space を除去)
print(my_data1.strip().replace("\t"," "), file=my_file)
my_file.close()

print("@@@@@@@@@@_5")
import pandas as pd
my_data2 = pd.read_table("output1.txt")
print(my_data2.head(12))

print("@@@@@@@@@@_6")
print(my_data2)

print("@@@@@@@@@@_7")
print("取得したhtmlのtype判定(str型ならbeautifulsoupでのパース解析可能)")
html_type = type(my_html.text)
print(html_type)

print("@@@@@@@@@@_8")
from bs4 import BeautifulSoup
soup = BeautifulSoup(my_html.text)
print(soup.find("title").text)

print("@@@@@@@@@@_9")
print("スーモページの表示建物数20が取れているか")
contents = soup.find_all("div",class_="cassetteitem")
print(len(contents))

 

read_htmlを試すために、lxml をインポート

f:id:minamibiwako:20210326150421p:plain

 

バッチファイル(pip_list.bat

出力結果(0)

Package Version
--------------- ----------
beautifulsoup4 4.8.1
certifi 2019.11.28
chardet 3.0.4
idna 2.8
lxml 4.6.3
numpy 1.20.1
pandas 1.2.3
pip 21.0.1
python-dateutil 2.8.1
pytz 2021.1
requests 2.22.0
setuptools 41.2.0
six 1.15.0
soupsieve 1.9.5
urllib3 1.25.7

lxml がインストールされました。

 

バッチファイルpythonコードを実行) do_py011.bat

rem do_py011.bat
@echo off
set year=%date:~0,4%
set month=%date:~5,2%
set day=%date:~8,2%
set time2=%time: =0%
set hour=%time2:~0,2%
set minute=%time2:~3,2%
set second=%time2:~6,2%
set logname=%year%-%month%-%day%_%hour%_%minute%_%second%

python parse_html_005.py >> %logname%_parse_html_005.txt

rem pause

 

出力結果(1)

@@@@@@@@@@_1
htmlを取得するurl
https://suumo.jp/chintai/shiga/sc_kusatsu/?page=1
@@@@@@@@@@_2
htmlを取得したurl
https://suumo.jp/chintai/shiga/sc_kusatsu/?page=1
@@@@@@@@@@_3
@@@@@@@@@@_4
@@@@@@@@@@_5
<!DOCTYPE html>
0 <!--[if lt IE 7]><html lang="ja" class="ie"><!...
1 <!--[if IE 7]><html lang="ja" class="ie"><![en...
2 <!--[if IE 8]><html lang="ja" class="ie"><![en...
3 <!--[if gt IE 8]><!--><html lang="ja"><!--<![e...
4 <!-- FR301FC0012 START -->
5 <head>
6 <meta charset="utf-8" />
7 <!-- seo.headerTag Start -->
8 <title>【SUUMO】草津市の賃貸(賃貸マンション・アパート)住宅のお部屋探し物件情報...
9 <meta name="keywords" content='草津市,滋賀県,賃貸,賃貸マン...
10 <meta name="description" content='【SUUMO(スーモ)賃...
11 <link rel="shortcut icon" href="/front/img/fav...
@@@@@@@@@@_6
<!DOCTYPE html>
0 <!--[if lt IE 7]><html lang="ja" class="ie"><!...
1 <!--[if IE 7]><html lang="ja" class="ie"><![en...
2 <!--[if IE 8]><html lang="ja" class="ie"><![en...
3 <!--[if gt IE 8]><!--><html lang="ja"><!--<![e...
4 <!-- FR301FC0012 START -->
... ...
4942 };
4943 </script>
4944 </body>
4945 <!-- FR301FC0012 END -->
4946 </html>

[4947 rows x 1 columns]
@@@@@@@@@@_7
取得したhtmlのtype判定(str型ならbeautifulsoupでのパース解析可能)
<class 'str'>
@@@@@@@@@@_8
【SUUMO】草津市の賃貸(賃貸マンション・アパート)住宅のお部屋探し物件情報
@@@@@@@@@@_9
スーモページの表示建物数20が取れているか
20

表示建物数20のデータが取れていることが確認できました。 

 

物件・部屋情報を取得します。

物件情報(物件名、住所、アクセス、築年数) 

部屋情報(物件の階数、賃料/管理費、敷金・礼金、間取り・面積)

f:id:minamibiwako:20210326164504p:plain

f:id:minamibiwako:20210326172408p:plain

 

物件情報(物件名、住所、アクセス、築年数)

f:id:minamibiwako:20210326172552p:plain

 

部屋情報(物件の階数、賃料/管理費、敷金・礼金、間取り・面積) 

f:id:minamibiwako:20210326180609p:plain

 

【演習】部屋情報の取得 

f:id:minamibiwako:20210327184729p:plain

 

pythonコード parse_html_006.py 

# coding: shift_jis
import io,sys
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')

my_url = "https://suumo.jp/chintai/shiga/sc_kusatsu/?page={}"
target_url = my_url.format(1)
print("@@@@@@@@@@_1")
print("htmlを取得するurl")
print(target_url)

import requests
my_html = requests.get(target_url)

print("@@@@@@@@@@_2")
print("htmlを取得したurl")
print(my_html.url)

print("@@@@@@@@@@_3")
#print("取得したhtml(長いので先頭の12行のみ表示)")
my_file = open("./output.txt", "w", encoding="utf-8")
print(my_html.text, file=my_file)
my_file.close()

'''
複数行にわたるコメントアウトはトリプルクォーテーションで!
「read_table」は行頭にタブがあるとエラー出る(pandas.errors.ParserError: Error tokenizing data. C error: Expected 1 fields in line 20, saw 2)
data = pd.read_table("output3.txt")
よって「read_html」を試したが、lxmlがインポートされていないとエラー出る(ImportError: lxml not found, please install it)
「read_html」はリストでheadが使えるテキスト属性じゃないよとエラー出る(AttributeError: 'list' object has no attribute 'head')
よって「read_table」を使うことに戻し、タブを空白に置換してエラーを回避(目視確認のためだけなので暫定対策)
'''

print("@@@@@@@@@@_4")
# ファイルを開く
my_file = open("./output1.txt", "w", encoding="utf-8")
with open("./output.txt", "r", encoding="utf-8") as f:
# 一行ずつ読み込む
for my_data1 in f:
# TAB を 空白へ置換(strip で white space を除去)
print(my_data1.strip().replace("\t"," "), file=my_file)
my_file.close()

print("@@@@@@@@@@_5")
import pandas as pd
my_data2 = pd.read_table("output1.txt")
print(my_data2.head(12))

print("@@@@@@@@@@_6")
print(my_data2)

print("@@@@@@@@@@_7")
print("取得したhtmlのtype判定(str型ならbeautifulsoupでのパース解析可能)")
html_type = type(my_html.text)
print(html_type)

print("@@@@@@@@@@_8")
from bs4 import BeautifulSoup
soup = BeautifulSoup(my_html.text)
print(soup.find("title").text)

print("@@@@@@@@@@_9")
print("スーモページの表示建物数20が取れているか")
contents = soup.find_all("div", class_="cassetteitem")
print(len(contents))

print("@@@@@@@@@@_10")
print("物件情報(物件名、住所、アクセス、築年数)")
content = contents[0]
detail = content.find("div", class_="cassetteitem-detail")
title = detail.find("div", class_="cassetteitem_content-title").text
address = detail.find("li", class_="cassetteitem_detail-col1").text
access = detail.find("li", class_="cassetteitem_detail-col2").text
age = detail.find("li", class_="cassetteitem_detail-col3").text
print(title)
print(address)
print(access)
print(age)

print("@@@@@@@@@@_11")
# print(content)
table = content.find("table", class_="cassetteitem_other")
# print(table)

print("@@@@@@@@@@_12")
tr_tags = table.find_all("tr", class_="js-cassette_link")
print(len(tr_tags))

print("@@@@@@@@@@_13")
tr_tag = tr_tags[0]
# print(tr_tag)

print("@@@@@@@@@@_14")
print("部屋情報(物件の階数、賃料/管理費、敷金・礼金、間取り・面積)")
td_tags = tr_tag.find_all("td")

# td_tag = td_tags[0]
# print(td_tag)

# td_tag = td_tags[1]
# print(td_tag)

td_tag = td_tags[2]
print(td_tag.text)

td_tag = td_tags[3]
print(td_tag.text)

td_tag = td_tags[4]
print(td_tag.text)

td_tag = td_tags[5]
print(td_tag.text)

 

 

 

バッチファイルpythonコードを実行) do_py012.bat 

rem do_py012.bat
@echo off
set year=%date:~0,4%
set month=%date:~5,2%
set day=%date:~8,2%
set time2=%time: =0%
set hour=%time2:~0,2%
set minute=%time2:~3,2%
set second=%time2:~6,2%
set logname=%year%-%month%-%day%_%hour%_%minute%_%second%

python parse_html_006.py >> %logname%_parse_html_006.txt

rem pause

 

 

出力結果(2)

@@@@@@@@@@_1
htmlを取得するurl
https://suumo.jp/chintai/shiga/sc_kusatsu/?page=1
@@@@@@@@@@_2
htmlを取得したurl
https://suumo.jp/chintai/shiga/sc_kusatsu/?page=1
@@@@@@@@@@_3
@@@@@@@@@@_4
@@@@@@@@@@_5
<!DOCTYPE html>
0 <!--[if lt IE 7]><html lang="ja" class="ie"><!...
1 <!--[if IE 7]><html lang="ja" class="ie"><![en...
2 <!--[if IE 8]><html lang="ja" class="ie"><![en...
3 <!--[if gt IE 8]><!--><html lang="ja"><!--<![e...
4 <!-- FR301FC0012 START -->
5 <head>
6 <meta charset="utf-8" />
7 <!-- seo.headerTag Start -->
8 <title>【SUUMO】草津市の賃貸(賃貸マンション・アパート)住宅のお部屋探し物件情報...
9 <meta name="keywords" content='草津市,滋賀県,賃貸,賃貸マン...
10 <meta name="description" content='【SUUMO(スーモ)賃...
11 <link rel="shortcut icon" href="/front/img/fav...
@@@@@@@@@@_6
<!DOCTYPE html>
0 <!--[if lt IE 7]><html lang="ja" class="ie"><!...
1 <!--[if IE 7]><html lang="ja" class="ie"><![en...
2 <!--[if IE 8]><html lang="ja" class="ie"><![en...
3 <!--[if gt IE 8]><!--><html lang="ja"><!--<![e...
4 <!-- FR301FC0012 START -->
... ...
5563 };
5564 </script>
5565 </body>
5566 <!-- FR301FC0012 END -->
5567 </html>

[5568 rows x 1 columns]
@@@@@@@@@@_7
取得したhtmlのtype判定(str型ならbeautifulsoupでのパース解析可能)
<class 'str'>
@@@@@@@@@@_8
【SUUMO】草津市の賃貸(賃貸マンション・アパート)住宅のお部屋探し物件情報
@@@@@@@@@@_9
スーモページの表示建物数20が取れているか
20
@@@@@@@@@@_10
物件情報(物件名、住所、アクセス、築年数)
トップペアー福甚No.2
滋賀県草津市野路東4

JR東海道本線/南草津駅 歩16分
JR東海道本線/瀬田駅 歩49分
JR東海道本線/草津駅 歩47分


築27年
3階建

@@@@@@@@@@_11
@@@@@@@@@@_12
2
@@@@@@@@@@_13
@@@@@@@@@@_14
部屋情報(物件の階数、賃料/管理費、敷金・礼金、間取り・面積)


3階


6万円
5000円

 


-
5万円

 


2LDK
52.8m2

 

 演習問題である「部屋情報の取得」ができていることが確認できました。

 

 

不動産情報の取得 PART2 

 

unpack

f:id:minamibiwako:20210328100144p:plain

floor, price, first_fee, capacity

 

データの仕分け 

f:id:minamibiwako:20210328144219p:plain

floor, price, first_fee, capacity
fee, management_fee, deposit, gratuity, madori, menseki

 

データの格納 

f:id:minamibiwako:20210328165319p:plain

 


forループ 

f:id:minamibiwako:20210328181006p:plain

f:id:minamibiwako:20210328181105p:plain

f:id:minamibiwako:20210328181452p:plain

 

pythonコード parse_html_007.py  

# coding: shift_jis
import io,sys
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')

my_url = "https://suumo.jp/chintai/shiga/sc_kusatsu/?page={}"
target_url = my_url.format(1)
print("@@@@@@@@@@_1")
print("htmlを取得するurl")
print(target_url)

import requests
my_html = requests.get(target_url)

print("@@@@@@@@@@_2")
print("htmlを取得したurl")
print(my_html.url)

print("@@@@@@@@@@_3")
#print("取得したhtml(長いので先頭の12行のみ表示)")
my_file = open("./output.txt", "w", encoding="utf-8")
print(my_html.text, file=my_file)
my_file.close()

'''
複数行にわたるコメントアウトはトリプルクォーテーションで!
「read_table」は行頭にタブがあるとエラー出る(pandas.errors.ParserError: Error tokenizing data. C error: Expected 1 fields in line 20, saw 2)
data = pd.read_table("output3.txt")
よって「read_html」を試したが、lxmlがインポートされていないとエラー出る(ImportError: lxml not found, please install it)
「read_html」はリストでheadが使えるテキスト属性じゃないよとエラー出る(AttributeError: 'list' object has no attribute 'head')
よって「read_table」を使うことに戻し、タブを空白に置換してエラーを回避(目視確認のためだけなので暫定対策)
'''

print("@@@@@@@@@@_4")
# ファイルを開く
my_file = open("./output1.txt", "w", encoding="utf-8")
with open("./output.txt", "r", encoding="utf-8") as f:
# 一行ずつ読み込む
for my_data1 in f:
# TAB を 空白へ置換(strip で white space を除去)
print(my_data1.strip().replace("\t"," "), file=my_file)
my_file.close()

print("@@@@@@@@@@_5")
import pandas as pd
my_data2 = pd.read_table("output1.txt")
print(my_data2.head(12))

print("@@@@@@@@@@_6")
print(my_data2)

print("@@@@@@@@@@_7")
print("取得したhtmlのtype判定(str型ならbeautifulsoupでのパース解析可能)")
html_type = type(my_html.text)
print(html_type)

print("@@@@@@@@@@_8")
from bs4 import BeautifulSoup
soup = BeautifulSoup(my_html.text)
print(soup.find("title").text)

print("@@@@@@@@@@_9")
print("スーモページの表示建物数20が取れているか")
contents = soup.find_all("div", class_="cassetteitem")
print(len(contents))

print("@@@@@@@@@@_10")
print("物件情報(物件名、住所、アクセス、築年数)")
content = contents[0]
detail = content.find("div", class_="cassetteitem-detail")
title = detail.find("div", class_="cassetteitem_content-title").text
address = detail.find("li", class_="cassetteitem_detail-col1").text
access = detail.find("li", class_="cassetteitem_detail-col2").text
age = detail.find("li", class_="cassetteitem_detail-col3").text
print(title)
print(address)
print(access)
print(age)

print("@@@@@@@@@@_11")
# print(content)
table = content.find("table", class_="cassetteitem_other")
# print(table)

print("@@@@@@@@@@_12")
tr_tags = table.find_all("tr", class_="js-cassette_link")
print(len(tr_tags))

print("@@@@@@@@@@_13")
tr_tag = tr_tags[0]
# print(tr_tag)

print("@@@@@@@@@@_14")
print("部屋情報(物件の階数、賃料/管理費、敷金・礼金、間取り・面積)")
td_tags = tr_tag.find_all("td")

# td_tag = td_tags[0]
# print(td_tag)

# td_tag = td_tags[1]
# print(td_tag)

td_tag = td_tags[2]
print(td_tag.text)

td_tag = td_tags[3]
print(td_tag.text)

td_tag = td_tags[4]
print(td_tag.text)

td_tag = td_tags[5]
print(td_tag.text)

print("@@@@@@@@@@_14")
print("データの仕分け")
floor, price, first_fee, capacity = tr_tag.find_all("td")[2:6]

fee, management_fee = price.find_all("li")
deposit, gratuity = first_fee.find_all("li")
madori, menseki = capacity.find_all("li")
print(floor.text)
print(fee.text)
print(management_fee.text)
print(deposit.text)
print(gratuity.text)
print(madori.text)
print(menseki.text)

print("@@@@@@@@@@_15")
print("データの格納")
d = {
"title": title,
"address": address,
"access": access,
"age": age,
"floor": floor.text,
"fee": fee.text,
"management_fee": management_fee.text,
"deposit": deposit.text,
"gratuity": gratuity.text,
"madori": madori.text,
"menseki": menseki.text
}
print(d)

print("@@@@@@@@@@_16")
print("小さく情報取得がokだったので、forループ")
# from pprint import pprint
d_list =
contents = soup.find_all("div", class_="cassetteitem")
# content = contents[0]
for content in contents:
detail = content.find("div", class_="cassetteitem-detail")
title = detail.find("div", class_="cassetteitem_content-title").text
address = detail.find("li", class_="cassetteitem_detail-col1").text
access = detail.find("li", class_="cassetteitem_detail-col2").text
age = detail.find("li", class_="cassetteitem_detail-col3").text

table = content.find("table", class_="cassetteitem_other")
tr_tags = table.find_all("tr", class_="js-cassette_link")

# tr_tag = tr_tags[0]
for tr_tag in tr_tags:
floor, price, first_fee, capacity = tr_tag.find_all("td")[2:6]
fee, management_fee = price.find_all("li")
deposit, gratuity = first_fee.find_all("li")
madori, menseki = capacity.find_all("li")
d = {
"title": title,
"address": address,
"access": access,
"age": age,
"floor": floor.text,
"fee": fee.text,
"management_fee": management_fee.text,
"deposit": deposit.text,
"gratuity": gratuity.text,
"madori": madori.text,
"menseki": menseki.text
}
# リストd_listの末尾に要素(取得した辞書d)を追加格納する
d_list.append(d)
# pprint(d, depth=2, width=70)
print(d)

 

 

バッチファイル(pythonコードを実行) do_py013.bat 

rem do_py013.bat
@echo off
set year=%date:~0,4%
set month=%date:~5,2%
set day=%date:~8,2%
set time2=%time: =0%
set hour=%time2:~0,2%
set minute=%time2:~3,2%
set second=%time2:~6,2%
set logname=%year%-%month%-%day%_%hour%_%minute%_%second%

python parse_html_007.py >> %logname%_parse_html_007.txt

rem pause

 

 

出力結果(3)

@@@@@@@@@@_1
htmlを取得するurl
https://suumo.jp/chintai/shiga/sc_kusatsu/?page=1
@@@@@@@@@@_2
htmlを取得したurl
https://suumo.jp/chintai/shiga/sc_kusatsu/?page=1
@@@@@@@@@@_3
@@@@@@@@@@_4
@@@@@@@@@@_5
<!DOCTYPE html>
0 <!--[if lt IE 7]><html lang="ja" class="ie"><!...
1 <!--[if IE 7]><html lang="ja" class="ie"><![en...
2 <!--[if IE 8]><html lang="ja" class="ie"><![en...
3 <!--[if gt IE 8]><!--><html lang="ja"><!--<![e...
4 <!-- FR301FC0012 START -->
5 <head>
6 <meta charset="utf-8" />
7 <!-- seo.headerTag Start -->
8 <title>【SUUMO】草津市の賃貸(賃貸マンション・アパート)住宅のお部屋探し物件情報...
9 <meta name="keywords" content='草津市,滋賀県,賃貸,賃貸マン...
10 <meta name="description" content='【SUUMO(スーモ)賃...
11 <link rel="shortcut icon" href="/front/img/fav...
@@@@@@@@@@_6
<!DOCTYPE html>
0 <!--[if lt IE 7]><html lang="ja" class="ie"><!...
1 <!--[if IE 7]><html lang="ja" class="ie"><![en...
2 <!--[if IE 8]><html lang="ja" class="ie"><![en...
3 <!--[if gt IE 8]><!--><html lang="ja"><!--<![e...
4 <!-- FR301FC0012 START -->
... ...
4883 };
4884 </script>
4885 </body>
4886 <!-- FR301FC0012 END -->
4887 </html>

[4888 rows x 1 columns]
@@@@@@@@@@_7
取得したhtmlのtype判定(str型ならbeautifulsoupでのパース解析可能)
<class 'str'>
@@@@@@@@@@_8
【SUUMO】草津市の賃貸(賃貸マンション・アパート)住宅のお部屋探し物件情報
@@@@@@@@@@_9
スーモページの表示建物数20が取れているか
20
@@@@@@@@@@_10
物件情報(物件名、住所、アクセス、築年数)
ユニヴァリィ グランヴィア8
滋賀県草津市草津町

JR東海道本線/草津駅 歩19分
JR東海道本線/南草津駅 歩25分
JR東海道本線/栗東駅 歩54分


築1年
3階建

@@@@@@@@@@_11
@@@@@@@@@@_12
1
@@@@@@@@@@_13
@@@@@@@@@@_14
部屋情報(物件の階数、賃料/管理費、敷金・礼金、間取り・面積)


3階


8.1万円
5000円

 


8.1万円
8.1万円

 


2LDK
51m2


@@@@@@@@@@_14
データの仕分け


3階
8.1万円
5000円
8.1万円
8.1万円
2LDK
51m2
@@@@@@@@@@_15
データの格納
{'title': 'ユニヴァリィ\u3000グランヴィア8', 'address': '滋賀県草津市草津町', 'access': '\nJR東海道本線/草津駅 歩19分\nJR東海道本線/南草津駅 歩25分\nJR東海道本線/栗東駅 歩54分\n', 'age': '\n築1年\n3階建\n', 'floor': '\r\n\t\t\t\t\t\t\t\t\t\t\t3階', 'fee': '8.1万円', 'management_fee': '5000円', 'deposit': '8.1万円', 'gratuity': '8.1万円', 'madori': '2LDK', 'menseki': '51m2'}
@@@@@@@@@@_16
小さく情報取得がokだったので、forループ
{'title': 'ユニヴァリィ\u3000グランヴィア8', 'address': '滋賀県草津市草津町', 'access': '\nJR東海道本線/草津駅 歩19分\nJR東海道本線/南草津駅 歩25分\nJR東海道本線/栗東駅 歩54分\n', 'age': '\n築1年\n3階建\n', 'floor': '\r\n\t\t\t\t\t\t\t\t\t\t\t3階', 'fee': '8.1万円', 'management_fee': '5000円', 'deposit': '8.1万円', 'gratuity': '8.1万円', 'madori': '2LDK', 'menseki': '51m2'}
{'title': 'メゾン・アイリス', 'address': '滋賀県草津市追分3', 'access': '\nJR東海道本線/南草津駅 歩22分\nJR東海道本線/草津駅 歩23分\nJR東海道本線/栗東駅 歩47分\n', 'age': '\n築11年\n2階建\n', 'floor': '\r\n\t\t\t\t\t\t\t\t\t\t\t1階', 'fee': '6.9万円', 'management_fee': '3000円', 'deposit': '6.9万円', 'gratuity': '-', 'madori': '2LDK', 'menseki': '57.85m2'}

 以下、省略 

 

f:id:minamibiwako:20210329162518p:plain

ここまでの内容で、

javascriptが使われていないwebページであれば、自由自在に情報抽出できます! 

 

 

不動産情報の取得 複数ページから

 

sleep 

f:id:minamibiwako:20210330083656p:plain

 

forループ(1~3ページまで)

f:id:minamibiwako:20210330081942p:plain

 

pythonコード parse_html_008.py  

# coding: shift_jis
import io,sys
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')

from time import sleep
from bs4 import BeautifulSoup
import requests
import pandas as pd
import sys


my_url = "https://suumo.jp/chintai/shiga/sc_kusatsu/?page={}"
d_list =
sys.stderr.write("requests.get ")

for i in range(1,4):
# target_url = my_url.format(1)
target_url = my_url.format(i)

# print("@@@@@@@@@@_1")
# print("htmlを取得するurl")
# print(target_url)
my_html = requests.get(target_url)
sys.stderr.write(".")
sleep(1)
sys.stderr.write(".")
sleep(1)
sys.stderr.write(".")
sleep(1)


# print("@@@@@@@@@@_2")
# print("htmlを取得したurl")
# print(my_html.url)

# print("@@@@@@@@@@_3")
# print("取得したhtml(長いので先頭の12行のみ表示)")
my_file = open("./output.txt", "w", encoding="utf-8")
print(my_html.text, file=my_file)
my_file.close()

'''
複数行にわたるコメントアウトはトリプルクォーテーションで!
「read_table」は行頭にタブがあるとエラー出る(pandas.errors.ParserError: Error tokenizing data. C error: Expected 1 fields in line 20, saw 2)
data = pd.read_table("output3.txt")
よって「read_html」を試したが、lxmlがインポートされていないとエラー出る(ImportError: lxml not found, please install it)
「read_html」はリストでheadが使えるテキスト属性じゃないよとエラー出る(AttributeError: 'list' object has no attribute 'head')
よって「read_table」を使うことに戻し、タブを空白に置換してエラーを回避(目視確認のためだけなので暫定対策)
'''

# print("@@@@@@@@@@_4")
# ファイルを開く
my_file = open("./output1.txt", "w", encoding="utf-8")
with open("./output.txt", "r", encoding="utf-8") as f:
# 一行ずつ読み込む
for my_data1 in f:
# TAB を 空白へ置換(strip で white space を除去)
print(my_data1.strip().replace("\t"," "), file=my_file)
my_file.close()

print("@@@@@@@@@@_5")
my_data2 = pd.read_table("output1.txt")
print(my_data2.head(12))

print("@@@@@@@@@@_6")
print(my_data2)

# print("@@@@@@@@@@_7")
# print("取得したhtmlのtype判定(str型ならbeautifulsoupでのパース解析可能)")
# html_type = type(my_html.text)
# print(html_type)

print("@@@@@@@@@@_8")
soup = BeautifulSoup(my_html.text)
print(soup.find("title").text)

print("@@@@@@@@@@_9")
# print("スーモページの表示建物数20が取れているか")
contents = soup.find_all("div", class_="cassetteitem")
print(len(contents))

# print("@@@@@@@@@@_10")
'''
print("物件情報(物件名、住所、アクセス、築年数)")
content = contents[0]
detail = content.find("div", class_="cassetteitem-detail")
title = detail.find("div", class_="cassetteitem_content-title").text
address = detail.find("li", class_="cassetteitem_detail-col1").text
access = detail.find("li", class_="cassetteitem_detail-col2").text
age = detail.find("li", class_="cassetteitem_detail-col3").text
print(title)
print(address)
print(access)
print(age)
'''

# print("@@@@@@@@@@_11")
# print(content)
'''
table = content.find("table", class_="cassetteitem_other")
'''
# print(table)

# print("@@@@@@@@@@_12")
'''
tr_tags = table.find_all("tr", class_="js-cassette_link")
print(len(tr_tags))
'''

# print("@@@@@@@@@@_13")
'''
tr_tag = tr_tags[0]
'''
# print(tr_tag)

# print("@@@@@@@@@@_14")
'''
print("部屋情報(物件の階数、賃料/管理費、敷金・礼金、間取り・面積)")
td_tags = tr_tag.find_all("td")
'''
# td_tag = td_tags[0]
# print(td_tag)

# td_tag = td_tags[1]
# print(td_tag)
'''
td_tag = td_tags[2]
print(td_tag.text)

td_tag = td_tags[3]
print(td_tag.text)

td_tag = td_tags[4]
print(td_tag.text)

td_tag = td_tags[5]
print(td_tag.text)
'''

# print("@@@@@@@@@@_14")
'''
print("データの仕分け")
floor, price, first_fee, capacity = tr_tag.find_all("td")[2:6]

fee, management_fee = price.find_all("li")
deposit, gratuity = first_fee.find_all("li")
madori, menseki = capacity.find_all("li")
print(floor.text)
print(fee.text)
print(management_fee.text)
print(deposit.text)
print(gratuity.text)
print(madori.text)
print(menseki.text)
'''

# print("@@@@@@@@@@_15")
'''
print("データの格納")
d = {
"title": title,
"address": address,
"access": access,
"age": age,
"floor": floor.text,
"fee": fee.text,
"management_fee": management_fee.text,
"deposit": deposit.text,
"gratuity": gratuity.text,
"madori": madori.text,
"menseki": menseki.text
}
print(d)
'''

print("@@@@@@@@@@_16")
# print("小さく情報取得がokだったので、forループ")
# from pprint import pprint
# d_list = []
contents = soup.find_all("div", class_="cassetteitem")
# content = contents[0]
for content in contents:
detail = content.find("div", class_="cassetteitem-detail")
title = detail.find("div", class_="cassetteitem_content-title").text
address = detail.find("li", class_="cassetteitem_detail-col1").text
access = detail.find("li", class_="cassetteitem_detail-col2").text
age = detail.find("li", class_="cassetteitem_detail-col3").text

table = content.find("table", class_="cassetteitem_other")
tr_tags = table.find_all("tr", class_="js-cassette_link")

# tr_tag = tr_tags[0]
for tr_tag in tr_tags:
floor, price, first_fee, capacity = tr_tag.find_all("td")[2:6]
fee, management_fee = price.find_all("li")
deposit, gratuity = first_fee.find_all("li")
madori, menseki = capacity.find_all("li")
d = {
"title": title,
"address": address,
"access": access,
"age": age,
"floor": floor.text,
"fee": fee.text,
"management_fee": management_fee.text,
"deposit": deposit.text,
"gratuity": gratuity.text,
"madori": madori.text,
"menseki": menseki.text
}
# リストd_listの末尾に要素(取得した辞書d)を追加格納する
d_list.append(d)
# pprint(d, depth=2, width=70)
print(d)

forループのインデント情報が消えてしまっています!申し訳ありません。

(はてなブログにpyソースを貼り付けると \t 情報が消えてしまう現象、なぜ?)

forループ内にインデント(字下げ)を追加しないとコピペだけでは動きません!

対策方法が分かり次第、修正します。

内容について

標準出力(print)は、バッチファイルでリダイレクトしてテキストファイルに落としています。エラー出力として、データ取得の進捗状況が把握したいと思いstderrで試してみましたが、全処理が終わったあとでの表示になってしまい、リアルタイムでの進捗状況確認はできませんでした。できなかった記録として、ソースを残しておきます!
 

 

バッチファイル(pythonコードを実行) do_py014.bat  

rem do_py014.bat
@echo off
set year=%date:~0,4%
set month=%date:~5,2%
set day=%date:~8,2%
set time2=%time: =0%
set hour=%time2:~0,2%
set minute=%time2:~3,2%
set second=%time2:~6,2%
set logname=%year%-%month%-%day%_%hour%_%minute%_%second%

python parse_html_008.py >> %logname%_parse_html_008.txt

rem pause

 

 

出力結果(4)

@@@@@@@@@@_5
<!DOCTYPE html>
0 <!--[if lt IE 7]><html lang="ja" class="ie"><!...
1 <!--[if IE 7]><html lang="ja" class="ie"><![en...
2 <!--[if IE 8]><html lang="ja" class="ie"><![en...
3 <!--[if gt IE 8]><!--><html lang="ja"><!--<![e...
4 <!-- FR301FC0012 START -->
5 <head>
6 <meta charset="utf-8" />
7 <!-- seo.headerTag Start -->
8 <title>【SUUMO】草津市の賃貸(賃貸マンション・アパート)住宅のお部屋探し物件情報...
9 <meta name="keywords" content='草津市,滋賀県,賃貸,賃貸マン...
10 <meta name="description" content='【SUUMO(スーモ)賃...
11 <link rel="shortcut icon" href="/front/img/fav...
@@@@@@@@@@_6
<!DOCTYPE html>
0 <!--[if lt IE 7]><html lang="ja" class="ie"><!...
1 <!--[if IE 7]><html lang="ja" class="ie"><![en...
2 <!--[if IE 8]><html lang="ja" class="ie"><![en...
3 <!--[if gt IE 8]><!--><html lang="ja"><!--<![e...
4 <!-- FR301FC0012 START -->
... ...
4496 };
4497 </script>
4498 </body>
4499 <!-- FR301FC0012 END -->
4500 </html>

[4501 rows x 1 columns]
@@@@@@@@@@_8
【SUUMO】草津市の賃貸(賃貸マンション・アパート)住宅のお部屋探し物件情報
@@@@@@@@@@_9
20
@@@@@@@@@@_16
{'title': 'ヴィラコーポ清水', 'address': '滋賀県草津市南笠東1', 'access': '\nJR東海道本線/南草津駅 歩16分\nJR東海道本線/瀬田駅 歩35分\nJR東海道本線/草津駅 歩64分\n', 'age': '\n築34年\n4階建\n', 'floor': '\r\n\t\t\t\t\t\t\t\t\t\t\t2階', 'fee': '6万円', 'management_fee': '3000円', 'deposit': '12万円', 'gratuity': '-', 'madori': '3LDK', 'menseki': '63m2'}

以下省略

 

@@@@@@@@@@_5
<!DOCTYPE html>
0 <!--[if lt IE 7]><html lang="ja" class="ie"><!...
1 <!--[if IE 7]><html lang="ja" class="ie"><![en...
2 <!--[if IE 8]><html lang="ja" class="ie"><![en...
3 <!--[if gt IE 8]><!--><html lang="ja"><!--<![e...
4 <!-- FR301FC0012 START -->
5 <head>
6 <meta charset="utf-8" />
7 <!-- seo.headerTag Start -->
8 <title>【SUUMO】草津市の賃貸(賃貸マンション・アパート)住宅のお部屋探し物件情報...
9 <meta name="keywords" content='草津市,滋賀県,賃貸,賃貸マン...
10 <meta name="description" content='【SUUMO(スーモ)賃...
11 <link rel="shortcut icon" href="/front/img/fav...
@@@@@@@@@@_6
<!DOCTYPE html>
0 <!--[if lt IE 7]><html lang="ja" class="ie"><!...
1 <!--[if IE 7]><html lang="ja" class="ie"><![en...
2 <!--[if IE 8]><html lang="ja" class="ie"><![en...
3 <!--[if gt IE 8]><!--><html lang="ja"><!--<![e...
4 <!-- FR301FC0012 START -->
... ...
5010 };
5011 </script>
5012 </body>
5013 <!-- FR301FC0012 END -->
5014 </html>

[5015 rows x 1 columns]
@@@@@@@@@@_8
【SUUMO】草津市の賃貸(賃貸マンション・アパート)住宅のお部屋探し物件情報(2ページ)
@@@@@@@@@@_9
20
@@@@@@@@@@_16
{'title': 'JR東海道本線 南草津駅 4階建 築13年', 'address': '滋賀県草津市南草津1', 'access': '\nJR東海道本線/南草津駅 歩4分\nJR東海道本線/草津駅 歩54分\nJR東海道本線/瀬田駅 歩39分\n', 'age': '\n築13年\n4階建\n', 'floor': '\r\n\t\t\t\t\t\t\t\t\t\t\t2階', 'fee': '6.9万円', 'management_fee': '2500円', 'deposit': '-', 'gratuity': '6.9万円', 'madori': '1K', 'menseki': '30.96m2'}

以下省略


@@@@@@@@@@_5
<!DOCTYPE html>
0 <!--[if lt IE 7]><html lang="ja" class="ie"><!...
1 <!--[if IE 7]><html lang="ja" class="ie"><![en...
2 <!--[if IE 8]><html lang="ja" class="ie"><![en...
3 <!--[if gt IE 8]><!--><html lang="ja"><!--<![e...
4 <!-- FR301FC0012 START -->
5 <head>
6 <meta charset="utf-8" />
7 <!-- seo.headerTag Start -->
8 <title>【SUUMO】草津市の賃貸(賃貸マンション・アパート)住宅のお部屋探し物件情報...
9 <meta name="keywords" content='草津市,滋賀県,賃貸,賃貸マン...
10 <meta name="description" content='【SUUMO(スーモ)賃...
11 <link rel="shortcut icon" href="/front/img/fav...
@@@@@@@@@@_6
<!DOCTYPE html>
0 <!--[if lt IE 7]><html lang="ja" class="ie"><!...
1 <!--[if IE 7]><html lang="ja" class="ie"><![en...
2 <!--[if IE 8]><html lang="ja" class="ie"><![en...
3 <!--[if gt IE 8]><!--><html lang="ja"><!--<![e...
4 <!-- FR301FC0012 START -->
... ...
4491 };
4492 </script>
4493 </body>
4494 <!-- FR301FC0012 END -->
4495 </html>

[4496 rows x 1 columns]
@@@@@@@@@@_8
【SUUMO】草津市の賃貸(賃貸マンション・アパート)住宅のお部屋探し物件情報(3ページ)
@@@@@@@@@@_9
20
@@@@@@@@@@_16
{'title': 'JR東海道本線 南草津駅 6階建 築30年', 'address': '滋賀県草津市南笠東2', 'access': '\nJR東海道本線/南草津駅 歩20分\nJR東海道本線/瀬田駅 歩26分\nJR東海道本線/草津駅 歩59分\n', 'age': '\n築30年\n6階建\n', 'floor': '\r\n\t\t\t\t\t\t\t\t\t\t\t2階', 'fee': '5.5万円', 'management_fee': '5000円', 'deposit': '-', 'gratuity': '-', 'madori': '2LDK', 'menseki': '53.9m2'}
以下省略

3ページ分のデータが取得できたことが確認できました。 

 

 

 

スクレイピング結果をCSVに保存

 

 

この動画までで、pythonのスクレイピングの一連の流れが習得 

f:id:minamibiwako:20210505143313p:plain


 

 

 

 

f:id:minamibiwako:20210305000634p:plain

 

 

 

 

 

 

 

 

記述中

pythonでスクレイピング(beautifulsoup 基礎編) からお読み下さい) 

 

 

 

滋賀を盛り上げていく旅は続く

 

 

 

 

■■■■■■■■■■■■■■■■■■■■■■■■■■■■

■■■■■■■■■■■■■■■■■■■■■■■■■■■■

以下、ネット上の反応