Python&R爬取分析赶集网北京二手房数据(附详细代码)

640?wx_fmt=gif


作者介绍:徐涛,19年应届毕业生,专注于珊瑚礁研究,喜欢用R各种清洗数据。

知乎:parkson


前言:

原文发布在知乎,已得到作者授权,在此向徐涛同学表示感谢。本文主要分为两部分:Python爬取赶集网北京二手房数据&R对爬取的二手房房价做线性回归分析。文章思路清晰,代码详细,特别适合刚刚接触Python&R的同学学习参考。

Part1:Python爬取赶集网北京二手房数据

入门爬虫一个月,所以对每一个网站都使用Xpath、Beautiful Soup、正则三种方法分别爬取,用于练习巩固。数据来源如下:

640?wx_fmt=png

本文使用Beautiful Soup讲解。

Xpath传送门:Xpath+requests爬取赶集网北京二手房数据

import requests
import re
from requests.exceptions import RequestException
from bs4 import BeautifulSoup
import csv
import time

headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'}

def get_one_page(url):
    try:
        response = requests.get(url,headers = headers)
        if response.status_code == 200:
            return response.text
        return None
    except RequestException:
        return None

def parse_one_page(content):
    try:
        soup = BeautifulSoup(content,'html.parser')
        items = soup.find('div',class_=re.compile('js-tips-list'))
        for div in items.find_all('div',class_=re.compile('ershoufang-list')):
            yield {
                'Name':div.find('a',class_=re.compile('js-title')).text,
                'Type': div.find('dd', class_=re.compile('size')).contents[1].text,#tag的 .contents 属性可以将tag的子节点以列表的方式输出
                'Area':div.find('dd',class_=re.compile('size')).contents[5].text,
                'Towards':div.find('dd',class_=re.compile('size')).contents[9].text,
                'Floor':div.find('dd',class_=re.compile('size')).contents[13].text.replace('\n',''),
                'Decorate':div.find('dd',class_=re.compile('size')).contents[17].text,
                'Address':div.find('span',class_=re.compile('area')).text.strip().replace(' ','').replace('\n',''),
                'TotalPrice':div.find('span',class_=re.compile('js-price')).text+div.find('span',class_=re.compile('yue')).text,
                'Price':div.find('div',class_=re.compile('time')).text
            }
        #有一些二手房信息缺少部分信息,如:缺少装修信息,或者缺少楼层信息,这时候需要加个判断,不然爬取就会中断。
        if div['Name', 'Type', 'Area', 'Towards', 'Floor', 'Decorate', 'Address', 'TotalPrice', 'Price'] == None:
                return None
    except Exception:
        return None

def main():
    for i in range(1,50):
        url = 'http://bj.ganji.com/fang5/o{}/'.format(i)
        content = get_one_page(url)
        print('第{}页抓取完毕'.format(i))
        for div in parse_one_page(content):
            print(div)
        with open('Data.csv', 'a', newline='') as f:  # Data.csv 文件存储的路径,如果默认路径就直接写文件名即可。
            fieldnames = ['Name', 'Type', 'Area', 'Towards', 'Floor', 'Decorate', 'Address', 'TotalPrice', 'Price']
            writer = csv.DictWriter(f, fieldnames=fieldnames)
            writer.writeheader()
            for item in parse_one_page(content):
                writer.writerow(item)
        time.sleep(3)#设置爬取频率,一开始我就是爬取的太猛,导致网页需要验证。

if __name__=='__main__':
    main()


对于小白容易遇见的一些问题:

a、有一些房屋缺少部分信息,如缺少装修信息,这个时候需要加一个判断,如果不加判断,爬取就会自动终止。我在这里跌了很大的坑。

b、Data.csv知识点存储文件路径默认是工作目录,关于工作目录传送门:python中如何查看工作目录

c、爬虫打印的是字典形式,每一个房屋信息都是一个字典,由于对Python中excel相关库是我知识盲点,所以爬虫的时候将字典循环直接写入CSV。

pycharm中打印如下:

640?wx_fmt=jpeg

图一

将字典循环直接写入CSV效果如下:

640?wx_fmt=jpeg

图二

d、很多初学者对于Address这种不知道如何处理,这里强调一下Beautiful Soup 中.contents的用法,亲身体会,我在这里花了好多时间才找到答案。

640?wx_fmt=jpeg

图三

Part2:R对爬取的二手房房价做一般线性回归分析

下面我们用R对抓取的赶集网北京二手房数据做一些简单的分析。

2.1、数据的说明

Name:主要是商家的醒目标题,分析的时候没有啥参考意义

Type:卧室数、客厅数、卫生间数

Area:面积(平方米)

Towards:朝向

Floor:楼层

Decorate:装修情况如:精装修、简单装修、毛坯房

Address:二手房的地址

TotalPrice:总价

Price:均价(元/平方米)

2.2、数据清洗

data<-read.csv("E://Data For R/RData/data.csv")
DATA<-data[,-c(1,7)]#将Name和Address两列去掉
DATA[sample(1:nrow(DATA),size=10),]
640?wx_fmt=jpeg

图四

#在爬取的时候加入了判断,所以不知道爬取的数据中是否存在缺失值,这里检查一下
colSums(is.na(DATA))


640?wx_fmt=jpeg

图五

#这里将Type的卧室客厅和卫生间分为三个不同的列
##这里需要注意,有一些房屋没有客厅如:1室1卫这时候需要单独处理,还有一些没有厕所信息。
library(tidyr)
DATA=separate(data=DATA,col=Type,into = c("Bedrooms","Halls"),sep="室")
DATA=separate(data=DATA,col=Halls,into = c("Halls","Toilet"),sep="厅")
##将卫生间后面的汉字去掉
DATA$Toilet<-str_replace(DATA$Toilet,"卫","")
###如图六,将Halls中带有汉字去掉,因为有一些房屋信息没有客厅,如:1室1厅,在分成卧室和客厅时,会将卫生间分到客厅一列。
DATA$Halls<-str_replace(DATA$Halls,"卫","")
##取出没有客厅信息的数据,这些数据被separate到Halls列
newdata<-DATA[which(DATA$Toilet %in% NA),2]
newdata
##将没有客厅的房屋信息Halls列填充为0
DATA[which(DATA$Toilet %in% NA),2]<-0
DATA[which(DATA$Toilet %in% NA),3]<-newdata
colSums(DATA=="")
  Bedrooms      Halls     Toilet       Area    Towards      Floor   Decorate 
         0          0          2          0          0          0          0 
TotalPrice      Price 
         0          0 

##发现有2个厕所没有信息,将其填写为0。
DATA$Toilet[DATA$Toilet == ""]<-0
640?wx_fmt=jpeg

图六

##这里将Area后的㎡去掉
DATA$Area<-str_replace(DATA$Area,"㎡","")

##查看Towards的类型
table(DATA$Towards)

Towards    北向  东北向  东南向  东西向    东向  南北向    南向  西北向 
     51      25      23      50      65      32    1901     678      38 
 西南向    西向 
     28      26 
##将Floor信息带括号的全部去除
DATA$Floor<-str_replace(DATA$Floor,"[(].*[)]","")##正则表达式
#查看Floor的类别信息
 低层  地下  高层 共1层 共2层 共3层 共4层 共5层  中层 
  632    32   790    36    61   101    68   130  1016 

#分别将TotalPrice和Price后面的万元、元/㎡去掉

DATA$TotalPrice<-str_replace(DATA$TotalPrice,"万元","")
DATA$Price<-str_replace(DATA$Price,"元/㎡","")

head(DATA)
640?wx_fmt=jpeg

图七

##将数据转换格式
DATA$Bedrooms<-as.factor(DATA$Bedrooms)
DATA$Halls<-as.factor(DATA$Halls)
DATA$Toilet<-as.factor(DATA$Toilet)
DATA$Area<-as.numeric(DATA$Area)
DATA$TotalPrice<-as.numeric(DATA$TotalPrice)
DATA$Price<-as.numeric(DATA$Price)
DATA$Towards<-as.factor(DATA$Towards)
DATA$Decorate<-as.factor(DATA$Decorate)
str(DATA)
640?wx_fmt=jpeg

图八

以上数据清洗完毕。

Part3:描述性分析

主要思路是探究单个自变量对因变量的影响,对房价的影响因素进行模拟探究之前,首先对各变量进行描述性分析,已初步判断房价的影响因素。这里探究各个因素对总价影响。

3.1探究Bedrooms与TotalPrice的关系

table(DATA$Bedrooms)
  1    2    3    4    5    6    7    9 
541 1225  779  193  102   20    5    1 
##由于拥有6、7、9个卧室数的数量较少,这里我们排出这些数据。
DATA<-DATA[-(which(DATA$Bedrooms %in% "6")),]
DATA<-DATA[-(which(DATA$Bedrooms %in% "7")),]
DATA<-DATA[-(which(DATA$Bedrooms %in% "9")),]
table(DATA$Bedrooms)
   1    2    3    4    5 
 541 1225  779  193  102 

library(ggplot2)
ggplot(DATA,aes(x=Bedrooms,y=TotalPrice))+geom_boxplot(col="red")
640?wx_fmt=jpeg

图九

DATA$Bedrooms<-as.numeric(DATA$Bedrooms)
##这里将卧室数为1、2、3命名为A,4为B,5为C
DATA$Bedrooms[DATA$Bedrooms=='1']<-"A"
DATA$Bedrooms[DATA$Bedrooms=='2']<-"A"
DATA$Bedrooms[DATA$Bedrooms=='3']<-"A"
DATA$Bedrooms[DATA$Bedrooms=='4']<-"B"
DATA$Bedrooms[DATA$Bedrooms=='5']<-"C"

不同卧室数,TotalPrice不同,且随着卧室数的增多,总价越高,符合大众的认知。

3.2探究Halls与TotalPrice的关系

 table(DATA$Halls) 
   0    1    2    3    4    5    9 
  20 1674 1050   77   18    1    0 
##5个客厅只有一个个体,我们这里将其排出
DATA<-DATA[-(which(DATA$Halls %in% "5")),]
table(DATA$Halls)
   0    1    2    3    4    5    9 
  20 1674 1050   77   18    0    0 
ggplot(DATA,aes(x=Halls,y=TotalPrice))+geom_boxplot(col="red")
640?wx_fmt=jpeg

图十

客厅数为3时候总价最高,客厅数为0、1和2的时候总价低于客厅数3和客厅数4。

3.3探究Toilet与TotalPrice的关系

#探究卫生间与总价的关系
table(DATA$Toilet)
   0    1    2    3    4    5    6    7    9 
   2 2142  470  116   74   26    7    2    0  
#这里将卫生间数为0、6和7的去掉
DATA<-DATA[-(which(DATA$Toilet %in% "0")),]
DATA<-DATA[-(which(DATA$Toilet %in% "6")),]
DATA<-DATA[-(which(DATA$Toilet %in% "7")),]
table(DATA$Toilet)
   0    1    2    3    4    5    6    7    9 
   0 2142  470  116   74   26    0    0    0 
ggplot(DATA,aes(x=Toilet,y=TotalPrice))+geom_boxplot(col="red")
640?wx_fmt=jpeg

图十一

一般卧室数越多,卫生间数也越多,即卫生间数越多,总价越高。

3.4探究Area与TotalPrice的关系

ggplot(DATA, aes(x=Area, y=TotalPrice)) + geom_point(col='red')
640?wx_fmt=jpeg

图十二

这个完全符合住房面积越大,总价越高。

3.5探究Towards与TotalPrice的关系

ggplot(DATA,aes(x=Towards,y=TotalPrice))+geom_boxplot(col="red")
640?wx_fmt=jpeg

图十三

3.6探究Floor与TotalPrice的关系

 ggplot(DATA,aes(x=Floor,y=TotalPrice))+geom_boxplot(col="red")
640?wx_fmt=jpeg

图十四

图中信息显示楼层一共只有1、2、3、地下的总价较高。

3.7探究Decorate与TotalPrice的关系

ggplot(DATA,aes(x=Decorate,y=TotalPrice))+geom_boxplot(col="red")
640?wx_fmt=jpeg

图十五

不同装修信息对总价影响较小。

Part4:模型建立

fit <-lm(TotalPrice~Bedrooms+Halls+Toilet+Area+Towards+Floor+Decorate,data=DATA)
summary(fit)

Call:
lm(formula = TotalPrice ~ Bedrooms + Halls + Toilet + Area + 
    Towards + Floor + Decorate, data = DATA)

Residuals:
     Min       1Q   Median       3Q      Max 
-1330.80  -103.49   -21.41    63.88  2961.59 

Coefficients:
                  Estimate Std. Error t value Pr(>|t|)    
(Intercept)      -112.7633    88.3010  -1.277 0.201697    
Bedrooms2         -43.5934    16.2533  -2.682 0.007359 ** 
Bedrooms3         -82.6565    20.7641  -3.981 7.04e-05 ***
Bedrooms4         -63.3096    34.9521  -1.811 0.070198 .  
Bedrooms5          79.0618    54.0763   1.462 0.143842    
Halls1             -5.0663    64.2764  -0.079 0.937182    
Halls2            -53.8905    65.4427  -0.823 0.410307    
Halls3           -303.9750    79.2280  -3.837 0.000127 ***
Halls4           -528.5427   104.0849  -5.078 4.07e-07 ***
Toilet2           112.9566    19.1171   5.909 3.87e-09 ***
Toilet3           543.7304    38.8056  14.012  < 2e-16 ***
Toilet4           735.1894    55.0977  13.343  < 2e-16 ***
Toilet5           338.7906    84.2851   4.020 5.98e-05 ***
Area                5.1091     0.1619  31.557  < 2e-16 ***
Towards东北向     138.9088    79.3817   1.750 0.080248 .  
Towards东南向     187.1895    68.5388   2.731 0.006351 ** 
Towards东西向     176.3055    65.8384   2.678 0.007453 ** 
Towards东向       210.9435    73.2744   2.879 0.004022 ** 
Towards南北向      75.7831    57.1199   1.327 0.184704    
Towards南向        60.1949    56.9678   1.057 0.290763    
Towards西北向      75.4326    71.1415   1.060 0.289091    
Towards西南向     169.8106    75.9626   2.235 0.025467 *  
Towards西向       234.0816    76.5585   3.058 0.002253 ** 
Floor地下        -812.3578    63.3277 -12.828  < 2e-16 ***
Floor高层          12.3525    14.2466   0.867 0.385991    
Floor共1层       -313.7278    52.1342  -6.018 2.00e-09 ***
Floor共2层       -453.3692    41.6829 -10.877  < 2e-16 ***
Floor共3层       -601.7032    44.3336 -13.572  < 2e-16 ***
Floor共4层       -183.7866    36.3396  -5.057 4.52e-07 ***
Floor共5层        -41.4184    25.7922  -1.606 0.108419    
Floor中层          -1.7223    13.5961  -0.127 0.899204    
Decorate简单装修  -63.1591    22.0584  -2.863 0.004224 ** 
Decorate精装修    -49.3276    19.8544  -2.484 0.013033 *  
Decorate毛坯     -157.0299    24.3012  -6.462 1.22e-10 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 265.5 on 2794 degrees of freedom
Multiple R-squared:  0.6852,    Adjusted R-squared:  0.6815 
F-statistic: 184.3 on 33 and 2794 DF,  p-value: < 2.2e-16

模型的F检验拒绝原假设,说明建立的模型是显著的;Ajusted R-squared 为0.6815,模型的拟合程度尚可接受。

后面还有模型的检验,由于近期实验太多了,之后有机会会进行更深入的探讨

(作为一小白,在抓取和分析过程中遇见非常多问题,非常感谢麟哥(徐麟,公众号:数据森麟)对我的耐心指导和鼓励。由于近期实验室实验太多且实验不顺,花了太多时间在实验上耽误了写这个,写了好几天草草结束。)



 大家都在看 

2017年R语言发展报告(国内)

精心整理 | R语言中文社区历史文章合集(作者篇)

精心整理 | R语言中文社区历史文章整理(类型篇)

640?wx_fmt=jpeg

公众号后台回复关键字即可学习

回复 爬虫             爬虫三大案例实战  
回复 
Python        1小时破冰入门

回复 数据挖掘      R语言入门及数据挖掘
回复 
人工智能      三个月入门人工智能
回复 数据分析师   数据分析师成长之路 
回复 机器学习      机器学习的商业应用
回复 数据科学      数据科学实战
回复 常用算法      常用数据挖掘算法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值