第一次的爬取老师说可能不够好,这的那的,那就再来一次呗。
她推荐我们爬取武汉二手房的房价,因为里面的信息比较全。
红色圈出来的都需要爬,这老师,有点坑。
局限比较大,只能存放一页的数据,因为这个网站反扒有点恶心,不想搞了,而且获取一页的数据也够了,多了反而数据不好展示。
代码在最后面,直接展示可视化界面和保存的Excel数据了。
- 标题:就是黑色的大标题
- 价格:这个是总的价格,单位万元
- 地点:这个是主要作为可视化图像界面的x轴的,因为字比较短,标题太长了
- 布局:几室几厅的
- 具体位置:字面意思,具体位置
- 面积:这个直接获取的int类型的数字,因为要界面处理,只能获取数字
- 楼层:就是楼层
- 楼层数:就是楼层数
- 年份:有的就获取,没有的就是null
提前说一下,如果获取的内容都是空的,那就直接去网站上刷新一下,因为有个机制,但时候就知道了。
#Time : 2022-11-26
#Actor: WangDengtao
#Contents: Wuhan second-hand house information crawl
import requests
import bs4
import pandas as pd
import numpy as np
import time
import matplotlib.pyplot as plt
import xlwt
import re
import squarify
#解决乱码问题,显示中文标签
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False
#获取地点函数
#------------------------------------------------------------
def get_title(html):
title_buf = []
soup = bs4.BeautifulSoup(html.content, 'html.parser')
for dl in soup.find_all('dl',{'class':'clearfix'}):
title_f = dl.span.string
#去除‘\n’'\t',获取地址
title_a = list(title_f)
title_b = title_a[13:]
#合并列表中的各元素组成地名
title = ''.join(title_b)
title_buf.append(title)
return title_buf
#获取价格函数
#------------------------------------------------------------
def get_price(html):
price_buf = []
soup = bs4.BeautifulSoup(html.content, 'html.parser')
for dd in soup.find_all('dd',{'class':'price_right'}):
price_f = dd.b.string
price_f = int(price_f)
price_buf.append(price_f)
return price_buf
#获取地点函数
#------------------------------------------------------------
def get_addr(html):
addr_buf = []
soup = bs4.BeautifulSoup(html.content, 'html.parser')
for p in soup.find_all('p',{'class':'add_shop'}):
addr_f = p.a.string
#去除‘\n’'\t',获取地址
addr_a = list(addr_f)
addr_b = addr_a[12:-11]
#合并列表中的各元素组成地名
addr = ''.join(addr_b)
addr_buf.append(addr)
return addr_buf
#获取具体地址函数
#------------------------------------------------------------
def get_location(html):
location_buf = []
soup = bs4.BeautifulSoup(html.content, 'html.parser')
for p in soup.find_all('p',{'class':'add_shop'}):
location_f = p.span.string
location_buf.append(location_f)
return location_buf
#获取X室X厅
#------------------------------------------------------------
def get_all_a(a):
all_a_buf = []
a1 = list(a)
#print(a1[0])
a2 = list(a1[0])
a3 = a2[11:-23]
a4 = ''.join(a3)
#print(a4)
all_a_buf.append(a4)
return all_a_buf
#获取房屋面积
#------------------------------------------------------------
def get_all_b(a):
all_b_buf = []
a1 = list(a)
a2 = list(a1[2])
a2 = [item for item in a2 if item not in ['\n', '\t']]
a3 = a2[0:-1]
#print(a2)
a4 = ''.join(a3)
#print(a3)
a4 = float(a4)
all_b_buf.append(a4)
return all_b_buf
#获取房屋楼层
#------------------------------------------------------------
def get_all_c(a):
all_c_buf = []
a1 = list(a)
#print(a1)
a2 = list(a1[5])
#print(a2)
a3 = ''.join(a2)
if a3 not in ['中层', '高层','低层','顶层']:
a2 = list(a1[4])
#print(a2)
a4 = a2[25:-63]
#print(a4)
a3 = ''.join(a4)
#print(a3)
all_c_buf.append(a3)
return all_c_buf
#获取房屋楼层数
#------------------------------------------------------------
def get_all_d(a):
all_d_buf = []
a1 = list(a)
#print(a1)
a2 = list(a1[6])
a3 = [item for item in a2 if item not in ['\n', '\t']]
a5 = ''.join(a3)
if a5 in['南向','北向','西向','东向','东南向','东北向','西南向','西北向','南北向','东西向']:
a2 = list(a1[4])
#print(a2)
a3 = a2[51:-34]
#print(a6)
#print(a2)
a4 = ''.join(a3)
a7 = list(a4)
a8 = a7[2:-2]
a4 = ''.join(a8)
a4 = int(a4)
all_d_buf.append(a4)
return all_d_buf
#获取房屋建造年份
#------------------------------------------------------------
def get_all_e(a):
all_e_buf = []
a1 = list(a)
#print(a1)
a2 = list(a1[-1])
a3 = [item for item in a2 if item not in ['\n', '\t']]
#print(a2)
a4 = ''.join(a3)
if a4 in ['南向','北向','西向','东向','东南向','东北向','西南向','西北向','南北向','东西向']:
a4 = 'null'
all_e_buf.append(a4)
return all_e_buf
#画柱状图(地址+房价(单位万))
#------------------------------------------------------------
def picture2(all_price, all_addr):
x_data = all_addr;
y_data = all_price;
# 画图,plt.bar()可以画柱状图
for i in range(len(x_data)):
plt.bar(x_data[i], y_data[i])
# 设置x轴标签名
plt.xlabel("地点")
#设置刻度标记的大小,设置刻度的样式
plt.xticks(rotation = -90,size = 10)
#设置位置,方便看的
plt.subplots_adjust(left=0.05, bottom=0.297, right=0.962, top=0.95)
# 设置y轴标签名
plt.ylabel("价格(万)")
# 显示
plt.show()
#面积分布图(地址+面积)
#------------------------------------------------------------
def picture3(size, all_addr,indoor_planning):
plt.rcParams['font.sans-serif'] = 'Microsoft YaHei'
plt.rcParams['axes.unicode_minus'] = False
自定义颜色 = ['r', 'y', 'b', 'g', 'yellow', 'cyan', 'coral']
图 = squarify.plot(sizes = size,
label=all_addr,# 指定标签
color=自定义颜色, # 自定义颜色
alpha=0.6,
value=indoor_planning, # 添加数据标签
edgecolor='white', # 设置边界框颜色为白色
linewidth=3, # 设置边框宽度
text_kwargs={'fontsize': 9}) # 设置字体大小
图.set_title("房屋面积及房屋规划", fontdict={'fontsize': 20})
plt.axis('off') # 去掉坐标轴
plt.tick_params(top='off', right='off') # 去掉刻度
plt.show()
#分组柱状图(价格+面积+地点)
#------------------------------------------------------------
def picture4(size, all_price, all_addr):
# 设置标题
plt.title('价格面积分组柱状图')
#数据准备
x = all_addr
y1= all_price
y2= size
#设置图形宽度
bar_width = 0.3
X_A = np.arange(len(x)) # A班条形图的横坐标
X_B = X_A + bar_width # B班条形图的横坐标
#绘制图形
plt.bar(X_A,y1,bar_width,align='center',color='r')
#并列柱状图:x轴加上宽度
plt.bar(X_B,y2,width=bar_width,color='y')
plt.xticks(X_A + bar_width/2, x)# 让横坐标显示运动
#加图例
plt.legend(['价格(万)','面积(m3)'])
plt.ylabel('价格(万)面积(m3)') # 纵坐标轴标题
fig=plt.gcf()
#设置刻度标记的大小,设置刻度的样式
plt.xticks(rotation = -90,size = 10)
#设置位置,方便看的
plt.subplots_adjust(left=0.05, bottom=0.215, right=0.962, top=0.95)
#显示
plt.show()
#楼层分布图(楼层+层数+建造年份)
#------------------------------------------------------------
def picture5(floor, floors,year):
plt.rcParams['font.sans-serif'] = 'Microsoft YaHei'
plt.rcParams['axes.unicode_minus'] = False
自定义颜色 = ['r', 'y', 'b', 'g', 'yellow', 'cyan', 'coral']
图 = squarify.plot(sizes = floors,
label=floor,# 指定标签
color=自定义颜色, # 自定义颜色
alpha=0.6,
value=year, # 添加数据标签
edgecolor='white', # 设置边界框颜色为白色
linewidth=3, # 设置边框宽度
text_kwargs={'fontsize': 9}) # 设置字体大小
图.set_title("楼层及其建造年份", fontdict={'fontsize': 20})
plt.axis('off') # 去掉坐标轴
plt.tick_params(top='off', right='off') # 去掉刻度
plt.show()
#保存数据到EXCEL函数
#------------------------------------------------------------
def save_excel(all_price, all_addr,all_title,indoor_planning,all_location,size,floor,floors,year):
# 创建工作workbook
workbook = xlwt.Workbook()
# 创建工作表worksheet,填入表名
worksheet = workbook.add_sheet('Wuhan_House_Price_Table')
# 在表中写入相应的数据
worksheet.write(0, 0, '标题')
worksheet.write(0, 1, '价格(万)')
worksheet.write(0, 2, '地点')
worksheet.write(0, 3, '布局')
worksheet.write(0, 4, '具体位置')
worksheet.write(0, 5, '面积(m2)')
worksheet.write(0, 6, '楼层')
worksheet.write(0, 7, '楼层数')
worksheet.write(0, 8, '建造年份')
for i in range(len(all_price)):
worksheet.write(1+i, 0, all_title[i])
worksheet.write(1+i, 1, all_price[i])
worksheet.write(1+i, 2, all_addr[i])
worksheet.write(1+i, 3, indoor_planning[i])
worksheet.write(1+i, 4, all_location[i])
worksheet.write(1+i, 5, size[i])
worksheet.write(1+i, 6, floor[i])
worksheet.write(1+i, 7, floors[i])
worksheet.write(1+i, 8, year[i])
# 保存表
workbook.save('F:\course\python\science\Wuhan_housing_price_Trend.xls')
print('数据存入EXCEL成功!')
#主函数开始
#------------------------------------------------------------
url = ("https://wuhan.esf.fang.com/house/a21-i33/?rfss=1-3c99878a26acceb41e-6c")
#存放全部价格
all_price = []
#存放全部地点
all_addr = []
#存放全部标题
all_title = []
#存放全部地址
all_location = []
#存放小标签的地方
all_a = []
#存放x室X厅
indoor_planning = []
#存放房屋大小
size = []
#存放楼层
floor = []
#楼层数
floors = []
#房屋建造年份
year = []
for i in range(1,2):
try:
html = requests.get(url)
html.raise_for_status()
html.encoding = 'utf-8'
#将获取的网页代码生成TXT文件
path = 'E:\\评论第{}页.txt'.format(i)
with open(path, 'w', encoding = 'utf-8') as file:
file.write(html.text)
#获取标题
page_title = get_title(html)
all_title.extend(page_title)
#print(all_title)
#获取价格
page_price = get_price(html)
all_price.extend(page_price)
#print(all_price)
#获取地点
page_addr = get_addr(html)
all_addr.extend(page_addr)
#print(all_addr)
#获取具体地址
page_location = get_location(html)
all_location.extend(page_location)
#print(all_location)
#获取X室X厅、X平方米、楼层、楼层数、朝向、X年建
soup = bs4.BeautifulSoup(html.content, 'html.parser')
for dl in soup.find_all('dl',{'class':'clearfix'}):
a = dl.find('p',{'class':'tel_shop'})
#调用get_all_a()获取X室X厅存放在indoor_planning中
page_indoor_planning = get_all_a(a)
indoor_planning.extend(page_indoor_planning)
#调用get_all_b()获取房屋面积存放在size中
page_size = get_all_b(a)
size.extend(page_size)
#调用get_all_c()获取房屋面积存放在floor中
page_floor = get_all_c(a)
floor.extend(page_floor)
#调用get_all_d()获取房屋面积存放在floors中
page_floors = get_all_d(a)
floors.extend(page_floors)
#调用get_all_d()获取房屋面积存放在floors中
page_year = get_all_e(a)
year.extend(page_year)
#print(indoor_planning)
#print(size)
#print(floor)
#print(floors)
#保存到Excel中
save_excel(all_price, all_addr,all_title,indoor_planning,all_location,size,floor,floors,year)
#展示可视化图片
picture2(all_price, all_addr)
picture3(size, all_addr,indoor_planning)
picture4(size, all_price, all_addr)
picture5(floor, floors,year)
print("完成第{}页".format(i))
time.sleep(3)
except Exception as ex:
print("第{}页采集出错,出错原因:{}".format(i, ex))
想想后面用PowerBI又将数据整理了一下,感觉房价的确实难分析,因为地点太多了。
都有注释,具体字符串怎么处理的就不说了,直接用吧。