python爬虫实战:使用scrapy和matplotlib进行房地产数据分析


虽然python爬虫已经火了很多年,但今天我们依然会通过scrapy爬虫框架结合matplotlib数据分析库实战一个房地产网站的数据采集以及数据分析,来帮助大家更系统的掌握大数据分析的进本流程。快跟随icode9小编一起来学习吧。

在今天的文章中,我们将从最大的房地产网站之一提取房地产列表,然后分析数据。与我们之前的网络数据分析博文类似,我将向您展示一种使用python提取网络数据然后对数据集进行描述性分析的简单方法。

技术堆栈和方法
我们将使用 python 作为编程语言。

工具和库:

尽管这可能是一个非常复杂的项目,因为它还涉及网络抓取和数据分析,但我们将通过使用以下过程使其变得简单:

定义数据要求
实施数据提取
进行数据分析(查询数据库+可视化)
开始吧!

资料要求
对于每个网络抓取项目,我们需要回答的第一个问题是——我们到底需要什么数据?当涉及到房地产清单时,我们可以抓取的数据点太多了,我们必须根据我们的需要真正缩小范围。现在,我将选择这些字段:

上市类型
价格
房屋面积
城市
建成年份
这些数据字段将使我们能够自由地从不同的角度查看列表。

数据提取
既然我们知道要从网站中提取哪些数据,我们就可以开始处理我们的蜘蛛了。

安装 Scrapy
我们正在使用 Scrapy,这个项目的网络抓取框架。建议在虚拟环境下安装Scrapy,这样不会和其他系统包冲突。

创建一个新文件夹并安装 virtualenv:

mkdir real_estate 
cd real_estate 
pip install virtualenv 
virtualenv env
源 env/bin/activate
安装废料:

pip 安装 scrapy
如果您在安装 Scrapy 时遇到问题,请查看安装指南。

创建一个新的 Scrapy 项目:

scrapy startproject 房地产
检查
现在我们已经安装了 Scrapy,让我们检查一下我们试图从中获取数据的网站。为此,您可以使用浏览器的检查器。我们的目标是在页面上的 HTML 中找到所有数据字段,并为它们编写一个选择器/XPath。

上面的 HTML 片段包含许多列表元素。在每个<li>标记内,我们可以找到许多我们正在寻找的字段,例如 listing_type 字段。由于不同的列表定义了不同的细节,我们不能仅根据 HTML 标签或 CSS 选择器来选择数据。(一些房源定义了房屋大小,而另一些则没有)因此,例如,如果我们想从上面的代码中提取房源类型,我们可以使用 XPath 来选择一个在其文本中具有“房源类型”的 HTML 元素,然后提取它的第一个兄弟。

listing_type的 Xpath :

“//span[@class='listing-detail-stats-main-key'[contains(text(),'ListingType')]/following-sibling::span”

然后,我们可以对房屋大小等做同样的事情……

“//span[@class='listing-detail-stats-main-key'[contains(text(),HouseSize)]/following-sibling::span”

找到所有选择器后,这是我们的爬虫代码:

def 解析(自我,响应):
        item_loader = ItemLoader(item=RealEstateItem(),response=response)
        item_loader.default_input_processor = MapCompose(remove_tags)
        item_loader.default_output_processor = TakeFirst()
        item_loader.add_value("url", response.url) 
        item_loader.add_xpath("listing_type", "") 
        item_loader.add_css("price", "") 
        item_loader.add_css("price", "") 
        item_loader.add_xpath(" house_size", "") 
        item_loader.add_css("city", "") 
        item_loader.add_xpath("year_built","")
        返回 item_loader.load_item()
如您所见,我正在使用ItemLoader。这样做的原因是对于某些字段,提取的数据是混乱的。例如,这是我们得到的原始房屋面积值:

2,100 平方英尺
该值在当前形式下不可用,因为我们需要一个数字作为房屋大小。不是字符串。所以我们需要去掉单位和逗号。在 Scrapy 中,我们可以为此使用输入处理器。这是带有清洁输入处理器的house_size字段:

house_size = Field( 
      input_processor=MapCompose(remove_tags, strip, lambda value: float(value.replace(" sqft", "").replace(",", ""))) 
      )
这个处理器做什么,按顺序:

移除 HTML 标签
删除不必要的空格
删除“平方英尺”
删除逗号
输出变成一个数值,可以很容易地插入到任何数据库中:

2100
为每个字段编写清理函数后,这就是我们的项目类的样子:

类 RealEstateItem(项目): 
       listing_type = Field( 
       input_processor=MapCompose(remove_tags, strip) 
       ) 
       price = Field( 
       input_processor=MapCompose(remove_tags, lambda value: int(value.replace(",", ""))) 
       ) 
       house_size = Field( 
       input_processor=MapCompose(remove_tags, strip, lambda 值: float(value.replace(" sqft", "").replace(",", ""))) 
       ) 
       year_built = Field( 
       input_processor=MapCompose(remove_tags, strip) , lambda 值: int(value)) 
       ) 
       city = Field() 
       url = Field()
数据库管道
至此,我们处理了数据提取部分。为了准备用于分析的数据,我们需要将其存储在数据库中。为此,我们创建了一个自定义的 Scrapy 管道。如果您不确定 Scrapy 中的数据库管道是如何工作的,请查看这篇文章。

类数据库管道(对象):
   def __init__(self, db, user, passwd, host): 
     self.db = db 
     self.user = user 
     self.passwd = passwd 
     self.host = host
   @classmethod 
   def from_crawler(cls, crawler): 
     db_settings = crawler.settings.getdict("DB_SETTINGS")
     如果不是db_settings: 
        raise NotConfigured 
     db = db_settings['db'] 
     user = db_settings['user'] 
     passwd = db_settings['passwd '] 
     host = db_settings['host'] 
     return cls(db, user, passwd, host)
   def open_spider(self, spider): 
     self.conn = MySQLdb.connect(db=self.db, 
                   user=self.user, passwd=self.passwd, 
                   host=self.host, 
                   charset='utf8', use_unicode=True) 
     self.cursor = self.conn.cursor()
   def process_item(self, item, spider): 
     sql = "INSERT INTO Listing (url, price, listing_type, house_size, year_built, city) VALUES (%s, %s, %s, %s, %s, %s)" 
     self.cursor.execute(sql, 
                  ( 
                   item.get("url"), 
                   item.get("价格"), 
                   item.get("listing_type"), 
                   item.get("house_size"), 
                   item.get(" year_built"), 
                   item.get("city") 
                  ) 
                  ) 
     self.conn.commit()
     返回项目
   def close_spider(self, spider): 
       self.conn.close()
现在我们可以运行我们的蜘蛛:

scrapy 爬行 real_estate
如果我们做的一切都正确,我们应该在数据库中看到提取的记录,格式很好。

数据分析
现在我们要可视化数据。希望能对它有更深入的了解。我们将要遵循的绘制图表的过程:

查询数据库获取需要的数据
将其放入熊猫数据框中
必要时清理、操作数据
使用panda的plot()函数绘制图表
在分析数据集时得出影响深远的结论之前,需要指出几件重要的事情:

我们只有大约 3000 条记录(我没有抓取整个网站,只有一部分)
我删除了土地清单(没有建筑物)
我只抓取了美国 9 个城市的列表
描述性报告
首先,让我们“了解”一下我们的数据库。我们将把整个数据库查询到一个数据框中,并创建一个新字典来获取所有数字数据字段的最小值、最大值、平均值和中值。然后从字典创建一个新的数据框,以便能够将其显示为表格。

query = ("SELECT price, house_size, year_built FROM Listing") 
df = pd.read_sql(query, self.conn) 
d = {'平均值': df.mean(), 
     'Min': df.min(), 
     ' Max': df.max(), 
     'Median': df.median()} 
return pd.DataFrame.from_dict(d, dtype='int32')[["Min", "Max", "Mean", "Median "]].转置()

这张表向我们展示了一些信息:

最古老的房子建于1837年
最便宜的房子是 19 900 美元,最贵的是 15 950 000 美元
最小的房子是 256 平方英尺,最大的是 17 875 平方英尺
平均房屋建于 1950 年代
平均房屋面积为 1883 平方英尺(174 平方米)
户型比例
总的来说,我们有三种房源类型:公寓/联排别墅、多户住宅和单户住宅。让我们看看哪些在列表中更受欢迎。

查询 = ("SELECT listing_type, COUNT(*) AS 'count' FROM Listing GROUP BY listing_type") 
df = pd.read_sql(query, self.conn, index_col="listing_type") df.plot.pie(y="count ", autopct="%1.1f%%", figsize=(7, 7)) 
plt.show()

超过一半的房源是单户住宅。其中大约三分之一被认为是公寓/联排别墅。只有 12.3% 是多户住宅。

价格与年份的相关性
接下来,让我们看看价格。最好看看建筑物的价格和年龄之间是否存在任何相关性。

query = "SELECT price, year_built FROM Listing" 
df = pd.read_sql(query, self.conn) 
x = df["year_built"].tolist() 
y = df["price"].tolist() 
c = 计数器( zip(x, y)) 
s = [10 * c[(xx, yy)] for xx, yy in zip(x, y)] df.plot(kind="scatter", x="year_built", y= "price", s=s, color="blue") 
yy, locs = plt.yticks() 
ll = ['%.0f' % a for a in yy] 
plt.yticks(yy, ll) 
plt.show( )

我们在这里看到的是,我们几乎每年都有一份清单。但我们并不能从中得出明确的结论。好像20世纪上半叶的房子不少,而且比新造的还贵。

每个城市的平均价格
在这一篇中,我们将查看每个城市的价格标签。

query = “SELECT FLOOR(AVG(price)) AS 'price', city, COUNT(city) AS 'count' FROM Listing GROUP BY city HAVING count > 30” 
df = pd.read_sql(query, self.conn) 
df = df.drop(df.index[1]) ax = plt.gca() ax.get_yaxis().get_major_formatter().set_useOffset(False) ax.get_yaxis().get_major_formatter().set_scientific(False) df.plot。 barh(x="city", y="price", color="royalblue", 
ax=ax, grid=True) 
plt.xlabel("AvgPrice ($)") 
plt.ylabel("城市") 
plt.show ()

在我们分析的城市中,旧金山和西雅图是最贵的。旧金山的平均房价约为 165 万美元。西雅图约为 185 万美元。买房最便宜的城市是奇克托瓦加和布法罗,这两个城市的平均房价约为 25 万美元。

每种户型的平均价格
在接下来的分析中,我们将检查不同房屋类型的平均价格。三种户型中,哪一种最贵,哪一种最便宜?

query = "SELECT FLOOR(AVG(price)) AS 'price', listing_type FROM Listing GROUP BY listing_type" 
df = pd.read_sql(query, self.conn) 
ax = plt.gca() 
df.plot(kind="酒吧", x="listing_type", y="price", color="royalblue", ax=ax, grid=True, rot=0) 
plt.xlabel("Type") 
plt.ylabel("AvgPrice ($)" ) 
plt.show()

正如我们所见,Condo/Townhome 和 Multi-Family Type 房屋之间没有太大区别。两者都在 1,000,000 美元至 1,200,000 美元之间。单户住宅要便宜得多,平均价格为 800,000 美元。

本文是与icode9.com icode9技术文章分享的小编一起来为大家呈现这篇技术文章,希望本文能对大家有帮助。感谢阅读!

本站声明:
1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;

2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;

3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;

4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;

5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/295084.html

(0)
上一篇 2023年1月13日
下一篇 2023年1月13日

相关推荐

发表回复

登录后才能评论