Quantcast
Channel: CodeSection,代码区,Python开发技术文章_教程 - CodeSec
Viewing all articles
Browse latest Browse all 9596

绝对的Geek!!用 Python 写了个机器人,租到了满意的房子

$
0
0

今天分享的这篇译文,讲述的是硅谷的一位工程师利用编程技能帮助自己又快又好地租房的故事。

数月前,我从波士顿搬到了湾区。我和 Priya(我女朋友)都听说了各种关于租房市场的恐怖故事。事实是,找房子是一个痛苦的过程。在 Google 上搜索“怎样在旧金山租公寓”,得到的 许多 建议的页面就是很好的证明。


绝对的Geek!!用 Python 写了个机器人,租到了满意的房子

波士顿很冷,但在旧金山找房子很可怕

我们了解到一些房东会举行开放日(open house)活动,届时你需要带上所有的文件材料,并且只有当你交了押金才会被考虑。我们对流程进行了详尽的研究,发现找房子的时机很重要。一些房东举行开放日活动,任何人都可以参加,而对于另一些房东,第一个去看房往往更能租到房子。因此你需要找到房屋出租的消息,快速审核房子是否符合你的标准,然后打电话给房东安排看房,才有机会。

译注:在国外的房产交易行业中,开放日是一种新颖的房产销售方式。它允许对房子感兴趣的人们直接去参观房子。

我们浏览了网络上推荐的一些房子租赁网站,比如 Padmapper 和 LiveLovely ,但是没有一个网站能为我们提供一个可供查看与评估的实时信息,也没有一个网站能让我们指定额外的标准,比如特定的社区,或者交通便利性。绝大多数湾区房子的租赁信息原本都在 Craigslist 上,之后才被其他站点采集,这就造成了一点担忧:(其他站点)采集的租赁信息可能不全,或者它们采集得不够迅速,实时性不强。

我们想要这样:

当 Craigslist 上有新的公告时,实时地获得通知。 过滤掉不是我们期望的社区的房子。 过滤掉不满足额外标准的的房子,比如公共交通便利性。 整合房子的租赁信息,以便对它们进行评估。 对于我们感兴趣的房子,要能方便地联系房东。

对问题进行过思考后,我意识到我们可以分四步解决问题:

从 Craigslist 采集租赁信息。 过滤掉不匹配我们的标准的房子。 将租赁信息发送到 Slack ,这是一个团队聊天工具,这样我们就能讨论并评估房子。 将整个过程封装进一个持续的循环中,并部署到服务器上(这样它就能一直运行了)。

在下文中,我们将介绍每一步是如何完成的,以及如何使用最终的 Slack 机器人帮助我们找房子。借助这个机器人,我和 Priya 在约一周之后就找到了一个我们都喜爱的,价格又合理(就旧金山而言)的卧室,这比我们预期要花费的时间少多了。

如果你想要在阅读本文的过程中看一看代码,项目链接在 这里 ,README.md 的链接在 这里 。

第一步 从 Craigslist 采集租赁信息

创建机器人的第一步是从 Craigslist 获取租赁信息。不幸的是,Craigslist 并不提供 API,但是我们可以使用 python-craigslist 包来获得房子的公告。用python-craigslist采集页面内容,再用 BeautifulSoup 从页面中提取出相关的部分,并转换成结构化的数据。这个包的代码相当简短,值得通读一遍。

Craigslist 网上,旧金山房子信息的网址是https://sfbay.craigslist.org/search/sfc/apa。在下面的代码中,我们将:

导入craigslistHousing,这是python-craigslist中的一个类。 用以下参数初始化类: site 要采集的 Craigslist 网站。site是 URL 的第一部分,比如https://sfbay.craigslist.org。 area 要采集的网站下的分区。area是 URL 的最后部分,比如https://sfbay.craigslist.org/sfc/,仅代表旧金山。 category 要查找的房子的类型。category是搜索 URL 的最后部分,比如https://sfbay.craigslist.org/search/sfc/apa,将列所有的房子。 filters 应用于结果的任何过滤器。 max_price 能承受的最高价 min_price 要查找的最低价 使用get_results方法从 Craigslits 获取结果,其实是一个 生成器 。 传入geotagged参数以尝试为每条结果添加坐标。 传入limit参数以只获取20条结果。 传入newest参数以只获取最新的租赁信息 从results生成器中获取每条result,并打印。 from craigslist import CraigslistHousing
cl = CraigslistHousing(site='sfbay', area='sfc', category='apa',
filters={'max_price': 2000, 'min_price': 1000})
results = cl.get_results(sort_by='newest', geotagged=True, limit=20)
for result in results:
print result

我们已经快速地完成了机器人的第一步!现在,我们就可以对 Craigslist 进行采集并获取租赁信息了。每一条Result都是带几个字段的字典:

{'datetime': '2016-07-20 16:39',
'geotag': (37.783166, -122.418671),
'has_image': True,
'has_map': True,
'id': '5692904929',
'name': 'Be the first in line at Brendas restaurant!SQuiet studio available',
'price': '$1995',
'url': 'http://sfbay.craigslist.org/sfc/apa/5692904929.html',
'where': 'tenderloin'}

下面是对字段的描述:

datetime 租赁信息公布的时间。 geotag 租赁信息上标注的坐标位置。 has_image Craigslist 公告上是否带图片。 has_mag 租赁信息是否带有相应的地图。 id 租赁信息在 Craigslist 上的 id。 name Craigslist 上显示的名称。 price 月租价。 url 查看完整的租赁信息的 URL。 where 租赁信息创建者标注的房子位置。 第二步 过滤结果

既然我们已经能够从 Craigslist 上获取租赁信息了,我们只需对它们进行过滤,就可以看到我们感兴趣的那些。

地区过滤

我和 Priya 在找房子时,我们只考虑了一部分区域,包括:

旧金山 日落区 太平洋高地 下太平洋高地 伯纳尔高地 列治文区 伯克利 奥克兰 亚当斯点 梅里特湖 岩石岭 阿拉米达

为了对社区进行过滤,我们首先需要定义包围盒(boundbing box),用于划出一个边界区域:


绝对的Geek!!用 Python 写了个机器人,租到了满意的房子
在下太平洋区域画一个包围盒

上图中的包围盒是用 BoundingBox 创建的。在左下角选择csv选项,以获得包围盒的顶点坐标。

你也可以使用像谷歌地图这样的工具,通过找出左下角和右上角的坐标来自定义包围盒。找出包围盒之后,我们创建一个社区与坐标的字典:

BOXES = {
"adams_point": [
[37.80789, -122.25000],
[37.81589, -122.26081],
],
"piedmont": [
[37.82240, -122.24768],
[37.83237, -122.25386],
],
...
}

用社区名做字典的键,每个键对应一个列表的列表。第一个内部列表表示包围盒左下角的坐标,第二个则表示右上角的坐标。然后,我们就可以通过检查坐标是否在某个包围盒内进行过滤。

下面的代码将:

遍历BOXES的键。 检查结果是否在包围盒内。 若结果在包围盒内,设置合适的变量。 def in_box(coords, box):
if box[0][0] < coords[0] < box[1][0] and box[1][1] < coords[1] < box[0][1]:
return True
return False
geotag = result["geotag"]
area_found = False
area = ""
for a, coords in BOXES.items():
if in_box(geotag, coords):
area = a
area_found = True

然而不幸的是, 并不是所有从 Craigslist 获取的结果都带有坐标信息。是否带坐标信息,取决于发布公告的人是否指定了位置,而坐标可以从位置中计算出。他对于在 Craigslist 发布公告越熟悉,那么他越有可能附上位置信息。

通常由代理中介发布的公告会带有位置信息,但他们往往会收取高额租金。房东自己发布的公告一般不带坐标信息,但也会更划算。因此,弄清楚那些不带坐标信息的房子是否在我们期望的社区很重要。我们将创建一个社区的列表,再进行字符串匹配,以检查那些房子是否落在其中。因为许多房子的社区信息是错误的,使得这样做的精确度不如使用坐标高,但聊胜于无。

NEIGHBORHOODS = ["berkeley north", "berkeley", "rockridge", "adams point", ... ]

要进行基于名字的匹配,我们可以对NEIGHBORHOODS进行遍历:

location = result["where"]
for hood in NEIGHBORHOODS:
if hood in location.lower():
area = hood

采集结果经以上代码处理之后,我们就过滤掉了所有不在我们想要入住的社区中的房子。可能会有一些误报,我们会遗漏掉那些既没有社区信息也没有指定位置的房子,但这个系统已经记录了大量的住房信息。

根据交通便利性进行过滤

我和 Priya 都清楚我们会很频繁地去旧金山,因此如果我们不住在旧金山的话,我们就要住的离公交进一点。在湾区,公交的主要形式是 BART 。BART 是一个半地下的交通系统,连接了奥克兰、伯克利、旧金山以及周围的区域。

为了在我们的机器人上实现这个基础功能,我们首先需要定义一个换乘站的列表。我们可以从 谷歌地图 获取换乘站的坐标,然后建一个字典:

TRANSIT_STATIONS = {
"oakland_19th_bart": [37.811805

Viewing all articles
Browse latest Browse all 9596

Latest Images

Trending Articles