python房价数据分析统计服_Python 爬取分析全国 12 个城市 4 万条房价信息,告诉你该怎样买房?...

本文介绍了一个Python爬虫项目,用于抓取链家网12个城市的4万条二手房信息,通过Requests、PyQuery等工具实现。文章详细讲解了爬虫架构、多线程爬取和IP代理池的使用,以及数据的分析和可视化过程,包括房价的最大值、最小值和平均值。最后展示了房价的可视化结果。
摘要由CSDN通过智能技术生成

原标题:Python 爬取分析全国 12 个城市 4 万条房价信息,告诉你该怎样买房?

作者 | 月小水长

责编 | 伍杏玲通过分页、线程池、代理池等技术,快速爬取链家网近4万条在售二手房信息,速度可达 10000 条 / 5 分钟。

通过对二手房作数据分析,得到北上广深等(新)一线城市四地房价的纵向比较,同时对各个城市各个区的房价做横向对比,并将对比结果可视化出来。

主要用到的库或模块包括 Requests、PyQuery、ThreadPoolExecutor、JSON、Matplotlib、PyEcharts。

环境:Widnows10、Python3.5、Pycharm2018。

数据抓取

爬虫架构设计

通过分析链家网的 URL ,不难发现,每一个城市的链家网的基本格式是:

城市名简拼 + ”.lianjia.com“

所以整个爬虫最外层应该是遍历一个保存城市简拼的列表,拼接得到一个个起始 URL,根据这些 URL 爬取对应城市的链家网。

针对每一个城市的链家网而言,首先得到该城市在售二手房的总套数,由于每一页显示的套数是 30,由总套数整除以30再加上1可以得到总页数,但是由于最大可浏览页数为 100,所以我们这里得加个判断,如果总页数大于 100 的话,令总页数等于 100。

分析具体城市的链家网每一页的 URL, 以北京为例,我们可以发现第 N 页的 URL 是:

bj.lianjia.com/ershoufang/pg{N},由此我们可以通过以下代码来得到每一页的 URL:

fori inrange(total_page):

page_url = "bj.lianjia.com/ershoufang/pg{}".format(i+1)

本来得到每一页的 URL 后,我们可以得到该页上 30 套房的房价信息和详情页 URL,但是页面上没有房子所在区的信息。

我们只能再向下请求访问详情页 URL,从而提取出我们想要的所有数据。

综上所述,我们可以将整个框架从上往下分为四层,如下图所示:

基于上述思路,在写代码的时候,可以分层从上往下实现,方便调试。

第一层 & 第二层:获取总套数

根据城市简拼得到起始 URL,并得到总套数,为分页做准备。

defget_list_page_url(city):

start_url = "https://{}.lianjia.com/ershoufang".format(city)

headers = {

'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36',

}

try:

response = requests.get(start_url, headers=headers)

# print(response.status_code, response.text)

doc = pq(response.text)

total_num = int(doc(".resultDes .total span").text())

total_page = total_num // 30+ 1

# 只能访问到前一百页

iftotal_page > 100:

total_page = 100

page_url_list = list()

fori inrange(total_page):

url = start_url + "/pg"+ str(i + 1) + "/"

page_url_list.append(url)

#print(url)

returnpage_url_list

except:

print("获取总套数出错,请确认起始URL是否正确")

returnNone

第三层:根据起始 URL 得到分页 URL

defget_detail_page_url(page_url):

globaldetail_list

headers = {

'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36',

'Referer': 'https://bj.lianjia.com/ershoufang'

}

try:

response = requests.get(page_url,headers=headers,timeout=3)

doc = pq(response.text)

i = 0

detail_urls = list()

foritem indoc(".sellListContent li").items():

i += 1

print(i)

ifi == 31:

break

child_item = item(".noresultRecommend")

ifchild_item == None:

i -= 1

detail_url = child_item.attr("href")

detail_urls.append(detail_url)

returndetail_urls

except:

print("获取列表页"+ page_url + "出错")

第四层

本层做的是具体解析,解析使用的是 PyQuery 库,支持 CSS 选择器且比 Beautiful Soup 方便。仅仅需要下面几行代码就帮助我们获得了目标数据:

response= requests.get(url=detail_url, headers=headers, proxies=proxies)

#detail_url 是得到的详情页 URL

detail_dict= dict()

doc= pq(response.text)

unit_price= doc(".unitPriceValue").text()

unit_price= unit_price[0:unit_price.index("元")]

title= doc("h1").text()

area= doc(".areaName .info a").eq(0).text().strip()

url= detail_url

多线程爬取

由于待爬取的数据量巨大,使用单线程速度太慢,最开始采用了第三方库 ThreadPool 来实现多线程,后来了解到 Python3.5 的内置包 concurrent.futures,使用里面的 ThreadPoolExecutor 来实现多线程,速度又提升了 20% 以上。

p = ThreadPoolExecutor(30)

forpage_url inpage_url_list:

p.submit(get_detail_page_url, page_url).add_done_callback(detail_page_parser)

p.shutdown()

第 1 行通过构造函数新建了线程池对象,最大可并发线程数指定为 30,如不指定,其默认值是 CPU 数的 5 倍,第 2、3 行依次把爬取的任务提交到线程池中,并设置回调函数,这里的回调函数拿到的是一包含 get_detail_page_url 返回值的对象。

并把这个对象作为回调函数的参数 res,先把返回的res得到一个结果,即在前面加上一个res.result(),这个结果就是 get_detail_page_url 的返回值。

IP 代理池

由于爬取的数量大,同时由于多线程提高了速度,链家网会拒绝访问,这时可通过代理 IP 来访问,这里使用已经有的轮子,源码链接附在文末。

下载后新开一个 Pycharm 视窗运行该项目,然后我们可以用下面的方式来获取可用的代理 IP:

defget_valid_ip():

url = "http://localhost:5000/get"

try:

ip = requests.get(url).text

returnip

except:

print("请先运行代理池")

然后通过参数设置使用代理 IP:

proxies = {

"http": "http://"+ get_valid_ip(),

}

response = requests.get(url=detail_url, headers=headers, proxies=proxies)

数据保存

采用 JSON文件形式保存数据,每个城市保存一个 JSON文件,文件名为该城市简拼。

defsave_data(data,filename):

withopen(filename+".json", 'w', encoding="utf-8") asf:

f.write(json.dumps(data, indent=2, ensure_ascii=False))

稍等一会儿,所有数据就保存在本地了:

本爬虫所爬数据仅为本人测试,严禁商用。

数据分析

数据整合

在这里做一些求同地区房价最大值、最小值、平均值,以及数据格式统一化的工作:

def split_data():

global region_data

region_data = dict()

for region in dic_data.keys():

# 最大值、最小值、平均值

region_data[region] = {"max":dic_data[region][0],"min":dic_data[region][0],"average":0}

for per_price in dic_data[region]:

if per_price > region_data[region]["max"]:

region_data[region]["max"] = per_price

if per_price < region_data[region]["min"]:

region_data[region]["min"] = per_price

region_data[region]["average"] += per_price

region_data[region]["average"] /= len(dic_data[region])

# 保留两位小数

region_data[region]["average"] = round(region_data[region]["average"],2)

数据可视化

将分析结果通过 Matplotlib 直观的体现出来,该部分的代码如下:

defdata_viewer():

label_list = region_data.keys() # 横坐标刻度显示值

max = []

min = []

average = []

forlabel inlabel_list:

max.append(region_data[label].get("max"))

min.append(region_data[label].get("min"))

average.append(region_data[label].get("average"))

x = range(len(max))

"""

绘制条形图

left: 长条形中点横坐标

height: 长条形高度

width: 长条形宽度,默认值0

.8

label: 为后面设置legend准备

"""

rects1 = plt.bar(x=x, height=max, width=0.25, alpha=0.8, color='red', label="最大值")

rects2 = plt.bar(x=[i + 0.25fori inx], height=average, width=0.25, color='green', label="平均值")

rects3 = plt.bar(x=[i + 0.5fori inx], height=min, width=0.25, color='blue', label="最小值")

#plt.ylim(0, 50) # y轴取值范围

plt.ylabel("房价/元")

"""

设置x轴刻度显示值

参数一:中点坐标

参数二:显示值

"""

plt.xticks([index + 0.2forindex inx], label_list)

plt.xlabel("地区")

plt.legend()

forrect inrects1:

height = rect.get_height()

plt.text(rect.get_x() + rect.get_width() / 2, height+1, str(height), ha="center", va="bottom")

forrect inrects2:

height = rect.get_height()

plt.text(rect.get_x() + rect.get_width() / 2, height + 1, str(height), ha="center", va="bottom")

forrect inrects3:

height = rect.get_height()

plt.text(rect.get_x() + rect.get_width() / 2, height + 1, str(height), ha="center", va="bottom")

plt.show()

结果如下:

限于篇幅,其他城市的图就不放了。

再来看全国主要一线城市二手房房价有序条形图:

可以看出,北京、上海、深圳的房价大致在同一水平线,而厦门位于第四,广州在第六,最后看一下房价地域图:

最后看一下房价地域图这是基于 Java 的可交互动态图,放截图挺别扭的,我已经把它放在我的网上了,感兴趣的可以点击在线观看。

作者简介:月小水长,某 985 计算机学院在校生,熟悉 C++、Java、Python 等多种语言,有大型软件项目开发经验,致力于安卓、计算机视觉、爬虫、数据可视化开发,同时也是业余的前端爱好者。

微信公众号:inspurer

源码:https://github.com/Python3Spiders/LianJiaSpider.git

动态图展示:https://inspurer.github.io/fang_price_city.html

责任编辑:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值