数据分析学习之路——(四)爬虫初探—链家网城市新开楼盘房价

        做数据分析离不开数据集,一般来讲数据集来源分为两种:已有数据和待获取数据。已有数据指公司内部数据或者网络共享数据,存在数据库或者文件里,这种数据已经有固定的字段信息,在数据分析过程中可以直接对数据进行整理后分析。待获取数据就是网络上或者文本中需要去查找获取的关键数据,一般通过爬虫这种方式来获取。本文通过链家网房价数据的获取,来讲一讲python基础爬虫的实现过程,本数据也是第二篇文章(数据分析学习之路——(二)链家网部分城市新开楼盘分析)的数据来源。

        首先定义全局变量csv_file,表示数据存储的路径和格式;writter表示写文件的变量。由于这两个变量都要在后面定义的函数中用到,因此定义成全局变量。

global csv_file
csv_file = open("F:/pyfile/lianjiaData.csv", "wb+")   # 以二进制格式写入
global writter
writter=csv.writer(csv_file)

        再定义一个字典,目的是:我们需要查询十多个城市的数据,使用字典可以用一个for循环就可以获取到对应城市的数据。

global city_dic
city_dic={0:'北京', 1:'成都', 2:'重庆', 3:'大连', 4:'上海', 5:'广州', 6:'杭州', 7:'深圳', 8:'西安', 9:'武汉', 10:'长沙'}

        下面开始正式的爬虫定义:先定义一个爬虫类,初始化方法里面定义爬虫的url链接,跟上面定义的字典对应。save_cityhouse_data方法里,每一次for循环调用 ljspider = LJSpider(dic),则就是爬完一个城市的数据后继续下一个城市。将爬取的内容通过csv_file变量写入文件中,需要爬取的内容与title定义的保持一致。我在爬取之前看了一下,每个城市新楼盘最多没有超过100个页面,因此设置的爬取页面为1~100。

class LJSpider:
    def __init__(self,city_dic):
        if city_dic == 0:
            self.url = 'http://bj.fang.lianjia.com/loupan'
        elif city_dic == 1:
            self.url = 'http://cd.fang.lianjia.com/loupan'
        elif city_dic == 2:
            self.url = 'http://cq.fang.lianjia.com/loupan'
        elif city_dic == 3:
            self.url = 'http://dl.fang.lianjia.com/loupan'
        elif city_dic == 4:
            self.url = 'http://sh.fang.lianjia.com/loupan'
        elif city_dic == 5:
            self.url = 'http://gz.fang.lianjia.com/loupan'
        elif city_dic == 6:
            self.url = 'http://hz.fang.lianjia.com/loupan'
        elif city_dic  == 7:
            self.url = 'http://sz.fang.lianjia.com/loupan'
        elif city_dic == 8:
            self.url = 'http://xa.fang.lianjia.com/loupan'
        elif city_dic == 9:
            self.url = 'http://wh.fang.lianjia.com/loupan'
        elif city_dic == 10:
            self.url = 'http://cs.fang.lianjia.com/loupan'
def save_cityhouse_data(self):
    title=['城市','楼盘','地址','居室','建筑面积','均价']
    csv_file.write(codecs.BOM_UTF8)            # 设置文件格式
    writter.writerow(title)                    # 文件第一行设置为标题
    for dic in city_dic:                       # 按城市
        #print i,dic[i]
        ljspider = LJSpider(dic)
        ljspider.save_houseinfos(dic, 1, 100)  # 爬取的起始页面
    csv_file.close()

        每个城市的数据:

def save_houseinfos(self,citydic,start_page,end_eage):
    for i in range(start_page,end_eage+1):              # 每个城市爬取页数为endPage
        print city_dic[citydic],u':第',i,u'个page'
        self.save_page_houseinfo(citydic,i)

        将获取到的数据写入文件,get_compile_hosuinfo方法是将html页面通过正则匹配的方式获取关键信息,返回给house_info,再将这些信息一行一行写入文件里面。

def save_page_houseinfo(self,citydic,page_index):
    houseinfo=self.get_compile_hosuinfo(citydic,page_index)
    for house in houseinfo:
        #print house
        writter.writerow(house)

        简单python爬虫最核心的方法就是通过正则匹配来获取我们需要的数据,page_houseinfo是我们请求url返回的html数据,一般来讲很乱,因此要设定一定的规则来匹配到所有我们需要的数据。在正则表达式里,.*表示任意字符,?表示贪心匹配,也就是匹配所找到最大的字符如<li data-index=.*?info-panel可以理解为,只要能找到一个字符串以<li data-index=开头,以info-panel结尾则满足匹配规则。(.*?)就表示我们需要匹配的数据,通过re.findall找出来;re.compile是我们自定义的匹配规则,通常根据获取的不同内容设置,re.S是必须的,表示我们在全局都使用这个规则。如<a>123</a>,通过设置匹配规则<a>(.*?)</a>,最终findall能得到123。这是一种很基础很常见的查找html标签内容的方式。

        最终,我们爬取的数据放在house_info里面,列表的每一行表示一条数据,包含的信息为:城市,楼盘,地址,居室,建筑面积,均价。

def get_compile_hosuinfo(self,citydic,page_index):
    page_houseinfo = self.get_page_houseinfo(page_index)
    pattern=re.compile('<li data-index=.*?info-panel.*?<h2>.*?<a.*?>(.*?)</a>.*?</h2>.*?where.*?<span.*?>(.*?)</span>.*?</div>'
                       '.*?area">(.*?)<span>(.*?)</span>.*?</div>.*?col-2.*?<div class="average">(.*?)</div>',re.S)
    items=re.findall(pattern,page_houseinfo)   # 通过正则匹配查找
    house_info=[]
    for item in items:
        #print item[0].decode('utf-8'),item[1].decode('utf-8'),item[2].decode('utf-8'),item[3].decode('utf-8'),item[4]
        house_info.append([city_dic[citydic],item[0].decode('utf-8'),item[1].decode('utf-8'),item[2].decode('utf-8'),item[3].decode('utf-8'),item[4]])
    return house_info

        每个城市的楼盘房价列表第一页为默认页面,第二页之后请求格式为XXX/pg2,XXX/pg3...因此需要做处理。为了避免网页的反爬机制,需要设置headers伪装成浏览器。urllib2库是最佳的选择方案,通过respose.read()直接将请求的url页面获取到,也就是上面说的html数据。

def get_page_houseinfo(self,page_index):
    url = self.url
    if page_index> 1:
        url = self.url + '/pg' + str(page_index)
    headers={
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36',
        'Cookie' : 'select_city=110000; lianjia_uuid=4bc21c12-b147-4372-9509-3bd0ccc1dde8; _jzqy=1.1500723365.1500723365.1.jzqsr=baidu|jzq'
                   'ct=%E9%93%BE%E5%AE%B6.-; _jzqckmp=1; UM_distinctid=15d6a1545772c5-0a692dced95414-323f5c0f-100200-15d6a15457848f; logger_'
                   'session=a926f1e130bf37c7c7a72672e62c0f48; _gat=1; _gat_global=1; _gat_new_global=1; _gat_dianpu_agent=1; _gat_past=1; lj'
                   'ref=pc_sem_baidu_ppzq_x; Hm_lvt_9152f8221cb6243a53c83b956842be8a=1500723365,1500723382; Hm_lpvt_9152f8221cb6243a53c83b95'
                   '6842be8a=1500723382; _smt_uid=597338a5.214c69e5; _jzqa=1.2112972850353302800.1500723365.1500723365.1500723365.1; _jzqc=1;'
                   ' _jzqb=1.2.10.1500723365.1; CNZZDATA1256144455=1547075288-1500722599-%7C1500722599; CNZZDATA1254525948=222887115-150072262'
                   '3-%7C1500722623; CNZZDATA1255633284=1973387483-1500721424-%7C1500721424; CNZZDATA1255604082=422852891-1500721424-%7C150072'
                   '1424; _ga=GA1.2.1732214611.1500723367; _gid=GA1.2.429065113.1500723367; _qzja=1.941513563.1500723367163.1500723367163.1500'
                   '723367163.1500723384025.1500723386440.0.0.0.4.1; _qzjb=1.1500723367163.4.0.0.0; _qzjc=1; _qzjto=4.1.0; _jzqa=1.211297285035'
                   '3302800.1500723365.1500723365.1500723365.1; _jzqc=1; _jzqb=1.3.10.1500723365.1; lianjia_ssid=7c12a186-5f19-4434-be11-3e93428'
                   '9b062',
        'Referer':'http://bj.fang.lianjia.com/'
    }
    try:
        request=urllib2.Request(url,headers=headers)
        respose=urllib2.urlopen(request)
        return respose.read()
    except Exception,e:
        print e

        最终,获取到的csv格式的数据如下:

            231057_S8oU_3642529.png

      说明:上述的每一个方法都是定义在LJSpider类里面,可以在其他.py文件中调用该类里面的save_cityhouse_data方法即可,如:有另外一个py文件定义了AnaData类,使用方法如下。

class AnaData:
    def __init__(self):
        self.LJ=lianjiaAna.LJSpider(0)
anaData = AnaData()
anaData.LJ.save_cityhouse_data()   # 调用方法

        至此,我将基础爬虫过程一步步拆解并进行了说明,感觉还是很简单的。除此之外,还有很多数据获取方式也可以提一下,比如新浪微博,twitter有自己的接口api可以调用接口方法获取关键数据,有兴趣可以进行探索。此外还有很多爬虫框架很简洁实用,Scrapy就是一种很高效很实用的爬虫框架,我曾经用这个框架爬过豆瓣读书的数据,跟本文讲的思路不太一样,Scrapy框架获取关键信息主要用xpath做规则匹配。另外在setting.py文件可以设置一些参数来应对网页的反爬虫机制。

转载于:https://my.oschina.net/nekyo/blog/1548818

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值