Bonjour, c'est @ 0yan. Aujourd'hui, j'ai essayé l'analyse de données de scraping Web comme pratique pratique d'analyse de données. Je veux acheter un condominium d'occasion un jour, alors j'ai choisi les informations sur les condominiums d'occasion sur l'itinéraire qui m'intéressait.
Les packages utilisés sont les suivants.
import datetime
import re
import time
from urllib.parse import urljoin
from bs4 import BeautifulSoup
import pandas as pd
import requests
La page que j'ai grattée est
C'était une configuration. Finalement,
[{'Nom de la propriété': spam, 'Prix de vente': spam, 'emplacement': spam, 'Le long de la ligne / de la gare': spam,
'Zone occupée': spam, 'Plan d'étage': spam, 'balcon': spam, 'Date de construction': spam},
{'Nom de la propriété': spam, 'Prix de vente': spam, 'emplacement': spam, 'Le long de la ligne / de la gare': spam,
'Zone occupée': spam, 'Plan d'étage': spam, 'balcon': spam, 'Date de construction': spam},
・ ・ ・,
{'Nom de la propriété': spam, 'Prix de vente': spam, 'emplacement': spam, 'Le long de la ligne / de la gare': spam,
'Zone occupée': spam, 'Plan d'étage': spam, 'balcon': spam, 'Date de construction': spam}]
Je veux créer une liste d'éléments avec des informations de propriété de type dictionnaire et la transmettre à pandas.DataFrame, donc je l'ai grattée avec la procédure suivante (voir les commentaires).
#Initialisation des variables (type dictionnaire) pour stocker les informations de propriété et des variables (liste) pour les stocker
property_dict = {}
properties_list = []
# 「property_Liste des clés nécessaires pour générer "dict" "clé"_générer une "liste"
key_list = ['Nom de la propriété', 'Prix de vente', 'emplacement', 'Le long de la ligne / de la gare', 'Zone occupée', 'Plan d'étage', 'balcon', 'Date de construction']
key_list *= 30 #30 propriétés/page
#Belle instanciation de soupe à la page 1
first_page_url = 'Certains sites immobiliers ont utilisé le résultat de la recherche d'informations sur l'appartement (1ère page) URL'
res = requests.get(first_page_url)
soup = BeautifulSoup(res.text, 'html.parser')
#Répéter pour 93 pages (comme ce n'est qu'une seule fois, l'acquisition du nombre maximum de pages est omise)
for page in range(93):
#Liste des balises dd contenant les données de propriété "dd"_générer une "liste"
dd_list = [re.sub('[\n\r\t\xa0]', '', x.get_text()) for x in soup.select('dd')] #Excluez les sauts de ligne inutiles, etc.
dd_list = dd_list[8:] #Exclure les données TOP de page inutiles
#Les données de propriété de type dictionnaire sont une liste d'éléments "propriétés"_générer une "liste"
zipped = zip(key_list, dd_list)
for i, z in enumerate(zipped, start=1):
if i % 8 == 0:
properties_list.append(property_dict)
property_dict = {}
else:
property_dict.update({z[0]: z[1]})
#Obtenez l'URL de la page suivante (après la partie de base)
next_page = soup.select('p.pagination-parts>a')[-1]
#Créez une instance de Beautiful Soup sur la page suivante
base_url = 'https://xxx.co.jp/' #URL d'un certain site immobilier
dynamic_url = urljoin(base_url, next_page.get("href"))
time.sleep(3)
res = requests.get(dynamic_url)
soup = BeautifulSoup(res.text, 'html.parser')
Enfin, j'ai passé la liste de propriétés properties_list
à pandas.DataFrame
et j'ai généré un DataFrame.
df = pd.DataFrame(properties_list)
Il est difficile de gratter à chaque fois et cela met une charge du côté du site, j'ai donc décidé de l'écrire une fois en CSV, puis de le lire et de l'utiliser.
csv_file = f'{datetime.date.today()}_Informations sur l'achat d'appartements d'occasion.csv'
df.to_csv(csv_file, encoding='cp932', index=False)
df = pd.read_csv(csv_file, encoding='cp932')
J'entends souvent l'expression "l'analyse des données prend 80% du temps à prétraiter", mais j'ai réalisé que "c'est ...". Le prétraitement suivant a été effectué.
import re
#Exclure les enregistrements sans montant dans le prix de vente
df = df[df['Prix de vente'].str.match('[0-9]*[Dix mille]Cercle') | df['Prix de vente'].str.match('[0-9]MilliardCercle') | df['Prix de vente'].str.match('[0-9]*Milliard[0-9]*Dix milleCercle')]
#Prix de vente[Dix mille yens]Ajouter
price = df['Prix de vente'].apply(lambda x: x.replace('* Y compris les droits', ''))
price = price.apply(lambda x: re.sub('([0-9]*)Milliard([0-9]*)Dix mille yens', r'\1\2', x)) # 1憶2000Dix mille yens → 12000
price = price.apply(lambda x: re.sub('([0-9]*)100 millions de yens', r'\10000', x)) # 1100 millions de yens → 10000
price = price.apply(lambda x: re.sub('([0-9]*)Dix mille yens', r'\1', x)) # 9000Dix mille yens → 9000
price = price.apply(lambda x: x.replace('@00', '0')) #Ne peut pas être considéré → Convertir en 0
price = price.apply(lambda x: x.replace('21900~31800', '0')) #Comme ci-dessus
df['Prix de vente[Dix mille yens]'] = price.astype('int')
df = df[df['Prix de vente[Dix mille yens]'] > 0] #0 exclusion d'enregistrement
#Zone occupée[m2]Ajouter
df['Zone occupée[m2]'] = df['Zone occupée'].apply(lambda x: re.sub('(.*)m2.*', r'\1', x))
df['Zone occupée[m2]'] = df['Zone occupée[m2]'].apply(lambda x: re.sub('-', '0', x)).astype('float') #Ne peut pas être considéré → Convertir en 0
df = df[df['Zone occupée[m2]'] > 0] #0 exclusion d'enregistrement
#balcon[m2]Ajouter
df['balcon[m2]'] = df['balcon'].apply(lambda x: re.sub('(.*)m2.*', r'\1', x))
df['balcon[m2]'] = df['balcon[m2]'].apply(lambda x: re.sub('-', '0', x)).astype('float') #Ne peut pas être considéré → Convertir en 0
df = df[df['balcon[m2]'] > 0] #0 exclusion d'enregistrement
#Ajouter un itinéraire
df['Route'] = df['Le long de la ligne / de la gare'].apply(lambda x: re.sub('(.*ligne).*', r'\1', x, count=5))
#Ajouter la station la plus proche
df['Station la plus proche'] = df['Le long de la ligne / de la gare'].apply(lambda x: re.sub('.*「(.*)」.*', r'\1', x, count=5))
#À pied[Minutes]Ajouter
df['À pied[Minutes]'] = df['Le long de la ligne / de la gare'].apply(lambda x: re.sub('.*Ayumu([0-9]*)Minutes.*', r'\1', x)).astype('int')
#Ajouter une préfecture
df['Préfectures'] = df['emplacement'].apply(lambda x: re.sub('(.*?[Préfectures]).*', r'\1', x))
#Ville ajoutée
df['Municipalité'] = df['emplacement'].apply(lambda x: re.sub('.*[Préfectures](.*?[Municipalité]).*',r'\1',x))
#Écraser le df de la colonne requise
df = df[['Nom de la propriété', 'Prix de vente[Dix mille yens]', 'Route', 'Station la plus proche', 'À pied[Minutes]',
'Plan d'étage', 'Zone occupée[m2]', 'balcon[m2]',
'Préfectures', 'Municipalité', 'emplacement']]
J'ai analysé toute la ligne dans laquelle je souhaite vivre et le 2LDK ou plus des stations (3 stations) qui m'intéressent particulièrement.
route = ['Ligne A', 'Ligne B', 'Ligne C', 'Ligne D', 'Ligne E', 'Ligne F']
floor_plan = ['2LDK', '2LDK+S (Nado)',
'3DK', '3DK+S (Nado)', '3LDK', '3LDK+S (Nado)', '3LDK+2S (Nado)',
'4DK', '4DK+S (Nado)', '4LDK', '4LDK+S (Nado)']
filtered = df[df['Route'].isin(route) & df['Plan d'étage'].isin(floor_plan)]
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
sns.pairplot(filtered)
plt.show()
Il semble y avoir une légère corrélation entre le prix de vente et la surface occupée, mais à part cela, cela ne semble pas trop affecter le prix de vente.
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
sns.boxplot(x='Prix de vente[Dix mille yens]', data=filtered)
plt.show()
Parmi les propriétés sur l'ensemble de l'itinéraire, 50% ont été réglées à environ 40 à 75 millions de yens. Après tout, c'est cher à Tokyo ...
filtered.describe()
C'était tout pour tout le parcours.
De là, j'ai vérifié les stations (3 stations) qui m'intéressaient.
station = ['Une station', 'Station B', 'Station C']
grouped = filtered[filtered['Station la plus proche'].isin(station)]
Nous avons étudié la répartition des prix de vente dans les trois stations.
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
sns.violinplot(x='Prix de vente[Dix mille yens]', y='Station la plus proche', data=grouped)
plt.show()
Celui qui m'intéresse le plus est le bas (vert), mais il a une distribution bimodale. Peut-être est-il polarisé entre Tawaman et les autres.
grouped.describe()
Je me suis demandé s'il y avait une propriété qui coûtait moins de 50 millions de yens à la gare qui m'intéressait le plus, alors je l'ai analysée plus en détail.
c = filtered[filtered['Station la plus proche'] == 'Station C']
c.groupby(by='Plan d'étage')['Plan d'étage'].count()
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
sns.swarmplot(x='Prix de vente[Dix mille yens]', y='Plan d'étage', data=c)
plt.show()
Il n'y a eu que 7 cas pour moins de 50 millions de yens ...
J'ai étudié les propriétés pour moins de 50 millions de yens.
c_u5k = c[c['Prix de vente[Dix mille yens]'] < 5000]
c_u5k = c_u5k[['Nom de la propriété', 'Plan d'étage', 'Zone occupée[m2]', 'balcon[m2]',
'Prix de vente[Dix mille yens]', 'emplacement', 'À pied[Minutes]']].sort_values(['Nom de la propriété', 'Plan d'étage'])
c_u5k
Comme il n'y a que 7 cas, lorsque j'ai recherché l'emplacement sur Google Maps, je me suis intéressé à 1471. 3LDK, 69,5㎡ est 42,8 millions de yens, ce qui semble être bon marché près de cette station, mais est-ce vraiment bon marché par rapport au prix du marché de 3LDK de 3 stations qui vous intéressent en premier lieu? Je l'ai cherché.
grouped[grouped['Plan d'étage'] == '3LDK'].describe()
résultat,
C'était assez bon marché. Quand j'ai cherché pourquoi, on a découvert que la propriété avait été construite en 1985 et qu'elle était assez ancienne. Puisqu'il n'y a pas de photo intérieure et qu'il est dit "Vous pouvez remodeler!", On peut en déduire qu'il vieillit considérablement.
Cependant, même si la rénovation coûte 10 millions de yens, elle reste bon marché. J'aurais aimé avoir l'argent ... ces jours-ci.
C'était la première fois que je faisais du web scraping, mais c'était une pratique très utile car elle sera probablement nécessaire à l'avenir. On dit que «ce que vous aimez est bon dans les choses», mais ce fut un jour où j'ai ressenti à nouveau que faire ce que je voulais faire, comme analyser ce qui m'intéressait, était le moyen le plus rapide de m'améliorer.
J'étudierai sur le site de Kame @ US Data Scientist "Introduction à Python pour la science des données". J'ai fait. Les points importants sont résumés de manière simple à comprendre. Je le recommande.
J'ai appris des articles suivants en faisant du web scraping.
L'article de @ tomson784 Grattage lors de la répétition des transitions de page en Python
Article de @ Chanmoro Belle soupe en 10 minutes
Merci beaucoup!
Recommended Posts