巧用web机器人搜索廉价二手房

1. 问题

我需要一套二室一厅,价格在40万左右的,位于上海某几个区(例如徐汇,闵行区)的二手房。我理想中的房子当然需要满足很多条件,例如它必须是两室都朝南的房子,它的均价必须低于7000元每平方米,等等。

通常我使用上海热线的二手房网(http://secondhand.online.sh.cn/)来查找最新的二手房信息。

但是每天跟踪网站的最新二手房信息太累人了。二手房网每天都要添加很多最新信息,为了识别出符合我的条件的房子,我必须把所有这些信息都看一遍。整个过程非常浪费时间。

原因在于:

1. 网站只会在首页显示最新加入的一些二手房的*概要*信息。而我为了作出自己的判断,光是看概要信息是不够的,我必须看详细信息。而这就意味着我必须点击概要信息中的名为“详细”的超链接来下载详细信息的页面。

2. 并不是所有信息都是放在一个页面上的。事实上,上海热线的二手房网的信息是分页显示的,每个页面大概只显示10条信息。如果我需要看所有的信息的话,我需要看大概500-3000条信息左右(信息的多少和搜索条件是否严格,搜索的区域的大小有关系)。

上述1,2点的意思就是,即使我只需要看500条信息,我也需要看550个页面:

500/10(概要信息页面)+500*1(每条信息的详细页面)=550

每个页面载入的时间是10秒(实际取样的结果),我阅读每个页面的时间是25秒(我的阅读速度是非常快的了)。

550*(10+25)=19250秒=320分钟=5小时。

也就是说,光是阅读信息我就需要花5小时的时间。事实上,我还没有考虑对信息进行分析(例如列出均价最低的10处房产)的时间呢,这远比阅读更花时间。

2. 问题的本质

由于现在很多信息都放在网上了,类似的问题很常见。例如招聘,证券等等,都有同样的问题。这个问题就是,如何高效率地从internet上获得数据并进行分析。

3.一个方案

我看了一些国内的相关文章,这些文章的方案都是基于IE的自动化的。通常使用VB语言加上WebBrowser控件。

这种方案最主要的缺点是由于WebBrowser对很多数据操作进行了封装,使得本来很简单的操作变得麻烦无比(我猜原因是因为微软设计WebBrowser的目的是自动化IE的操作)。例如取得当前页面这样一个操作,如果使用WebBrowser开发的话竟然需要分取得当前页面,在某个事件中获得取得页面成功两个进程。为了使这两个进程通信又需要很多额外的工作。

我的方案是使用python开发一个脚本,因为python的库支持比较完备,这样还可以获得跨平台的额外好处。我使用结构化的设计,因为使用web机器人取得数据这样的事情本身就是结构化的。我将和具体网站相关的操作都封装在某几个函数内,这意味着该脚本如果经过适当的改写,还能有其他应用。也就是,这个脚本不仅仅是用于上海热线二手房网的,也不仅仅是先于搜索二手房的。

在写这个脚本之前,我已经有一些边写web机器人的经验,使用的语言包括VB,Java,Python等等。我认为目前我写的这个web机器人是比较成熟的。

这个方案的要点是这样的,首先向二手房网提交条件,然后获得分页搜索结果,从第一页中读取各信息条款(),读取共有多少页面等等必要的信息(这些信息的读取同样需要硬编码起始标志和结束标志)等等。然后根据这些信息模拟翻页,点击“详细”链接等动作。这些动作无非就是http标准中的get,post动作而已。

上述方案中的某些地方需要硬编码,必要的话需要分析浏览器客户端脚本(例如JavaScript):

*各信息条款的起始标志和结束标志

*当前页面计数的起始标志和结束标志

*页面总数的起始标志和结束标志

*翻页动作中的超链接地址

*点击“详细”超链接中的超链接地址

获得的数据我都打印在屏幕上,这些数据使用逗号分割,如果希望把数据导入到文件中,可以使用管道机制。

例如,假设我写的脚本是house.py,你希望把house.py的数据导入到文件house.csv中去,你可以输入这样的命令:

python house.py > house.csv

接下来你可以就可以分析house.csv了。我通常用支持正则表达式的编辑器去掉house.csv中的一些格式化字符,再用excel进行数据分析。

4. 具体实现以及代码

具体实现中还碰到一些小问题。例如为了支持中文,我必须再脚本的开头加上“# -*- coding: mbcs -*-”这一行。我上网需要使用指定的代理服务器,所以我使用urllib2库而不是urllib库。这些问题都已经在源代码中说明了。

下面就是源代码:





config_using_proxy=0


config_httpproxy=""


config_username=""


config_password=""


config_szqx=""


config_fx_room=""


config_fx_hall=""


config_jg_min=""


config_jg_max=""


config_type=""


config_djrq=""


config_tbl_begin_str=""


config_tbl_end_str=""





config_post_data={"":config_szqx,"":config_fx_room,"":config_fx_hall,"":config_jg_min,"":config_jg_max,"":config_type,"":config_djrq,"":"","":"","":""}






 string  *
 sys


 ():
    sys.stdout.write('')


 ():
    sys.stdout.write(""+"")
    sys.stdout.write(""+"")
    sys.stdout.write(""+"")
    sys.stdout.write(""+"")
    sys.stdout.write(""+"")
    sys.stdout.write(""+"")
    sys.stdout.write(""+"")
    sys.stdout.write(""+"")
    sys.stdout.write(""+"")
    sys.stdout.write(""+"")
    sys.stdout.write(""+"")
    sys.stdout.write(""+"")
    sys.stdout.write(""+"")
    sys.stdout.write(""+"")
    sys.stdout.write(""+"")
    sys.stdout.write(""+"")
    sys.stdout.write(""+"")
    sys.stdout.write(""+"")
    sys.stdout.write(""+"")
    sys.stdout.write(""+"")
    sys.stdout.write(""+"")
    sys.stdout.write("")


 (str):
    sys.stdout.write(str+"")





 (s):
    no_begin=find(s,"")
     no_begin==-1:
         0

    no_begin=rfind(s,"",0,no_begin)
    no_begin+=len("")
    no_end=find(s,"",no_begin)
     no_end==-1:
         0

     no_begin>no_end:
         0
     atoi(s[no_begin:no_end])


 (instr4,tag):
    tag_begin=find(instr4,""+tag)
     tag_begin==-1:
         instr4

    tag_begin=find(instr4,"")
     tag_begin==-1:
         instr4
    tag_begin+=1

    tag_end=find(instr4,""+tag+"",tag_begin)
     tag_end==-1:
         instr4

     instr4[tag_begin:tag_end]

 (str):
     strip(replace(replace(replace(replace(str,"",""),'',''),'',''),'','')) 

 (instr3,keyword):

    
    

    data_begin=find(instr3,keyword)
     data_begin==-1:
         ""
    
    data_begin=find(instr3,"",data_begin)
     data_begin==-1:
         ""

    data_begin=find(instr3,"",data_begin)
     data_begin==-1:
         ""
    data_begin=data_begin+1

    data_end=find(instr3,"",data_begin)
     data_end==-1:
         ""

     data_begin>data_end:
         ""
    
    
     filter_rubbish_data(instr3[data_begin:data_end])


 (instr2):
    dump_one_field(get_one_detailed_data(instr2,""))
    dump_one_field(get_one_detailed_data(instr2,""))
    dump_one_field(get_one_detailed_data(instr2,""))
    dump_one_field(get_one_detailed_data(instr2,""))
    dump_one_field(get_one_detailed_data(instr2,""))
    
    tmpstr=get_one_detailed_data(instr2,"")
    tmppos=find(tmpstr,"")
     tmpstr<>-1:
        tmpstr=strip(tmpstr[:tmppos])
    dump_one_field(tmpstr)
    dump_one_field(get_one_detailed_data(instr2,""))
    dump_one_field(get_one_detailed_data(instr2,""))
    dump_one_field(get_one_detailed_data(instr2,""))
    dump_one_field(get_one_detailed_data(instr2,""))
    dump_one_field(get_one_detailed_data(instr2,""))
    dump_one_field(get_one_detailed_data(instr2,""))
    dump_one_field(get_data_in_one_tag(get_one_detailed_data(instr2,""),""))
    dump_one_field(get_data_in_one_tag(get_one_detailed_data(instr2,""),""))


 (instr,tbl_begin_str,tbl_end_str):
    
    idx=find(instr,tbl_begin_str)
     idx==-1:
        
    idx=find(instr,"",idx)
     idx==-1:
        
    table_begin=idx
    

    
    idx=find(instr,tbl_end_str,table_begin)
    
     idx==-1:
        
    idx=rfind(instr,"",table_begin,idx)
     idx==-1:
        
    table_end=idx+len("")
    

    
    tr_idx=table_begin
     tr_idx<table_end:
        
        tr_idx=find(instr,"",tr_idx)
         tr_idx==-1:
            
        tr_idx=find(instr,"",tr_idx)
         tr_idx==-1:
            
        tr_begin=tr_idx+1

        
        tr_idx=find(instr,"",tr_begin)
         tr_idx==-1:
            
        tr_end=tr_idx
        


        
        td_idx=tr_begin
        is_really_a_row_dumped=0
         td_idx<tr_end:
            
            td_idx=find(instr,"",td_idx)
            
             td_idx==-1:
                
            td_idx=find(instr,"",td_idx)
            
             td_idx==-1:
                
            tddata_begin=td_idx+1

            
            td_idx=find(instr,"",td_idx)
            
             td_idx==-1:
                
            tddata_end=td_idx

             tddata_begin>tddata_end:
                

             tddata_end>tr_end:
                

             tddata_end>table_end:
                

            tddata=filter_rubbish_data(instr[tddata_begin:tddata_end])

            
            href_begin=find(tddata,"")
             href_begin==-1:
                dump_one_field(tddata)
                


            href_begin=href_begin+len("")

            href_end=find(tddata,"",href_begin)
             href_end==-1:
                

            view_url=""+tddata[href_begin:href_end]
            
            

            view_result=urllib2.urlopen(view_url)
            view_data=view_result.read()
            
            get_detailed_data(view_data)
            is_really_a_row_dumped=1

         is_really_a_row_dumped:  
            dump_row_end()



 ():
    httpproxy=config_httpproxy
    username=config_username
    password=config_password
    httpproxystring='' +  username + '' + password + '' + httpproxy

    
    proxy_support=urllib2.ProxyHandler({"":httpproxystring})

    authinfo=urllib2.HTTPBasicAuthHandler()
    opener = urllib2.build_opener(proxy_support, authinfo,urllib2.HTTPHandler)

    
    urllib2.install_opener(opener)


 __name__=="":
    
     urllib2
     urllib

    
     config_using_proxy:
        install_proxy()

    f = urllib2.urlopen("",urllib.urlencode(config_post_data))
    
    s=f.read()
    

    
    
    
    

    
    dump_table_begin()
    
    get_data(s,config_tbl_begin_str,config_tbl_end_str)

    
    last_page=get_last_page_number(s)
    
     i  range(2,last_page):
        config_post_data['']=str(i)
        f = urllib2.urlopen("",urllib.urlencode(config_post_data))
        s=f.read()
        get_data(s,config_tbl_begin_str,config_tbl_end_str)

    
    

    

发布了127 篇原创文章 · 获赞 43 · 访问量 116万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览