zoukankan      html  css  js  c++  java
  • 安居客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

  • 相关阅读:
    HDU 4348 To the moon(可持久化线段树)
    HDU 5875 Function 大连网络赛 线段树
    HDU 5877 2016大连网络赛 Weak Pair(树状数组,线段树,动态开点,启发式合并,可持久化线段树)
    HDU 5876 大连网络赛 Sparse Graph
    HDU 5701 中位数计数 百度之星初赛
    CodeForces 708B Recover the String
    Java实现 蓝桥杯 算法提高 套正方形(暴力)
    ASP.NET生成验证码
    ASP.NET生成验证码
    ASP.NET生成验证码
  • 原文地址:https://www.cnblogs.com/byadmin/p/10836201.html
Copyright © 2011-2022 走看看