【Python】爬取贝壳网深圳二手房数据
一,爬取数据
1,爬取目标内容
先打开页面/ershoufang/ ,看下页面的结构,分页的列表页,点击就可以跳转到对应的详细页面,有详细的二手房信息。
主要爬取编号、户型、楼层、朝向、面积、单位面积房价、总价、小区名称、所在区域以及URL。
2,爬起思路
贝壳网二手房都是这种分页的形式,总共100页,每一页的列表有30个二手房详细页链接。两种思路:
第一,用循环的方式,构建下一页URL,访问抓取,直到100页后停止;
第二,直接用xpath定位下一页的标签属性href,取出下一页URL,直至100页,此时下一页的标签属性href是空值,于是停止抓取。
但是,贝壳网底部的分页栏数据是通过js动态加载出来的,所以,直接requests请求的页面,没法用xpath定位下一页的标签,因此,还是采用第一种思路,根据页数循环请求下一页的数据内容。
于是开始写代码,用scrapy框架爬取,写好spider代码,并且使用之前已经做好的cookies池以防被反爬。结果一运行,速度还可以,也正常运行,就是数据有点少,才3000条,但是页面显示总共4万多条房源信息,数据量差得有点多。
如果按照之前的思路就只能爬取3000条房源信息,因为就总共显示100页,一页30条,上限就3000。所以需要换种思路,观察页面,发现可以按区域筛选,比如,罗湖区-百仕达下有686条房源,如果只爬取这个区域的,没超过3000,肯定可以完整地爬取686条,其他区域也是相同的,这样一个一个区域的爬取就基本把整个深圳市的二手房信息都爬取了。
接下来,就是要解决分页的问题,可以看到每个区域二手房总数都会显示出来,比如罗湖区-百仕达有686条,那么一页显示30条,那就至少有23页,前面22页每页都是30条,第23页只有26条,这要计算出页数后,再构造循环去抓取每一页就行了,其他区域也是相同的做法。
3,代码实现
思路确定后,就代码实现,还是使用scrapy框架爬取,但是在此需要获取所有小区域的URL。先规定,罗湖区这样的大区域为一级区域,其下的区域为二级区域。这样先爬取一级区域URL,再根据一级区域URL爬取二级区域的。
class BeikeInit(object):
def __init__(self, city):
self.pre_url = city_url.get(city) #城市url
def get_ershoufang(self):
"""
爬取一级区域url
:return:一级区域url列表
"""
response = requests.get(self.pre_url)
if response.status_code == 200:
etree_obj = etree.HTML(response.text)
region_lists = etree_obj.xpath('//div[@data-role="ershoufang"]/div/a/@href')
region_urls = [self.pre_url+url[11:] for url in region_lists]
return region_urls
def get_area(self,region_urls):
"""
根据一级区域url,爬取其下的二级区域url
:param region_urls: 一级区域url列表
:return: 二级区域url列表
"""
area_urls =[]
for url in region_urls:
response = requests.get(url)
if response.status_code == 200:
etree_obj = etree.HTML(response.text)
area_lists = etree_obj.xpath('//div[@data-role="ershoufang"]/div[2]/a/@href')
for url in area_lists:
area_urls.append(self.pre_url + url[12:])
return area_urls
接下来编写spider代码,最主要是构建初始爬取的url队列,以及页码,页数的计算以及传递,以下是部分代码:
def start_requests(self):
# 根据二级区域url,构建爬取队列
for url in self.area_urls:
# 请求时,传递初始的参数,url,页码,页数
yield scrapy.Request(url=url,callback=self.parse, meta={'region_url': url, 'curpage': 0, 'pagenum':0})
def parse(self, response):
# 获取请求时携带的参数
region_url = response.meta['region_url']
curpage = response.meta['curpage']
pagenum = response.meta['pagenum']
if curpage == 0:
# 获取总数
total = response.xpath('//div[@class="resultDes clear"]//span/text()').extract_first().strip()
# 设置当前页的页码为1
curpage = 1
# 计算页面数
pagenum = math.ceil(int(total) / 30)
house_list = response.xpath('//ul[@class="sellListContent"]//li[@class="clear"]')
# 爬取详细页
for i_item in house_list:
house_item = KeItem()
url = i_item.xpath('.//a/@href').extract_first()
house_item['url'] = url
# 请求详细页
yield scrapy.Request(url=url, callback=self.parse_detail, meta={'item': house_item})
curpage +=1 # 页码加1
# 判断是否继续爬取下一页
if curpage <= pagenum:
# 请求下一页,回调parse,并带上相应的参数
next_url = region_url+'pg{}/'.format(curpage)
yield scrapy.Request(next_url,callback=self.parse,meta={'region_url': region_url, 'curpage': curpage, 'pagenum': pagenum})
4,爬取结果
程序运行后,单机爬取了差不多2个小时,时间比较久,可能主要是代码写得不够好,还有就是单机,如果分布式就可以快点,除此之外,还有scrapy参数设置,网速都可能有些影响。运行后日志如图:
这是10月27号运行的,所以数据就截止是2019年10月27日,总共爬取到45285个item,也就是45285条二手房源数据,并保存在文件中。
二,数据可视化
爬取到45285条房源后,看了数据发现就要有地下车库的信息,于是删除这部分数据后剩余45269条房源数据,这部分数据截止至2019年10月27日。
其中最贵的是南山区深圳湾的一套别墅,接近42万一平,总价1亿多。
最便宜的是龙华区观澜的一套商品房,1万多一平,总价25万,
整个深圳市二手房平均5.98万一平,差不多6万吧。
根据每平米房价绘制直方图,为了区别展示明显些,对y轴取了对数,可以看出,房价集中在5-10万元/平方米,同时也存在着一些天假房,还有一些经济的商品房。
根据各城区二手房单位面积房价箱线图,单位面积房价均值可以看出,南山区的房价波动较大,均价也是最高的,并且存在着挺多异常值,也是天价房。去过南山区都知道那里都是大企业,高科技企业,高楼大厦的,各种生活娱乐,购物的大商城,还有科技园,可以说是寸土寸金。
在看下各户型和朝向单位面积房价均值,
毕业后在深圳南山区工作过一段时间,感觉那里房价和物价是真的高,但是高也有其高的道理,许多高科技,上市企业将总部设在这里,科技园和南山中心都是高楼林立;各种休闲娱乐商场,美食购物广场,这里的生活质量水平都很高;还是那句话,深圳是遍地黄金,奋斗者的世界。
哈哈哈,以上是博主练手爬虫的项目,有问题错误,请拍砖评论交流!最后发发感慨,最后祝愿各位在北上广深奋斗的追梦者,都可以实现自己的梦想。