python爬虫--爬取各大城市的各个区域的租房信息
一、选题背景
衣食住行是生活的基本需求。衣和食好解决,不喜欢的衣服可以买新的,不好吃的食物可以换一家吃。可是在住宿上,买房和租房的置换成本都相对较高,因此房源选择尤为慎重。作为目前买不起房的自然人,我们一般是通过中介来实现租房的需求比如自如,贝壳找房和链家。链家占据了租赁市场的主导地位,且提供的信息相对公允。但每当我刷超过十个房源,我就会记不起来每一个的信息,也无法可视化去比较很多个房源,城市里面大多数多个区,数据太多导致难以分辨。所以我通过python来爬取链家网上我所需要的指定区域的租房信息,就可以可视化的去比较多个房源对于租房也更有利,可以说是更快更方便的找到心仪的房子。
二、主题式网络爬虫设计方案
1.主题式网络爬虫名称
武汉市各个区域租房信息爬取
2.主题式网络爬虫爬取的内容与数据特征分析
武汉市各个区域租房信息爬取,主要爬取了链家网上武汉市江岸的租房信息的数据。
爬取武汉江岸租赁方式,每月租金,行政区,板块,房屋面积,格局,朝向等信息。
3.主题式网络爬虫设计方案概述(包括实现思路与技术难点)
思路:查看网页的结构,定位目标数据的位置,爬取数据,将数据进行清洗,最后将清洗后的数据进行可视化。
难点:如何解决数据分析缺少模块,如何爬取多个页面的数据,请求异常的处理
三、主题页面的结构特征分析
1.主题页面的结构与特征分析
目标内容界面:

2.Htmls 页面解析



3.节点(标签)查找方法与遍历方法
打开网页的源码,然后用鼠标检查工具找打对应大概位置进行查找,先找大标签,再找其中的小标签。
我们这里把要获取的数据找着之后,然后在元素中对应位置分析。(如图对应的就是元素中“div.content.clear.w1150”)

四、网络爬虫程序设计
1.数据爬取与采集
以下为爬取流程图

以下为爬取过程的代码
import requests
import time
from lxml.etree import HTML, parse
from pymongo import MongoClient
import sys
import re
import random
import redis
import hashlib
以上为导入库的代码
def parse_content(content, col):
"""
content, lxml.etree.HTML() 对象
col, MongoDB集合
"""
#解析当前页面数据 div块列表
divs = content.xpath('//div[@class="content__list--item--main"]')
#print(divs)
cur_page_items = []
#解析列表中的每一个房源div块
for div in divs:
try:
trp = div.xpath(".//p[@class='content__list--item--title']/a/text()")[0].strip("\n").strip().split(" ")
#标题部分经过空格划分后长度大部分都为3,其他的忽略,以提高程序的健壮性
if len(trp) == 3:
title, room_type, position = trp
print(title, room_type, position)
#详细位置
detail_place = "-".join(div.xpath(".//p[@class='content__list--item--des']/a/text()"))
print("detail place:", detail_place)
#解析房源面积
raw_square = div.xpath(".//p[@class='content__list--item--des']/text()")
#print(raw_square)
square = re.findall("(\d+\.\d+)", "".join(raw_square))[0]
print("square:", square)
#解析价格
price = div.xpath(".//span[@class='content__list--item-price']/em/text()")[0]
print("price:", price)
except:
continue
#每平方的价格
square_price = round(float(price) / float(square), 1)
item = {
"title": title,
"room_type": room_type,
"square": float(square),
"position": position,
"detail_place": detail_place,
"price": float(price),
"square_price": square_price
}
cur_page_items.append(item)
#将当前页面中所有的房源项插入MongoDB集合
col.insert_many(cur_page_items)
以上为分析房源内容代码
def get_areas(url, col):
"""
url, 形式如https://wh.lianjia.com
col, MongoDB中的集合
"""
print('start grabing areas...')
# 设置请求头
headers = {
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) \
Chrome/63.0.3239.108 Safari/537.36',
}
# 获取请求页面数据
res = requests.get(url + "/zufang/", headers=headers)
content = HTML(res.text)
# 获取当前城市的区域信息
areas = content.xpath('//ul[@data-target="area"]/li[@class="filter__item--level2 "]/a/text()')
print(areas)
# 获取当前城市的区域链接
areas_link = content.xpath('//ul[@data-target="area"]/li[@class="filter__item--level2 "]/a/@href')
print(areas_link)
# 遍历获取所有区域的链接,按每个区域去获取数据
for i in range(len(areas)):
area = areas[i]
area_link = areas_link[i]
# 拼接区域链接 域名地址 + 路径
#如https://wh.lianjia.com + /zufang/jiangan/
link = url + area_link
print("start to fetch area link:" + link)
#获取一个区域的所有租房信息
get_pages(area, link, col)
#获取一个区域的所有数据,数据过多时会产生分页
def get_pages(area, area_link, col):
"""
area, 区域字符串
area_link, 区域链接,如https://wh.lianjia.com/zufang/jiangan/
col, MongoDB中的集合
"""
headers = {
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36',
}
#发送请求
res = requests.get(area_link, headers=headers)
#print(res.status_code)
content = HTML(res.text)
#解析当前页的content对象
parse_content(content, col)
#判断当前区域共有多少页,并分析下一页的url结构
#https://wh.lianjia.com/zufang/jiangan/pg2/
#https://wh.lianjia.com/zufang/jiangan/pg3/
#有个div节点,class='content__pg' 有总页数
try:
total_pages = content.xpath('//*[@id="content"]/div[1]/div[2]/@data-totalpage')[0]
print("共计页数:",total_pages)
except:
print("parse area link pages error:", area_link)
return
#逐一获取后续的每一页,然后解析数据
for i in range(2, int(total_pages) + 1):
#请求下一页
nex_page = area_link + "pg%d"%i + "/"
get_house_info(area, nex_page, col)
以上为获取城市区域信息代码
hlist = []
headers = {
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko)\
Chrome/63.0.3239.108 Safari/537.36',
}
time.sleep(random.uniform(0.5,1.5))
try:
# 获取页面信息
res = requests.get(url, headers=headers)
content = HTML(res.text)
#解析入库
parse_content(content, col)
except Exception as e:
print(e)
print( 'ooops! connecting error, pls retry.....')
time.sleep(3)
def main(city):
print('start to fetch data of %s!'%city)
# 需要爬取的url
url = 'https://{0}.lianjia.com'.format(city)
client = MongoClient('localhost', 27017)
db = client.get_database("lianjia")
col = db.get_collection("loupan")
#按照当前城市的各个区 进行抓取房源数据
get_areas(url, col)
以上为爬取数据到数据库的代码
以下是部分代码截图



因为我们这是可以爬取多个城市租房信息的代码,在jupyter note中运行了之后,这里我们要手动输入“wh”才会出现武汉地区我们想要爬取的租房信息

获取了以下信息(武汉可租房的房子信息数据基本上都在图内)爬取了“https://wh.lianjia.com/zufang/”网页的信息

数据实在多看的眼花缭乱,而且数据过多也失去了原本爬虫的本意。
经过数据处理之后选取了以下部分数据,更加直观,针对某一区域的租房信息。
以下是爬取“https://wh.lianjia.com/zufang/jiangan/”网页的信息

4.数据分析与可视化
#对地区分组计算平均房价和最高房价
pipeline = [
{"$group":
{
"_id": "$area",
"avgPrice": {"$avg": "$square_price"},
"maxPrice": {"$max": "$square_price"}
}
},
]
#设置match和group分组聚合管道得到城市每个区租房的房价信息
match_pipeline = [
{"$match":
{
"room_type": re.compile("2室1厅"),
"square": {"$gt": 60, "$lt": 100},
}
},
{"$group":
{
"_id": "$area",
"avgPrice": {"$avg": "$square_price"},
"maxPrice": {"$max": "$square_price"}
}
},
]
以上为数据可视化处理的部分代码

以下为爬出的柱形图

由图可知,我们所爬取的武汉最高房价远远高于最低房价
爬取出来的饼状图

5.数据持久化
import requests
from bs4 import BeautifulSoup
import sqlite3
import pandas as pd
url = "https://wh.lianjia.com/zufang/jiangan/"
response = requests.get(url)
if response.status_code == 200:
print("请求成功")
soup = BeautifulSoup(response.content, 'html.parser')
table = soup.find('div', attrs={"class": 'chart'})
rows = table.find_all('tr')
data = []
for row in rows:
cells = row.find_all('td')
if len(cells) == 15:
date = cells[0].text
Front_Area_1 = cells[1].text
# ... 继续提取其他数据
data.append([date, Front_Area_1, ...])
df = pd.DataFrame(data, columns=['租赁方式', '每月租金', ...])
# 连接到SQLite数据库
conn = sqlite3.connect('lottery_data.db')
cursor = conn.cursor()
cursor.execute(create_table_query)
# 插入数据
insert_query = 'INSERT INTO lottery (每月租金,行政区,板块,房屋面积,格局和发布时长) VALUES (?, ?, ?, ..., ?);'
cursor.executemany(insert_query, df.values.tolist())
# 提交事务并关闭连接
conn.commit()
conn.close()
print("数据已保存到数据库")
else:
print("请求失败")
以上为数据持久化的代码

6.将以上各部分的代码汇总,附上完整程序代码
(1)爬虫代码部分

(2)数据可视化代码

(3)数据持久化代码

五、总结以及遇到的问题
对本课程设计的整体完成情况做一个总结,通过这次利用python代码爬虫爬取网站数据并分析,得出武汉的平均房价远远低于最高房价。同时租房面积50到70平米的占比最多,30平米以下的租房人数最少。这让我掌握了最基础的数据分析知识,体验了数据分析的乐趣,包括数据预处理,异常值的查找等,数据的合并和分组及聚合,还有数据可视化来直观的观察,分析数据,更加直观的获得自己想要的信息,也变得更加便捷。同样大多数人面临这样一个挑战:我们认识到数据可视化的必要性,但缺乏数据可视化方面的专业技能。部分原因可以归结于,数据可视化只是数据分析过程中的一个环节,数据分析师可能将精力花在获取数据、清洗整理数据、分析数据、建立模型。
问题:由于anaconda之前下载的版本问题,数据分析缺少很多模块,在cmd中用“pip list”查询模块可以说是基本上的模块都没有,想要安装模块也一直是安装失败。在查询“python”表示是安装成功。在网上查询了才知道是我的anaconda版本问题。我将原本的anaconda彻底卸载(如果没有彻底卸载新安装的其他版本的anaconda也是不能使用的)通过“清华大学开源镜像网站”,重新下载了anaconda3-2021.11版本,之后再cmd中查询安装数据分析运行所缺失的模块都很顺利。折腾了许久之后终于解决了运行问题。