利用 Python 分析城市各区域楼盘

通过爬取某房产网站,得到某城市各楼盘的一些基本信息,包括楼盘名称,楼盘区域,参考价格等等。然后利用 Pandas, Numpy, matplotlib 等库进行数据分析及可视化
摘要由CSDN通过智能技术生成

1. 项目目标

  • 信息爬取:通过爬取某房产网站,得到重庆各楼盘的一些基本信息,包括楼盘名称,楼盘区域,参考价格,产权年限,开发商,物业公司,物业费,容积率,绿化率等信息
  • 数据分析:利用 Pandas, Numpy 等数据分析库对数据进行清洗与整理,并分析数据得出结论

2. 信息爬取

2.1 房产网站 URL 分析

1. 基础 URL:

  • 通过观察房产链接,可以看到其基础 URL 格式如下:

      https://[city].fang.lianjia.com/loupan/
    
  • 其中 city 为城市拼音首字母,例如重庆为 ‘cq’

2. 楼盘列表页:

  • 楼盘列表页包含了楼盘名称和对应的楼盘代码,楼盘代码是楼盘详情页链接的组成部分,所以我们要先提取列表页的信息

  • 观察可以发现,列表页的 URL 格式如下:

      base_url + house_class + page
    
  • 其中:

    • house_class = {‘全部’: ‘’, ‘住宅’: ‘nht1’, ‘别墅’: ‘nht2’, ‘写字楼’: ‘nht3’, ‘商业’: ‘nht4’, ‘底商’: ‘nht5’,},本次我们只分析住宅,所以选择 ‘nht1’
    • page,页数,与 house_class 直接相连,没有任何分隔符,格式为 ‘pg’+number,一页 10 个楼盘,我们分析前 50 页
  • 于是我们的列表页链接为:

      pages = range(1, 51)
      my_list_url = base_url + my_house_class + page, page in pages
      如:https://cq.fang.lianjia.com/loupan/nht1pg1
    

3. 楼盘详情页

  • 观察可以发现,楼盘详情页的 URL 格式如下:

      base_url + 'p_'+ 楼盘代码 + '/xiangqing/'
    
  • 可见关键部分为楼盘代码,这部分通过爬取列表页得到。通过观察列表页的源码,如下截图,我们可以在爬取楼盘列表页的时候使用 BeautifulSoup,利用 CSS 选择器,在楼盘列表页提取对应节点和楼盘代码。

      selected = soup.select('ul.resblock-list-wrapper div.resblock-name a')
    

2.2 楼盘列表页爬取

1. 网页源码分析:

  • 楼盘列表页中,我们只需要提取楼盘名称及其对应的 URL 代码即可,在 Chrome 中查看楼盘名称的源码,可以发现该文字链接在一个 a 节点中,完整的节点结构如下,在爬取的时候可以适当简化:

      body > div.resblock-list-container.clearfix > ul.resblock-list-wrapper > li:nth-child(1) > div > div.resblock-name > a
    

2. 提取信息:

  • 知道了楼盘名称及其代码的节点结构后,我们使用 BeautifulSoup 的 CSS 选择器来选中节点,并提取相关信息,存储到字典中,封装为函数后的代码如下:
def get_name_dic(url):
    response = requests.get(url, headers=headers)
    soup = BeautifulSoup(response.text, 'lxml')
    selected = soup.select('ul.resblock-list-wrapper div.resblock-name a')
    name_dic = {
   }
    for item in selected:
        name_dic[item.string] = item['href'][8:]
        print('code of {} getted.'.format(item.string))
    return name_dic

2.3 楼盘详情页爬取

1. 网页源码分析

  • 节点查找: 打开任意几个楼盘的详情页,观察网页结构及源码,发现我们需要的信息都在 class 为 x-box 的 ul 节点下面的 li 节点中,其中 ul 节点有两个,分别为基本信息和规划信息,前者包含参考价格,区域位置以及开发商,后者包含绿化率、容积率、产权年限等信息。
  • 节点分析:
    • 在 li 节点中,信息名称在 class 为 label 的节点中,信息值在 class 为 label-val 的节点中。
    • 仔细观察发现,参考价格并没有在 li .label-val 节点中,而在其子节点中,不过没有关系,当我们使用 text 属性提取文本的时候,节点中的所有文本都会被提取出来。
    • 对于区域名称也是一样的,即使城市名称和区域名称是分开的,我们可以都提取出来,在后面数据处理的时候统一处理,这样所有类型的信息提取方法都是一样的了。

2. 提取信息

  • 我们同样使用 BeautifulSoup 的 CSS 选择器来选中节点,并提取相关信息,存储到字典中,封装为函数后的代码如下:
# 获取楼盘中需要的信息
def get_info(url):
    soup = get_soup(url)
    lis = soup.select('ul.x-box li')
    infos = {
   }
    my_keys = ['参考价格:', '区域位置:', '绿化率:', '容积率:', '产权年限:', '开发商:', '物业公司:', '物业费:']
    for li in lis:
        if li.select('.label')[0].text in my_keys:
            label = li.select('.label')[0].text.replace(':', '')
            value = li.select('.label-val')[0].text.strip()
        else:
            continue
        infos[label] = value
        print('info getted')
    return infos

2.4 保存文件

  • 由于我们保存的数据结构均为字典,这里我们先保存为 JSON 格式的文件(后面再拓展以下保存至数据库等)
  • 注意中文字符在转换为 JSON 对象的时候要添加 ensure_ascii=False,否则会出现乱码
  • 另外我们在每次写入后都添加了一个换行符,避免一行字符太多,方便后面逐行读取数据
  • 封装后的代码如下:
def save_to_json(data, name='data'):
    results = json.dumps(data, ensure_ascii=False)
    with open(name + '.json', 'a+', encoding='utf-8') as f:
        f.write(results)
        f.write('\n')
    return None

2.5 提高代码运行速度

1. 第一版,效率低下

  • 其实上面已经完成了爬取的基本模块,主函数如下,但是运行速度很慢,爬取 50 页,500 个楼盘花了约 6 分多钟,需要提高代码运行效率。
'''效率低下版'''
CITY = 'cq'
MY_HOUSE_CLASS = 'nht1'
PAGES = range(1, 51)
def main():
	# 文件初始化
    with open(CITY + '.json', 'w', encoding='utf-8') as f:
        pass
	base_url = 'https://{}.fang.lianjia.com/loupan/'.format(CITY)
	houses = []
    name_dic = {
   }
    start = ctime()
    # 获取楼盘名称及代码
    for page in PAGES:
        print(page)
        list_url = '{base}{house}pg{page}'.format(base=base_url, house=MY_HOUSE_CLASS, page=page)
        name_dic.update(get_name_dic(list_url))
	# 爬取各楼盘信息
    for name, code in name_dic.items():
        detail_url = base_url + code + 'xiangqing/'
        my_info = get_info(detail_url)
        my_info['楼盘名称'] = name
        houses.append(my_info)
    # 保存文件
    save_to_json(houses)
    end = ctime()
    print('All done\nStarted at {}, done at {}'.format(start, end))

2. 多线程版本

  • 前段时间刚学习了使用 threading 模块实现多线程,在这个项目中,由于每页的爬取与存储是相对独立,互不干扰的,因此我们可以将每页的爬取与存储封装为一个函数,再使用 threading 模块实现多线程,使每页的工作同时进行。修改代码后,整个工作只使用了 40 多秒,速度提升了约 90% 。多线程版本的代码如下:
# 定义每页的爬取与保存函数
def get_and_save(page
  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值