[Python] Flux du scraping Web à l'analyse des données

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.

environnement

Ce que j'ai fait

  1. Web scraping
  2. Écriture / lecture CSV
  3. Prétraitement des données
  4. Analyse

1. Web scraping

Les packages utilisés sont les suivants.

Paquet utilisé

import datetime
import re
import time
from urllib.parse import urljoin

from bs4 import BeautifulSoup
import pandas as pd
import requests

Flux de raclage

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)

2. Écriture / lecture CSV

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')

3. Prétraitement des données

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']]

4. Analyse

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 entière

filtration

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)]

Analyse de corrélation

import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline

sns.pairplot(filtered)
plt.show()

image.png

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.

Répartition des 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()

image.png

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 ...

Statistiques

filtered.describe()

image.png

C'était tout pour tout le parcours.

Stations d'intérêt particulier sur la ligne (3 stations)

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)]

Répartition des prix de vente

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()

image.png

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.

Statistiques

grouped.describe()

image.png

La station qui vous intéresse le plus

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.

Analyse pour chaque étage

Nombre de propriétés
c = filtered[filtered['Station la plus proche'] == 'Station C']
c.groupby(by='Plan d'étage')['Plan d'étage'].count()

image.png

Prix de vente
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()

image.png

Il n'y a eu que 7 cas pour moins de 50 millions de yens ...

Propriétés à 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

image.png

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()

image.png

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.

Impressions

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.

Sites qui ont appris l'analyse des données

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.

Les références

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

[Python] Flux du scraping Web à l'analyse des données
Analyse de données pour améliorer POG 1 ~ Web scraping avec Python ~
Météorologie x Python ~ De l'acquisition de données météorologiques à l'analyse spectrale ~
Analyse de données python
Python: lecture de données JSON à partir de l'API Web
[Python] Application Web à partir de 0! Pratique (4) - Mise en forme des données-
Porté du langage R de "Sazae-san's Janken Data Analysis" vers Python
Introduction à l'analyse de données par Python P17-P26 [ch02 1.usa.gov données de bit.ly]
Analyse de données avec python 2
Comment ouvrir un navigateur Web à partir de python
Changements de Python 3.0 à Python 3.5
Changements de Python 2 à Python 3.0
Présentation de l'analyse de données python
[Python] Comment lire les données de CIFAR-10 et CIFAR-100
Modèle d'analyse de données Python
Analyse de données avec Python
Extraire des données d'une page Web avec Python
[Python] De l'analyse morphologique des données CSV à la sortie CSV et à l'affichage graphique [GiNZA]
WEB grattage avec python et essayez de créer un nuage de mots à partir des critiques
[Pour les débutants] Comment étudier le test d'analyse de données Python3
Comment récupérer des données d'image de Flickr avec Python
Note de lecture: Introduction à l'analyse de données avec Python
Envoyer des données de Python au traitement via une communication socket
[Livre technique] Introduction à l'analyse de données avec Python -1 Chapitre Introduction-
Mon conteneur d'analyse de données python
Publier de Python vers Slack
Web scraping avec python + JupyterLab
Python pour l'analyse des données Chapitre 4
Anaconda mis à jour de 4.2.0 à 4.3.0 (python3.5 mis à jour vers python3.6)
Notes d'apprentissage sur l'analyse des données Python
Flux de raclage des données de courses de chevaux
Web scraping avec Selenium (Python)
Passer de python2.7 à python3.6 (centos7)
Connectez-vous à sqlite depuis python
Python pour l'analyse des données Chapitre 2
Web scraping débutant avec python
Analyse de données à l'aide de pandas python
Python pour l'analyse des données Chapitre 3
[Mis à jour de temps en temps] Mémos Python souvent utilisés pour l'analyse des données [Division N, etc.]
[Impression] [Analyse de données à partir de zéro] Introduction à la science des données Python apprise dans des analyses de rentabilisation
[Python] Introduction au scraping | Programme d'ouverture de pages Web (sélénium webdriver)
20200329_Introduction à l'analyse de données avec Python 2nd Edition Personal Summary
Récupérer les données souhaitées du site Web en liant Python et Excel
Appuyez sur REST en Python pour obtenir des données de New Relic
Transmettez les données OpenCV de la bibliothèque C ++ d'origine à Python
Appelez Matlab depuis Python pour optimiser
De l'installation d'Elasticsearch à la saisie des données
[Python] Comment FFT des données mp3
Python: analyse des séries chronologiques: prétraitement des données des séries chronologiques
Obtenir des données de Quandl en Python
Publication de Python sur la chronologie Facebook
Web scraping avec Python Première étape
J'ai essayé webScraping avec python.
[Lambda] [Python] Publier sur Twitter depuis Lambda!
Python (de la première fois à l'exécution)
Publier une image de Python sur Tumblr