Scrapy实战篇(一)之爬取链家网成交房源数据(上)

今天,我们就以链家网南京地区为例,来学习爬取链家网的成交房源数据。

这里推荐使用火狐浏览器,并且安装firebug和firepath两款插件,你会发现,这两款插件会给我们后续的数据提取带来很大的方便。

首先创建一个名称为lianjia的项目。

需求分析

爬取数据的第一步当然是确定我们的需求,大方向就是我们想拿到南京地区的房源成交信息,但是具体的细节信息,我们需要从网页来看,,我们直接在浏览器中输入以下的网址https://nj.lianjia.com/chengjiao/,会显示南京地区的成交的房源信息,包括名称,房屋简介,地理位置,成交日期,成交价格,成交单价等详细信息,这样我们就确定了我们想要的信息,我们在items.py文件中定义如下的一些字段。

#items.py
from scrapy import Item,Field

class LianjiaItem(Item):
    region = Field()      #行政区域
    href = Field()        #房源链接
    name = Field()        #房源名称
    style = Field()       #房源结构
    area = Field()           #小区
    orientation = Field()    #朝向
    decoration = Field()     #装修
    elevator = Field()       #电梯
    floor = Field()          #楼层高度
    build_year = Field()     #建造时间
    sign_time = Field()      #签约时间
    unit_price = Field()     #每平米单价
    total_price = Field()    #总价
    fangchan_class = Field()   #房产类型
    school = Field()         #周边学校
    subway = Field()         #周边地铁

请注意,以上的信息,并不是每一套房源都有的,比如下面的地铁,学校,很多房源都是没有的。

问题

  • 你会发现一个问题,每一个页面会呈现30条的房源信息,最下面一共可以显示100页,总计最多也就是3000条信息,南京地区的成交房源信息肯定不止这区区的3000条,那么如果直接从这个页面通过翻页来获取数据,最多只能获取到3000条信息,所以我们这里需要转思路。

  • 还是这个页面,可以看到页面上部列出了南京地区的行政区,我们随意选择一个,会发现,新的页面依然是每一页30条,共计100页,但是我们有11个行政区,那么其数量也是翻了好几倍了。

  • 这个时候,你可能还是不满足,我们想办法看一下是不是还可以进一步向下划分,没错那就是小区,我们把房源从11个行政区划分到小区上,以小区为单位,每一个小区上面还有房源数据,这样的话,我们的信息可以说比较全面了,当然了,我们需要做的工作也是要翻倍的。

总结

这里我们通过分析,总结出了如下的思路:

  • 以行政区为单位,先获取南京地区所有的小区信息
  • 以小区为单位,获取每一个小区里面的房源数据
  • 最后就是获取具体的每一个房源的信息。

具体实施

现在明确了我们的思路,下面就开始具体的实施。

编写spider.py文件

from scrapy import Spider,Request
import re
from lxml import etree
import json
from urllib.parse import quote
from lianjia.items import LianjiaItem

class Lianjia_spider(Spider):
    name = 'lianjia'
    allowed_domains = ['nj.lianjia.com']
    regions = {'gulou':'鼓楼',
               'jianye':'建邺',
               'qinhuai':'秦淮',
               'xuanwu':'玄武',
               'yuhuatai':'雨花台',
               'qixia':'栖霞',
               'jiangning':'江宁',
               'liuhe':'六合',
               'pukou':'浦口',
               'lishui':'涟水',
               'gaochun':'高淳'
    }

    def start_requests(self):
        for region in list(self.regions.keys()):
            url = "https://nj.lianjia.com/xiaoqu/" + region + "/"
            yield Request(url=url, callback=self.parse, meta={'region':region}) #用来获取页码

    def parse(self, response):
        region = response.meta['region']
        selector = etree.HTML(response.text)
        sel = selector.xpath("//div[@class='page-box house-lst-page-box']/@page-data")[0]  # 返回的是字符串字典
        sel = json.loads(sel)  # 转化为字典
        total_pages = sel.get("totalPage")

        for i in range(int(total_pages)):
            url_page = "https://nj.lianjia.com/xiaoqu/{}/pg{}/".format(region, str(i + 1))
            yield Request(url=url_page, callback=self.parse_xiaoqu, meta={'region':region})

    def parse_xiaoqu(self,response):
        selector = etree.HTML(response.text)
        xiaoqu_list = selector.xpath('//ul[@class="listContent"]//li//div[@class="title"]/a/text()')
        for xq_name in xiaoqu_list:
            url = "https://nj.lianjia.com/chengjiao/rs" + quote(xq_name) + "/"
            yield Request(url=url, callback=self.parse_chengjiao, meta={'xq_name':xq_name, 
                                    'region':response.meta['region']})

    def parse_chengjiao(self,response):
        xq_name = response.meta['xq_name']
        selector = etree.HTML(response.text)
        content = selector.xpath("//div[@class='page-box house-lst-page-box']")  #有可能为空
        total_pages = 0
        if len(content):
            page_data = json.loads(content[0].xpath('./@page-data')[0])
            total_pages = page_data.get("totalPage")  # 获取总的页面数量
        for i in range(int(total_pages)):
            url_page = "https://nj.lianjia.com/chengjiao/pg{}rs{}/".format(str(i+1), quote(xq_name))
            yield Request(url=url_page, callback=self.parse_content, meta={'region': response.meta['region']})

    def parse_content(self,response):
        selector = etree.HTML(response.text)
        cj_list = selector.xpath("//ul[@class='listContent']/li")


        for cj in cj_list:
            item = LianjiaItem()
            item['region'] = self.regions.get(response.meta['region'])
            href = cj.xpath('./a/@href')  
            if not len(href):
                continue
            item['href'] = href[0]

            content = cj.xpath('.//div[@class="title"]/a/text()') 
            if len(content):
                content = content[0].split()  # 按照空格分割成一个列表
                item['name'] = content[0]
                item['style'] = content[1]
                item['area'] = content[2]

            content = cj.xpath('.//div[@class="houseInfo"]/text()')
            if len(content):
                content = content[0].split('|')
                item['orientation'] = content[0]
                item['decoration'] = content[1]
                if len(content) == 3:
                    item['elevator'] = content[2]
                else:
                    item['elevator'] = '无'

            content = cj.xpath('.//div[@class="positionInfo"]/text()')
            if len(content):
                content = content[0].split()
                item['floor'] = content[0]
                if len(content) == 2:
                    item['build_year'] = content[1]
                else:
                    item['build_year'] = '无'

            content = cj.xpath('.//div[@class="dealDate"]/text()')
            if len(content):
                item['sign_time'] = content[0]

            content = cj.xpath('.//div[@class="totalPrice"]/span/text()')
            if len(content):
                item['total_price'] = content[0]

            content = cj.xpath('.//div[@class="unitPrice"]/span/text()')
            if len(content):
                item['unit_price'] = content[0]

            content = cj.xpath('.//span[@class="dealHouseTxt"]/span/text()')  
            if len(content):
                for i in content:
                    if i.find("房屋满") != -1:  # 找到了返回的是非-1得数,找不到的返回的是-1
                        item['fangchan_class'] = i
                    elif i.find("号线") != -1:
                        item['subway'] = i
                    elif i.find("学") != -1:
                        item['school'] = i
            yield item

我们对上面关键的地方进行解释:

  • start_requests
    这个就是我们以行政区为单位,目的是爬取每一个行政区的小区列表。
  • parse
    对行政区返回的response进行解析,我们目的是拿到这个大的行政区,包含多少个页面,其中的
    total_pages就是具体的页面数,接下来就是按照页码请求每一个页面。
  • parse_xiaoqu
    上面返回了每一个页面的信息,这个时候我们就把当前页面的小区列表拿到,而后,在针对小区列表,每一个小区进行一次请求。
  • parse_chengjiao
    解析小区的页面数,上面说到了,我们请求了每一个小区数据,这个小区肯定不止包含一页的数据,那么我们这个方法就是将这个小区包含的页面数抽取出来,而后针对每一个页面进行请求
  • parse_content
    这个方法就是解析具体的页面了,可以看到,这个方法里面包含了非常多的条件判断,这是因为,我们之前定义的item字段里面的信息,并不是每一个小区都有的,就是说,我们要的信息他不是一个规规矩矩的信息,很多的房源没有提供相关的信息,比如地铁,周边学校等等的信息,我们这里就是如果有这个信息,我们就把它提取出来,如果没有的话,我们就给他自定义一个内容
    。最后将item提交给item pipeline进行后续的处理。

由于这一节的信息比较多,我们就把它分为两个小节,在下一节中,我们对拿到的数据进行后续的处理。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容