Python案例实现|爬取租房网站信息

简介: 本实战项目的数据来自于“北京链家网”的租房数据,网址为https://bj.lianjia.com/zufang/。

image.png


# 01、案例实现

下面以综合实战项目为例,从“北京链家网”爬取包括城区名(district)、街道名(street)、小区名(community)、楼层信息(floor)、有无电梯(lift)、面积(area)、房屋朝向(toward)、户型(model)和租金(rent)等租房信息。

爬取数据的程序流程图如图1所示。

image.png


■ 图1 “北京链家网”租房数据爬取流程图

(1) 导入库。代码如下。首先导入爬取过程中所需的库,这里仅对库进行简单说明,后面会详细讲解。

import csv
import random
import time
import requests
import pandas as pd
from Ixml import etree

其中,requests库用于请求指定页面并获取响应,etree库对返回的页面进行XPath解析,以获取指定的数据,random库和time库用于爬取过程中的一些设置,Pandas库和csv库用于处理和保存文件。

(2) 输入“北京链家网”的城市简称和要爬取的房源页面的页码范围。打开租房页面,首先展现的是房源列表页,通过观察不同城市的链家网租房页面的URL链接可知,一个房源列表页的URL链接主要分为3部分:城市的拼音简写、页码和其他相同部分,例如下面给出三个房源列表页的URL。

#北京
https://bj.lianjia.com/zufang/pg4/#contentList 
#重庆
https://cq.lianjia.com/zufang/pg5/#contentList 
#上海
https://sh.lianjia.com/zufang/pg6/#contentList

其中,第一条URL中的“bj”表示城市北京的拼音简写,“pg4”表示第4页。通过设置房源列表页URL的城市拼音简写,除了可以爬取北京的租房数据外,也可以爬取其他城市的租房数据。

本案例使用城市(如bj)和页码(pg4)的拼音简称构造一条房源列表页的URL链接,其中“#contentList”用于页内定位,可以忽略。

(3) 爬取并解析房源列表页。由于本案例拟爬取的房源信息在房源列表页和每一个房源的详情页均有分布,因此首先需要获取每一个房源详情页的URL链接。另外,房源列表页中还包含每一个房源所在的地理位置(所在城区、街道和小区)。下面介绍如何对房源列表页的页面信息进行分析,以获得房源详情页的URL链接和每一个房源的地理位置。

使用火狐浏览器打开“北京链家网”的租房页面https://bj.lianjia.com/zufang/ ,在页面空白位置右击,在弹出的快捷菜单中选择“检查”功能,单击页面最左侧小箭头形状的按钮,随后指向其中的一个房源信息,在“查看器”子窗口中右击蓝色文字的MTML代码,选择“复制”→“整体HTML”,得到如下的HTML内容(为简化分析难度,仅保留部分代码)。

<div class="content list">
<div class="content list--item">
<div class="content list--item--main"><p class="content list--item--title"><a class="twoline" target=" blank"href="/zufang/BJ2840486736310837248.html">整租·长阳国际城二区 3 室 1厅南/北< /a>
</p><p class="content list--item--des"><a target="blank"href="/zufang/fangshan/">房山</a>-<ahref="/zufang/changyang1/"target=" blank">长阳</a>-<atitle="长阳国际城二区"href="/zufang/c1111053458322/"target=" blank">长阳国际城二区< /a>
<i>/</i>
89.00m2
<i> /< /i>南北<i> /< /i>
3室1厅1卫<span class="hide"><i>/</i>
中楼层(20 层)</span></p>
< /div>
</div>
</div>

通过观察会发现,房源详情页的URL链接包含在

标签中的 标签的href属性中,房源的地理位置(城区名、街道名和小区名)包含在

标签中的3个“a”标签内。

获得房源的URL链接和地理位置的具体过程如下。

① 首先,通过XPath获取房源的URL链接,路径为//a[@class="content list--item--aside"]/@href。使用该路径可以获取当前页面中所有class属性为“contentlist--item--aside”的“a”标签的href属性值,得到的结果为当前页面所有房源的URL链接列表detailsUrl。

② 然后,通过XPath获取房源的地理位置(城区名、街道名和小区名),路径为 //p[@class="contentlist--item--des"]/a/text()。使用该路径可以获取当前页面中所有class属性为“contentlist--item--des”的“p”标签下“a”标签的文本内容,得到的结果为当前页面所有房源的地理位置列表location。需要注意的是,每一个“p”标签下共有3个“a”标签,分别对应房源的城区名、街道名和小区名。

③ 最后,通过遍历列表detailsUrl和列表location,将房源详情页URL链接和对应的城区名、街道名和小区名存放在字典中。

该部分代码如下。

defgetPageLines(city, page):
I I 获取指定城市和页码所在页面中的房源 URL 链接、所在地理位置 (district streetcommunity),并分别存入 house 字典中
:param city:城市简称
:param page:要爬取的页码
:return:字典列表
#构造房源列表页的 URL 链接
URI="https://"+ city +",lianjia.com/zufang/pg"+ str(page)
# 构造房源详情页 URL 链接的公共部分
baseUrl=URL.split("/")[0] +"//+ URL.split("/")[2
# 爬取房源列表页,并处理响应信息
response=reguests .get(url=URL)
# 获取页面 HTML,并对其进行解析
html=response.text
mvelement=etree .HTML (html)
# 提取本页面所有房源的 URL 链接和地理位置
detailsUrl=myelement.xpath('//al@class="content list--item--aside"]/@href门)
location=myelement.xpath('//p @class="content list--item--des"7/a/text
07
#将数据存入字典列表中
houses=list()
foriin range(len(detailsurl)):
# 获取房源详情页的 URI 链接detailsLink=baseUrl + detailsUrl i# 获取房源所在地理位置
slineIndex=i *
district=location lineIndex
street=location lineIndex + 17
community=location lineIndex + 2
# 将房源详情页 URI 链接和所在地理位置存入字典
house=[}
house "detailsLink" =detailsLink
house["districtu]=district
housel"street"=street
house "community"=community
houses.append(house)
return houses

(4) 爬取并解析房源详情页。从房源详情页中可以获取房屋楼层、电梯、面积、朝向、户型和租金等信息。在浏览器中打开一个房源详情页,通过火狐浏览器的“检查”功能获取房源详情页面的部分HTML源码。房源详情页的部分HTML源码如下。

<div class="content  aside--title">
<span>5500</span>元/月
(季付价)
<div class="operate-box">······</div></div>
<ul class="content aside list">
<li><span class="label">租赁方式:</span>整租</li><li><span class="label">房屋类型:</span>3室1厅1卫 89.00m’精装修</li>
<li class="floor"><span class="label">朝向楼层:</span><span class="">南/北中楼层/20 层< /span></li>
<li>
< span class="label">风险提示:</span></li>
</ul>
<div class="contentarticle  info" id="info"><h3 id="info">房屋信息< /h3>
<ul>
<li class="fl oneline">基本信息</li>
<li class="fl oneline">面积: 89.00m2< /li>
<li class="fl oneline">朝向: 南北< /li>
<li class="fl oneline">&nbsp;</li>
<li class="fl oneline">维护:7天前< /li>
<li class="fl oneline">入住:随时人住< /li>
<li class="fl oneline">&nbsp;</li>
<l class="fl oneline">楼层:中楼层/20 层</li>
<li class="fl oneline">电梯: 有</li>
...
</ul>

通过分析该段HTML源码可知,房屋租金位于class属性为“contentaside--title”的

标签下的标签中,房屋户型位于class属性为“contentaside list”的
标签下的第二个“li”标签中,楼层、电梯、面积和朝向4个房屋信息都存在于class属性为“contentarticle__info”的
标签下的“ul”标签下的“li”标签中。通过XPath获取“li”标签中的内容,并对文本内容进行数据清洗,以得到字典类型的目标数据,最后将其存入对应的house字典。

获得房源的楼层、电梯、面积、朝向、户型和租金等信息的具体过程如下。

① 在上一步得到的house字典中读取房源详情页的URL链接,发送请求获取房源详情页面的HTML源码,并对其进行解析。

② 通过XPath获取房屋租金rent和房屋户型model,得到的结果存入house字典。

③ 通过XPath获取房屋楼层、电梯、面积和朝向。因为HTML内容中解析得到的数据含有空格,使用dataCleaning()方法对其进行数据清洗,该方法同时对数据进行类型转换,最终将得到的房屋楼层、电梯、面积和朝向数据存入house字典。

至此,所需的数据都保存在house字典中,该部分代码如下。

defgetDetail(house) :
爬取并解析房源详情页的数据,将其存入字典中。
:param house:含有房源详情页 URL 链接和地理位置的字典
: return:含有案例拟爬取数据的字典

# 读取房源详情页的 URL 链接
url=house"detailsLink"
try:
response=requests.get(url=url,timeout=10)except:
return None,None
# 获取房源详情页面 HTML,并对其进行解析myelement=etree.HTML(response.text)# 获取房屋租金和房屋户型
house["rent"]=myelement.xpath('//div[@ class="content aside- - title"]/span/text()')[0house["model"]=(myelement.xpath('//ul[@class="content aside list"]/li[2]/text()'))[o].split("")[o]
# 获取房屋其他信息:楼层,电梯,面积,朝向
details=myelement.xpath('//div[@class="content article info"]/ul[1]/li/text())
details=dataCleaning(details)
house_"floor"=details"楼层
house["lift"=details["电梯
house"area”=details "面积"
house "toward"=details "朝向
return house,response.status code

在上面的代码中,使用dataCleaning()函数对一条房屋的信息进行数据清洗,以获取房屋的楼层、电梯、面积和朝向等数据。数据清洗包括两部分:删除数据中的空格'\xa0';将数据由列表类型转换成字典类型,以方便存储。例如,一条房屋信息原本的类型是列表类型:['基本信息','面积:89.00m2','朝向:南','\xa0','维护:5天前','入住:随时入住','\xa0','楼层:中楼层/28层','电梯:有','\xa0','车位:暂无数据','用水:暂无数据','\xa0','用电:暂无数据','燃气:有','\xa0','采暖:集中供暖'],经过dataCleaning()函数后,该房屋类型被转换为字典类型:{'面积': '89.00','朝向': '南','维护': '5天前','入住': '随时入住','楼层': '中楼层/28层','电梯': '有','车位': '暂无数据','用水': '暂无数据','用电': '暂无数据','燃气': '有','采暖': '集中供暖' }。dataCleaning()函数的具体实现如下。

def dataCleaning(details):
I I
对房屋信息进行清洗
:param details: 列表类型,一条房屋信息
:return: 字典类型,清洗后的房屋信息
details=detailsnew details=list()for detail in details:if detail="xa0":continuedetail=str(detail).split(':')new details.append(detail)
return dict(new details)

爬取网页时,不可避免会遇到“\xa0”字符串。“\xa0”其实表示空格。“\xa0”属于latin1(ISO/IEC_8859-1) 中的扩展字符集字符,代表空白符nbsp(non-breaking space)。latin1字符集可向下兼容ASCII码。

(5) 保存数据。通过Python的内置库CSV实现对字典数据按行保存。该部分代码如下。

save(row,fileName) :def
nn
按行保存数据
:param row:字典类型,每一行的数据
:param fileName: 数据保存的文件名
with open(fileName,"a+",newline= ,encoding='qbk') as f:writer=csv.DictWriter(f,fieldnames=fieldnames)writer.writerow(row)

(6) 主程序。在主函数中,从键盘输入链家网的城市简称和爬取的页码范围,并新建CSV文件,以保存爬取的数据。然后调用上述步骤中的各个函数进行数据爬取。

所有数据爬取完成后,通过第三方库Pandas对数据去除重复行,并在数据中添加一列“ID”作为索引列。至此,爬取任务完成。

该部分代码如下。

ifname==main
city = input("请输人要爬取的城市拼音(如北京: bj,上海: sh):").strip().lower()pageRange=input("请输人要爬取的页码范围(如第 1页到第 100 页:1-100):")strip()startPage=int(pageRange.split("-")[0])endPage=int(pageRange.split("-")[17) + 1
#将爬取的数据保存在 CSv 表
fileName=city n lianJia.csv"
fieldnames='floor','lift','district','street','community','area','toward''model''rent'
"w",newline='') as f:with open(fileName,#将表头写入 CSv 表
writer=csv.DictWriter(f,fieldnames=fieldnames)writer.writeheader()startTime=time .time ()
for page in range(startPager endPage):print("\n--->>正在爬取第”+ str(page) +"页”)houses=getPageLines(city=city,page=page)for house in houses:
data,statusCode=getDetail(house=house)
if data= None:
continueprint('响应状态:,statusCode)# CSV 文件不需要保存链接网址,所以删除 detailsLink 键值对del data "detailsLink"save(data,fileName)time.sleep(3)endTime=time .time ()print(耗时:,round(endTime- startTime,2),'s')# 使用 pandas 对数据表进行处理df=pd.read csv(fileName,encoding='gbk')# 删除重复行
df=df.drop duplicates ()index=list()
for i in range(1,len(df) + 1):id="rent" + str(i).zfill(4)index.append(id)
#插入 id列
df.insert(0,"id",index)
df.to csv(fileName,index=False,encoding='gbk')
目录
相关文章
|
9天前
|
程序员
大家来决定:python-office运行时的提示信息,要不要删除?
**摘要:** 程序员晚枫发起投票,询问是否应去除`python-office`项目运行时显示的中文提示信息,这些信息包含教程、源码链接和答疑群等。提示虽无运行影响,但显得不够专业。项目因用户咨询增加而添加此信息,作者考虑删除,因觉得与常见开源项目风格不同且其教程收费。附三张截图展示提示内容。用户可在评论区投票决定,输入“取消”或“保留”。
大家来决定:python-office运行时的提示信息,要不要删除?
|
3天前
|
人工智能 数据挖掘 大数据
538个代码示例!麻省理工教授的Python程序设计+人工智能案例实践
Python简单易学,且提供了丰富的第三方库,可以用较少的代码完成较多的工作,使开发者能够专注于如何解决问题而只花较少的时间去考虑如何编程。 此外,Python还具有免费开源、跨平台、面向对象、胶水语言等优点,在系统编程、图形界面开发、科学计算、Web开发、数据分析、人工智能等方面有广泛应用。 尤其是在数据分析和人工智能方面,Python已成为最受开发者欢迎的编程语言之一,不仅大量计算机专业人员选择使用Python进行快速开发,许多非计算机专业人员也纷纷选择Python语言来解决专业问题。 由于Python应用广泛,关于Python的参考书目前已经有很多,但将Python编程与数据分析、人工智
|
2天前
|
JSON 数据格式 索引
Python内置函数如`print()`输出信息,`len()`计算长度
【6月更文挑战第23天】Python内置函数如`print()`输出信息,`len()`计算长度,`type()`识别类型,`range()`生成序列,`sum()`求和,`min()`和`max()`找极值,`abs()`取绝对值,`round()`四舍五入,`sorted()`排序,`zip()`和`enumerate()`组合及遍历,`map()`和`filter()`应用函数。标准库如`os`用于操作系统交互,`sys`处理解释器信息,`math`提供数学运算,`re`支持正则表达式,`json`处理JSON数据。学习这些能提升编程效率。
11 5
|
5天前
|
机器学习/深度学习 自然语言处理 数据可视化
文本挖掘与可视化:生成个性化词云的Python实践【7个案例】
词云(Word Cloud),又称为文字云或标签云,是一种用于文本数据可视化的技术,通过不同大小、颜色和字体展示文本中单词的出现频率或重要性。在词云中,更频繁出现的单词会显示得更大,反之则更小。
|
5天前
|
机器学习/深度学习 自然语言处理 数据可视化
文本挖掘与可视化:生成个性化词云的Python实践【7个案例】
词云是文本数据可视化的工具,显示单词频率,直观、美观,适用于快速展示文本关键信息。 - 用途包括关键词展示、数据探索、报告演示、情感分析和教育。 - 使用`wordcloud`和`matplotlib`库生成词云,`wordcloud`负责生成,`matplotlib`负责显示。 - 示例代码展示了从简单词云到基于蒙版、颜色和关键词权重的复杂词云生成。 - 案例覆盖了中文分词(使用`jieba`库)、自定义颜色和关键词权重的词云。 - 代码示例包括读取文本、分词、设置词云参数、显示和保存图像。
23 1
|
8天前
|
存储 数据挖掘 索引
Python streamlit框架开发数据分析网站并免费部署
使用Python的Streamlit框架,开发了一个在线数据分析工具,替代Excel查看设备温度CSV数据。通过pandas读取数据,matplotlib绘制图表。程序处理CSV,提取所需列,计算最大最小平均值,用户可多选查看特定数据。[GitHub](https://github.com/yigedaigua/MGHB)上有完整代码,应用已部署至Streamlit Cloud。
|
10天前
|
数据采集 机器学习/深度学习 数据可视化
数据挖掘实战:Python在金融数据分析中的应用案例
Python在金融数据分析中扮演关键角色,用于预测市场趋势和风险管理。本文通过案例展示了使用Python库(如pandas、numpy、matplotlib等)进行数据获取、清洗、分析和建立预测模型,例如计算苹果公司(AAPL)股票的简单移动平均线,以展示基本流程。此示例为更复杂的金融建模奠定了基础。【6月更文挑战第13天】
42 3
|
11天前
|
Python 存储 数据处理
【Python数据类型的奥秘】:构建程序基石,驾驭信息之海
【Python数据类型的奥秘】:构建程序基石,驾驭信息之海
|
11天前
|
存储 缓存 Python
野生的Python装饰器案例
野生的Python装饰器案例
|
13天前
|
存储 XML 数据处理
Python网络实践:去哪儿旅游数据爬取指南
Python网络实践:去哪儿旅游数据爬取指南