• 安居客scrapy房产信息爬取到数据可视化(上)-scrapy爬虫


    出发点

    想做一个地图热力图,发现安居客房产数据有我要的特性。emmm,那就尝试一次好了~

    老规矩,从爬虫,从拿到数据开始...

    scrapy的配置

    创建一个项目(在命令行下敲~):

    scrapy startproject anjuke

    这命令会建一个叫anjuke的文件夹,里面会有一些待你配置的文件

    创建一个spider:

    先进入创建的项目文件夹里

    cd anjuke
    scrapy genspider anju qd.anjuke.com

    这命令会建一个叫anju.py的文件,它就是刚刚创建的spider

    这时的文件夹结构应该是这样的:

    创建item

    item是保存爬取数据的容器,使用方法和字典类似~

    将item.py修改如下:

    import scrapy
    
    
    class AnjukeItem(scrapy.Item):
        # define the fields for your item here like:
        address = scrapy.Field()
        name = scrapy.Field()
        type_ = scrapy.Field()
        tags = scrapy.Field()
        price = scrapy.Field()
        area = scrapy.Field()
        city = scrapy.Field()

    至于item为什么是这样的可以看看这张图片:

    网页结构:

    上图就是下面代码用xpath获取divs的那部分,这跟网页的结构有关~

    浏览器直接按f12审查元素就是这个站的源码了(有的网站有些内容由js加载时,其实这里可能不是返回的源码)。

    上图列出了下面xpath代码的逻辑~~

    spider的逻辑(spider-anju.py的修改)

    # -*- coding: utf-8 -*-
    import scrapy
    from anjuke.items import AnjukeItem  # 使用item
    
    
    class AnjuSpider(scrapy.Spider):
        name = 'anju'  # spider的名称,影响不大
        allowed_domains = []  # 允许爬取的域,为空则是允许当前spider爬取所有的域名
        start_urls = ['https://cheng.fang.anjuke.com/', 'https://chang.fang.anjuke.com/', 'https://chi.fang.anjuke.com/',
                      'https://chu.fang.anjuke.com/', 'https://cy.fang.anjuke.com/', 'https://chao.fang.anjuke.com/',
                      'https://cx.fang.anjuke.com/', 'https://hf.fang.anjuke.com/', 'https://changd.fang.anjuke.com/',
                      'https://cg.fang.anjuke.com/', 'https://chongz.fang.anjuke.com/', 'https://chss.fang.anjuke.com/',
                      'https://ba.fang.anjuke.com/', ]
    
        def parse(self, response):
            divs = response.xpath('''//div[@class="key-list imglazyload"]/div''')  # 使用xpath从response中获取需要的html块
            city = response.xpath(
                '''//span[@class="city"]/text()''').extract_first()  # 我们匹配到的其实只有一个,获取第一个就行了,这里如果用.extract()其实会返回一个列表
            print(divs)
            for div in divs:
    
                item = AnjukeItem()  # 实例化item对象
                item['city'] = city  # 城市
                item['address'] = div.xpath('.//span[@class="list-map"]/text()').extract_first()  # 楼盘地址
                item['name'] = div.xpath('.//span[@class="items-name"]/text()').extract_first()  # 开发商名称
                try:
                    item['type_'] = div.xpath('.//a[@class="huxing"]/span/text()').extract()[:-1]  # 房子类型比如两房一厅这样子~
                except:
                    pass
    
                item['tags'] = div.xpath('.//span[@class="tag"]/text()').extract()  # 网站给楼盘定的标签~
    
                price = div.xpath('.//p[contains(@class,"price")]//text()').extract()  # 价格
                item['price'] = price
                try:
    
                    item['area'] = div.xpath('.//a[@class="huxing"]/span/text()').extract()[-1].replace('建筑面积:',
                                                                                                        '')  # 房子面积范围~
                except:
                    pass
                yield item
    
            next_ = response.xpath('//a[@class="next-page next-link"]/@href').extract_first()  # 获取下一页的链接
            print('-----next')
            print(next_)
            yield response.follow(url=next_, callback=self.parse)  # 将下一页的链接加入爬取队列~~
    上面的start_urls的链接是另外爬的,链接这里:安居客,全部链接爬下来了,这里为了篇幅就列出几个就好了。

    上面代码item的结构:

    为什么我要将价格保存为list呢?

    因为网站这里给的价格有最低价、总价、均价,我只想要均价,保留价格的类型后面用时分类方便~

    然后是将数据保存到Mongodb,需要对pipelines.py进行一些修改:

    import pymongo
    
    
    class TextPipeline(object):  #这个自定义的类是打算用来处理item数据的,后来发现爬到的item数据好像还挺干净就没有写逻辑了~
        def process_item(self, item, spider):
            print(item)
            return item
    
    
    class MongoPipeline(object):
        def __init__(self,mongo_uri,mongo_db):  
            self.mongo_uri = mongo_uri
            self.mongo_db = mongo_db
        @classmethod
        def from_crawler(cls,crawler):  #类方法,用于从settins.py中获取在那边设置的MONGO_URI和MONGO_DB
            return cls(
                mongo_uri = crawler.settings.get('MONGO_URI'),
                mongo_db = crawler.settings.get('MONGO_DB')
                )
        def open_spider(self,spider):  #当spider开启时这个方法被调用,这里用来连接数据库
            self.client = pymongo.MongoClient(self.mongo_uri)
            self.db = self.client[self.mongo_db]
        def process_item(self,item,spider):  #实现了item数据插入到数据库,自动创建与项目名同名,spider同名的表,数据都保存在里面
            name = item.__class__.__name__
            self.db[name].insert(dict(item))
            return item
        def close_spider(self,spider):  #当spider关闭时这个方法被调用
            self.client.close()

    最后就是应付反爬的一些操作咯:

    这些都在settings.py设置:

    首先,站点对user-agent有检查,发现是爬虫头直接跳转到验证码页面...

    emmm,伪造浏览器请求头就好了:

    在settings.py加(记得import random):

    USER_AGENT_LIST=[  #各浏览器的请求头
    'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36'
        "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",
        "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; 360SE)",
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
        "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
        "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.0 Safari/536.3",
        "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24",
        "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24"
    ]
    USER_AGENT = random.choice(USER_AGENT_LIST)  #随机从上面列表中选取请求头,伪造请求头~

    还有就是禁用cookie,网站会通过用户的Cookie信息对用户进行识别与分析,所以要防止目标网站识别我们的会话信息:

    COOKIES_ENABLED = False  #关闭cookie

    最后就是访问频率的控制,站点对一个ip的访问频率也有监测,一直很访问快的话,也是会跳到人机验证页面~:

    DOWNLOAD_DELAY = random.choice([1,2])  #访问延时,随机选1或2~

     最后,看看爬到的部分数据(去重之后大概有7w条左右)~

    对爬取到的数据的想法:

    1、给出的房源少,房源最多的城市也就2000左右,我想这很大程度并不能代表各个城市的平均水平。。

    2、爬到的数据也不一定对,可能房地产或网站这边故意压低一点房价,以消费者吸引目光~

    3、其实最好的办法是以公司的合作来取到数据,有这样官方的数据就不用自己去爬了,而且也最准确、最真实啊(有大腿抱得话真的舒服)~

    End

  • 相关阅读:
    MSP430程序库<十四>DMA程序库
    MSP430程序库<十三>硬件乘法器使用
    MSP430程序库<十五>Flash控制器
    MSP430程序库<九>数码管显示
    [debug] 调试小结
    SourceInsight Shortcuts
    git commands
    Linux常用命令
    [转] 宏点滴
    Linux 开发
  • 原文地址:https://www.cnblogs.com/byadmin/p/10836201.html
Copyright © 2020-2023  润新知