大据采集与预处理课程设计任务书
- 数据采集与预处理的概述
要求:引言的作用,要以自己后面使用的内容分为中心简述。
2、XXX为基础的相关技术介绍
要求:
- 数据采集、预处理选择的技术或库选择介绍。要求具体到选用开发工具、库函数的介绍、API参数设置等,在数据预处理部分可有预处理方法选择的原由、针对同一类型预处理多种选择方法的对比分析。
- 文中引用内容用上标标注参考文献的引用
3、XXX数据爬取、预处理的分析设计与实现
要求:
-
-
- 原始网站数据出现的界面,预爬取数据的编程分析过程及关键结果的描述,包括爬取数据的URL、参数、定位信息、爬取时用到的header等,表述形式:截图+说明文字。
- 包括主要功能模块设计和介绍,数据存储方式和数据所含数据项的描述。
- 软件组成介绍:软件模块的项目结构截图或软件文件的资源管理器截图,并附文字介绍。以功能模块为切入点介绍具体的实现,针对功能模块附加必要的文字注释、解释、主要代码、运行界面和遇到的问题及对应的解决方法。
-
- 总结
主要介绍收获、心得体会、个人的展望、实现的完善方向等。
5、参考文献
目录
第二章 requests和lxml库为基础的相关技术和应用分析
通过了解芜湖市二手房的情况,可以帮助人们在购房、出租等方面做出更明智的决策。随着互联网的发展,越来越多的房地产信息通过网络发布,使用爬虫技术可以方便地收集和分析这些信息。
本次数据采集与预处理课程设计选择的数据来源是链家。链家是一家著名的房地产经纪公司,在芜湖市有着广泛的房地产业务。通过爬取芜湖市链家发布的二手房房信息,可以获得丰富的数据,为分析提供参考。
链家官网提供的数据包括二手房房源基本信息、房源描述、价格情况、中介服务等相关内容,以及用户留言反馈等信息。这些数据采用爬虫技术获取,在选择爬虫方式时,可以使用多种方式对数据进行筛选,通过对数据的筛选,从而获得更全面、准确的数据,得到我们需要的信息。
本次课程以链家网房源信息为例,爬取链家网二手房的房源信息相关,爬取完房源信息相关数据之后,对房源信息数据进行预处理,进行删除重复值,调整数据表格格式等一系列数据预处理操作,保证数据的准确性。在对链家网房源信息数据采集与预处理之后,对房源信息数据进行数据可视化相关操作,分析影响房价的一些因素,尝试画出了这些因素与房价的分布情况。
第二章 requests和lxml库为基础的相关技术和应用分析
① 原始网站页面
注意:
在原始网站界面可以观察到URL:芜湖二手房房源_芜湖二手房出售|买卖|交易信息(芜湖链家)
其中:wuhu是爬取城市的拼写
ershoufang:是爬取的房源类型拼写
② 当原始网站页面翻到了第二页时,URL发生了变化
注意:
URL:https://wuhu.lianjia.com/ershoufang/pg2/
可见界面换页操作是通过pg进行控制的
③ 观察请求方法与User-Agent
请求方法:get
User-Agent:
以页面第一个房源信息——翡丽世家叠墅为例
要爬取的数据有:
①楼房简介
②楼房地点
③楼房信息(户型,面积,朝向,装修,楼层,结构)
④楼房价格
⑤楼房单价
以翡丽世家叠墅为例。右键所选网页字段,选择检查,找到字段在源代码中的位置,右键选择复制选项栏中复制为完整的xpath路径
(1)楼房简介
xpath路径://*[@id="content"]/div[1]/ul/li[1]/div[1]/div[1]/a
(2)楼盘地点
需要获取两个部分的内容,分别位于div标签下的两个a标签中
xpath路径:① //*[@id="content"]/div[1]/ul/li[1]/div[1]/div[2]/div/a[1]
② //*[@id="content"]/div[1]/ul/li[1]/div[1]/div[2]/div/a[2]
(3)楼房信息
获取的楼房信息数据是以“|”为间隔的,后面进行数据预处理操作时,需要把楼房信息数据中的各个数据以间隔符“|”分开。
xpath路径://*[@id="content"]/div[1]/ul/li[1]/div[1]/div[3]/div
(4)楼房价格
总价 xpath路径://*[@id="content"]/div[1]/ul/li[1]/div[1]/div[6]/div[1]/span
单价 xpath路径://*[@id="content"]/div[1]/ul/li[1]/div[1]/div[6]/div[2]/span
(1)开发平台:PyCharm Community Edition 2022.3.2
Pycharm是一种Python IDE(Integrated Development Enviroment,集成开发环境),带有一整套可以帮助用户在使用Python语言开发时提高其效率的工具,比如调试、语法高亮、项目管理、代码跳转、智能提示 、自动完成、单元测试、版本控制。此外,该IDE提供了一些高级功能,以用于支持Django框架下的专业web开发。此次,以链家家房源数据为基础的数据采集和预处理就是Pycharm开发环境下运行的。
(2)库选择介绍:requests库、openpyxl库、lxml库、pandas库、tkinter库、os库、messagebox库。
- tkinter库: 用于创建 GUI 界面,包括窗口、标签、按钮等。tkinter 负责创建用户界面,让用户输入要爬取的页面数量;
- requests库: 用于发送 HTTP 请求,获取网页内容。requests 发送网络请求获取网页内容;
- lxml库: 用于解析 HTML 和 XML 文档,提取所需数据。lxml 解析网页内容提取所需数据;
- pandas库: 用于数据处理和分析,将爬取的数据存储到 DataFrame 中并进行预处理。pandas 将数据存储到 DataFrame 中并进行预处理;
- os库: 用于操作文件路径,获取桌面路径和创建 Excel 文件。os 获取桌面路径并创建 Excel 文件;
- openpyxl库: 用于读写 Excel 文件,对 Excel 文件进行格式调整。openpyxl 读取 Excel 文件并调整格式;
- messagebox库: 用于创建消息框,显示提示信息和错误信息。
(3)函数介绍:fetch_data_and_preprocess(pages)、start_scraping_and_preprocessing()、pd.read_excel()、DataFrame.drop_duplicates()、DataFrame.isnull().values.any()等
- pd.read_excel():读取 Excel 文件并将其转换为 pandas 的 DataFrame。
- DataFrame.drop_duplicates():去除 DataFrame 中重复的行。
- DataFrame.map():根据提供的映射将 DataFrame 中的某一列的值转换为其他值。
- DataFrame.isnull().values.any():检查 DataFrame 中是否存在空值,并返回结果。
- to_excel():将 DataFrame 写入 Excel 文件。
- load_workbook():加载一个已存在的 Excel 文件。
- Alignment(horizontal='center', vertical='center'):设置单元格文本的水平和垂直对齐方式。
- Font(bold=True):定义单元格文本的字体样式。
- wb.save():保存对 Excel 文件的修改。
- fetch_data_and_preprocess(pages) :从链家网站爬取指定数量的页面数据,并进行预处理。
- start_scraping_and_preprocessing():从 GUI 中获取用户输入的页面数量,并调用 fetch_data_and_preprocess(pages) 函数进行数据爬取和处理。如果用户输入的不是有效的页数,则弹出错误提示。
2.5数据预处理过程
数据预处理的方法有:1.数据清理,通过填写缺失的值,光滑噪声数据,识别或删除离群点并解决不一致性来“清理”数据;2.数据集成,将多个数据源中的数据结合起来并统一存储,建立数据仓库的过程实际上就是数据集成;3.数据变换;4.数据归约。
- 查看列名,删除不相关列
其中‘楼房简介’并不是用户买二手房的决定性因素,需要删除。
- 查看是否有重复行
在去除楼房简介之前先根据楼房简介来删除重复行,相对于其他的来说数据更加准确。
- 查看是否有空值
- 非数值列数值化
楼房结构共有板楼、板塔结合、暂无数据、塔楼三种。
用1表示板楼,2表示板塔结合,0表示暂无数据,3表示塔楼。
对于楼房结构列数值化
添加楼房结构化说明方便对照
(1)导入相关库
Gui总
芜湖链家家居数据爬取
(2)向网页发送请求
① URL的确定
由于要连续爬取多个页面的房源信息数据,所以用利用循环语句去改变URL。
我们可以通过改变pg参数来改变不同页面的URL,实现连续多页爬取
url = f'https://wuhu.lianjia.com/ershoufang/pg{i}'
② 确定请求方法
向网页发送get请求,并将请求结果赋给response
(3)解析页面数据
爬取的数据有楼房简介、楼房位置、楼房户型、楼房面积、楼房朝向、楼房装修、楼房楼层、楼房结构、楼房价格、楼房单价。
# 解析数据
div_list = data.xpath('//div[@class="info clear"]')
for div in div_list:
# 爬取标题信息
title = div.xpath('.//div[@class="title"]/a/text()')[0]
title_list.append(title)
# 爬取位置信息
positionInfo1 = div.xpath('.//div[@class="flood"]/div/a[1]/text()')[0]
positionInfo2 = div.xpath('.//div[@class="flood"]/div/a[2]/text()')[0]
positionInfo = positionInfo1 + positionInfo2
positionInfo_list.append(positionInfo)
# 爬取房源信息
houseInfo = div.xpath('.//div[@class="address"]/div/text()')[0]
houseInfo_list = houseInfo.split('|')
a = houseInfo_list[0].strip()
a_list.append(a)
b = houseInfo_list[1].strip('平米')
b_list.append(b)
c = houseInfo_list[2].strip()
c_list.append(c)
d = houseInfo_list[3].strip()
d_list.append(d)
e = houseInfo_list[4].strip()
e_list.append(e)
f = houseInfo_list[5].strip()
f_list.append(f)
# 爬取价格信息
priceInfo = div.xpath('.//div[@class="priceInfo"]/div[1]/span/text()')[0]
priceInfo_list.append(priceInfo)
unitInfo = div.xpath('.//div[@class="priceInfo"]/div[2]/span/text()')[0].strip('元/平') # 爬取房源的标签单价
unitInfo_list.append(unitInfo)
(4)存储数据
# 存储数据
name = ["楼房简介", "楼房位置", "楼房户型", "楼房面积(平米)", "楼房朝向", "楼房装修", "楼房楼层", "楼房结构",
"楼房价格(万/套)", "楼房单价(元/平)"]
housedata = pd.DataFrame(
zip(title_list, positionInfo_list, a_list, b_list, c_list, d_list, e_list, f_list, priceInfo_list,
unitInfo_list), columns=name)
数据预处理部分
# 去除重复行
housedata.drop_duplicates(subset=['楼房简介'], inplace=True)
# 去除"楼房简介"列
housedata.drop(columns=['楼房简介'], inplace=True)
# 检查空值
null_count = housedata.isnull().sum().sum()
if null_count > 0:
messagebox.showerror("错误", f"数据中存在 {null_count} 个空值,请处理后重新运行")
return
else:
print("数据中不存在空值")
# 楼房结构映射
structure_mapping = {
'板楼': 1,
'板塔结合': 2,
'暂无数据': 0,
'塔楼': 3
}
# 映射楼房结构
housedata['楼房结构'] = housedata['楼房结构'].map(structure_mapping)
# 创建预处理后的Excel文件
desktop_path = os.path.expanduser("~/Desktop")
preprocessed_file_path = os.path.join(desktop_path, "芜湖二手房(预处理完成).xlsx")
housedata.to_excel(preprocessed_file_path, index=False, engine='openpyxl')
# 加载新创建的Excel文件并调整格式
wb = load_workbook(preprocessed_file_path)
ws = wb.active
# 设置列宽和居中对齐
for col in ws.columns:
max_length = 0
column = col[0].column_letter
for cell in col:
try:
if len(str(cell.value)) > max_length:
max_length = len(str(cell.value))
except:
pass
cell.alignment = Alignment(horizontal='center', vertical='center')
# 单独处理楼房简介和楼房位置列,增加更多宽度
if col[0].value == '楼房简介' or col[0].value == '楼房位置':
adjusted_width = (max_length + 2) * 1.9 # 增加更多宽度
else:
adjusted_width = (max_length + 2) * 1.5 # 其他列适度增加宽度
ws.column_dimensions[column].width = adjusted_width
# 添加楼房结构说明
structure_notes = ['暂无数据', '板楼', '板塔结合', '塔楼']
structure_values = [0, 1, 2, 3]
structure_col = len(ws['A']) + 2 # 楼房结构说明列在原数据右侧
structure_col = len(ws['A']) + 2 - 21
for i, (note, value) in enumerate(zip(structure_notes, structure_values)):
note_cell = ws.cell(row=i + 1, column=structure_col, value=note)
value_cell = ws.cell(row=i + 1, column=structure_col + 1, value=value)
note_cell.alignment = Alignment(horizontal='center', vertical='center') # 居中对齐
value_cell.alignment = Alignment(horizontal='center', vertical='center') # 居中对齐
# 添加边框和设置字体
thin_border = Border(left=Side(style='thin'), right=Side(style='thin'), top=Side(style='thin'),
bottom=Side(style='thin'))
note_cell.border = thin_border
value_cell.border = thin_border
note_cell.font = Font(bold=True)
(4)输出数据并保存数据
#