分享到:

Python
——从入门到PY交易

其实我早就入门了。

其实我入门了好多次。

不过这次是我第一次真正写出来一个有点用处的脚本。

虽然最终租下房子还是中介提醒我可以预定了,这脚本没完全起效。




事情起因是因为最近房子快到期了,所以考虑换一套。

由于有跟人合租的需求,所以想找一套两室一厅的。

在某租房网站上挑来挑去后,决定租X地的房子,于是和中介打好招呼,去看房。

结果到了地方,中介告诉我房子还在装修没法看,于是只好问了问详情,留了联系方式就走了。

没想到刚上地铁走了没两站,中介打电话告诉我房子可以看了,并且看中的几套中,有一套当天50分钟后就可以签约。

然而看中的几套中,有一套比这一套更喜欢的,所以告诉中介希望等等后面的房子。

结果就在这套房子可签约后的20分钟,房子被别人签走了,走了,了……

(该网站是线上签约,热门房子就看谁手速快)

虽然想要的并不是这套房子,但是痛定思痛,还是决定写个脚本实时监控想要的房子。

虽然我学的是Java,但是Java本身运行比较吃内存,不够轻量级,所以我把目光转向Python,一个我并不怎么会的语言

思路如下:

  1. 如果网站是以JavaScirpt发起请求调用JSON获取房源数据的话,我直接解析JSON就很容易得到房子是否可签约。通过JSON获取数据例子:Apple Inc.预约新机时显示各店是否有新机是这种模式,常见于Ajax异步刷新使用的方式。不过我找了一圈,发现该网站不是这种类型,可能是PHP在后端调用接口直接把成品页面拼装好了直接返回给浏览器的;
  2. 直接抓取整个页面,通过寻找相关Dom节点获取所需数据,根据数据判断房子是否可以预定;
  3. 通过阿里大于,当房子可以预定时就给自己的手机发一条短信提醒;
  4. 定期执行该方法,准备随时获得最新信息。

具体代码如下:

# -*- coding: utf-8 -*-
import httplib2.socks
import top.api
import sys
import time
from threading import Timer
from lxml import etree

reload(sys)
sys.setdefaultencoding('utf8')

# 阿里大于接口URL
alidayuUrl = 'gw.api.taobao.com'
# 阿里大于接口端口
alidayuPort = '80'
# 阿里大于短信模板(需要通过阿里大于服务器端验证)
alidayuTemplet = "SMS_12345678"
# 阿里大于签名(需要通过阿里大于服务器端验证)
alidayuSign = "贰浩次元"
# 阿里大于手机号
alidayuTel = "1**********"

class PageClass:
    # 获得页面
    def getPage(self, url):
        http = httplib2.Http()
        response,content = http.request(url,'GET')
        return content

# 打开某一文件获得地址列表
def getURL(filepath):
    input = open(filepath, 'r')
    cites = input.readlines()
    return cites

def zhaofangzi():
    # 1、打开文件
    urls = getURL('url.txt')
    # 2、循环所有地址
    for url in urls:
        print "url:",url
        # 3、实例化页面类并获取页面
        page = PageClass()
        content = page.getPage(url.strip())

        # 4、将页面转化成树
        tree = etree.HTML(content)
        # 5、解析树,找到所需元素,如预订按钮元素
        hyperlinks = tree.xpath(u'//div[@class="room_btns clearfix"]/a')
        # 6、循环元素(此处只可能有1个元素或0个元素,即仅执行一次或不执行)
        for index,hyperlink in enumerate(hyperlinks):
            if index > 1:
                break
            btnId = hyperlink.get('id')
            yudingFlg = False
            if index == 0:
                if btnId == 'zreserve':
                    yudingFlg = False
                else:
                    yudingFlg = True
            elif index == 1:
                if btnId == 'toYuding':
                    yudingFlg = True

            if yudingFlg == True:
                # 7、获取所需的房间名称
                title = tree.xpath(u'//div[@class="room_name"]/h2')[0].text.strip()
                print "title:",title
                # 8、实例化阿里大于短信发送请求并填入各种配置参数
                req = top.api.AlibabaAliqinFcSmsNumSendRequest(alidayuUrl, alidayuPort)
                req.set_app_info(top.appinfo('appkey', 'appsecret'))

                req.extend = ""
                req.sms_type = "normal"
                req.sms_free_sign_name = alidayuSign
                req.sms_param = "{housename:'"+title+"'}"
                req.rec_num = alidayuTel
                req.sms_template_code = alidayuTemplet
                try:
                    # 9、发送
                    resp = req.getResponse()
                    print (resp)
                except Exception, e:
                    print (e)
        print "end"
    return True

if __name__ == "__main__":
    while zhaofangzi():
        print 'now time:'+time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))+'. waiting for 15 min'
        t = Timer(60 * 15, zhaofangzi)
        t.start()
        t.join()

实际操作及运行中遇到的问题如下:

  1. 乱码问题。不同的机器上运行,有的抓取页面时会出乱码,有的不会出,这个比较头疼,会直接影响到运行结果,最终也没解决这个问题(反正房子已经订好了)
  2. 做这个脚本的时候实际没有监控到「XX:XX可预订」按钮的信息,实际上之后的某个版本做了,但仍然卡在乱码的问题上,最终还是放弃了。

一张效果图