欢迎访问 生活随笔!

生活随笔

当前位置: 首页 >

基于 Scrapy-Redis 全国房源信息抓取系统

发布时间:2024/3/24 83 豆豆
生活随笔 收集整理的这篇文章主要介绍了 基于 Scrapy-Redis 全国房源信息抓取系统 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

基于 Scrapy-Redis 全国房源信息抓取系统

摘要

近几年,人们对房源信息的关注度越来越高。如何对全国房源信息进行灵活高效的采集并存储,对全国房源信息的分析工作起到重要作用。文中在分析房天下站点特征结构的基础上采用 Python 开源框架 Scrapy 搭配 Redis 数据库,设计实现了一套抓取速度快、扩展性高的分布式爬虫系统,获取的数据具有良好的实时性和准确性,为后续分析工作提供了有力的数据支撑。
关键字 :Scrapy 框架;Scrapy-Redis;分布式爬虫;可视化

前言

爬虫技术,无论是在学术领域,还是在工程领域,都扮演者非常重要的角色。相比于其他技术,爬虫技术虽然在实现上比较简单,没有那么多深奥的技术难点,但想要构建一套稳定、高效、自动化的爬虫框架,也并不是一件容易的事情。本文介绍了一种分布式爬虫框架的实现方法和工作原理。[1−2]

结构设计

scrapy 是一个 python 爬虫框架,爬取的效率极高,具有高度的定制性,但是不支持分布式。而 scrapy-redis 是一套基于 redis 库,运行在 scrapy 框架之上的组件,可以让scapy 支持分布式策略。[3]
Salverr 端共享 Master 端 redis 数据库里的 item 队列、请求队列和请求指纹集合。
选择 redis 数据库的原因:[4]

  • redis支持主从同步,而且数据都是缓存 在内存中的,所以基于redis的分布式爬
    虫,对请求和数据的高频率读取效率都非常高
  • scrapy-redis和scrapy的关系就像电脑和固态硬盘一样,是电脑中的一个插件,能
    让电脑更快的运行
  • scrapy是一个爬虫框架,scrapy-redis则是这个框架上可以选择的插件,它可以让
    爬虫跑得更快。

Scrapy框架调度器

图1 Scrapy 框架

Scrapy框架解释

如图1所示未Scrapy框架,该框架解释[5]如下:

  • 从优先级队列中获取requests对象,交给engine;
  • engine将requests对此昂交给下载器下载,期间会通过downloadmiddleware的process_request方法;
  • 下载器完成下载,获得response对象,将该对象交给engine,期间会经过downloadmiddleware的process_response()方法;
  • engine将获得的response对象交给spider进行解析,期间会经过spidermiddleware的process_spider_input()方法;
  • spider解析下载器下载下来的response,返回item或links(url);
  • item或者link经过spidermiddleware的process_spider_out()方法,交给engine;
  • engine将item交给item pipeline,将links交给调度器;
  • 在调度器中,先将requests对象利用scrapy内置的指纹函数生成一个指纹;
  • 如果requests对象中的don’t filter参数设置为False,并且该requests对象的指纹不在信息指纹的队列中,那么就把该requests对象放到优先级队列中。
  • 中间件

    spider与engine之间(爬虫中间件)
    介于scrapy引擎和爬虫之间的框架,主要工作就是处理爬虫的响应输入和请求的输
    出。
    download与engine之间(下载器中间件)
    介于scrapy引擎和下载器之间的框架,主要是处理scrapy引擎与下载器之间的请求和响应。
    scrapy框架中的middleware.py

    • Scrapy Middleware有以下几个函数被管理
  • process_spider_input:接收一个response对象并处理;
  • process_spider_exception:spider出现异常时被调用;
  • process_spider_output:当spider处理response返回result时,就会调用该
    方法;
  • process_spider_requests:当spider发出请求时,被调用;
    • Download Middleware有以下几个函数被管理
  • process_requests:requests通过下载中间件的时候,该方法被调用,这里可
    以通过设置代理,设置request.meta[‘proxy’]就OK了;
  • process_response:下载结果经过中间件的时候会被这个方法解惑来进行处
    理;
    3… process_exception:下载过程中出现异常的时候会被调用。
  • scrapy的优缺点

    优点:scrapy 是异步的,写middleware,方便写一些统一的过滤器。
    缺点:基于python的爬虫框架,扩展性比较差,基于twisted框架,运行中的exception是不会干掉reactor,并且异步框架出错后是不会停掉其他任务的,数据出错后难以察觉。

    Scrapy-Redis框架

    图 2 Scrapy-Redis 框架
    如图2所示,可以发现,scrapy-redis在scrapy的架构上增加了redis,与scrapy相差无几。本质的区别就是,将scrapy的内置的去重的队列和待抓取的request队列换成了redis的集合。此改动就使scrapy-redis具备分布式特性。

    Scrapy-Redis组件

    Scrapy-redis提供了下面四种组件(components):(四种组件意味着这四个模块都要做相应的修改)。

    Scheduler组件

    Scrapy改造了python本来的collection.deque(双向队列)形成了自己的Scrapy queue,但是Scrapy多个spider不能共享待爬取队列Scrapy queue, 即Scrapy本身不支持爬虫分布式,scrapy-redis 的解决是把这个Scrapy queue换成redis数据库(也是指redis队列),从同一个redis-server存放要爬取的request,便能让多个spider去同一个数据库里读取。
    Scrapy中跟“待爬队列”直接相关的就是调度器Scheduler,它负责对新的request进行入列操作(加入Scrapy queue),取出下一个要爬取的request(从Scrapy queue中取出)等操作。它把待爬队列按照优先级建立了一个字典结构,然后根据request中的优先级,来决定该入哪个队列,出列时则按优先级较小的优先出列。为了管理这个比较高级的队列字典,Scheduler需要提供一系列的方法。但是原来的Scheduler已经无法使用,所以使用Scrapyredis的scheduler组件。

    Duplication Filter组件

    Scrapy中用集合实现这个request去重功能,Scrapy中把已经发送的request指纹放入到一个集合中,把下一个request的指纹拿到集合中比对,如果该指纹存在于集合中,说明这个request发送过了,如果没有则继续操作。在scrapy-redis中去重是由Duplication Filter组件来实现的,它通过redis的set 不重复的特性,巧妙的实现了Duplication Filter去重。scrapy-redis调度器从引擎接受request,将request的指纹存⼊redis的set检查是否重复,并将不重复的request push写⼊redis的 request queue。引擎请求request(Spider发出的)时,调度器从redis的request queue队列⾥里根据优先级pop 出⼀个request 返回给引擎,引擎将此request发给spider处理。

    Item Pipeline组件

    引擎将(Spider返回的)爬取到的Item给Item Pipeline,scrapy-redis 的Item Pipeline将爬取到的 Item 存⼊redis的 items queue。修改过Item Pipeline可以很方便的根据 key 从 items queue 提取item,从⽽实现itemsprocesses集群。

    Base Spider组件

    不再使用scrapy原有的Spider类,重写的RedisSpider继承了Spider和RedisMixin这两个类,RedisMixin是用来从redis读取url的类。当我们生成一个Spider继承RedisSpider时,调用setup_redis函数,这个函数会去连接redis数据库,然后会设置signals(信号):

  • 当spider空闲时候的signal,会调用spider_idle函数,这个函数调用schedule_next_request函数,保证spider是一直活着的状态,并且抛出DontCloseSpider异常。
  • 当抓到一个item时的signal,会调用item_scraped函数,这个函数会调用schedule_next_request函数,获取下一个request。
  • Scrapy-Redis分布式策略


    图 3 Scrapy-Redis 分布式策略
    Scrapy-Redis分布式爬虫分为Master端和Salverr端:

  • Master端(核心服务器) :使用 Windows 10,搭建一个Redis数据库,不负责爬取,只负责url指纹判重、Request的分配,以及数据的存储。
  • Salverr端(爬虫程序执行端) :Ubuntu 16.04,负责执行爬虫程序,运行过程中提交
    新的Request给Master。
  • 如图3首先Salverr端从Master端拿任务(Request、url)进行数据抓取,Salverr抓取数据的同时,产生新任务的Request便提交给 Master 处理。
    Master端只有一个Redis数据库,负责将未处理的Request去重和任务分配,将处理后的Request加入待爬队列,并且存储爬取的数据。[6]

    爬虫设计

    爬行策略设计

    本文在设计全国房源信息爬虫系统时,以房天下网作为爬取对象,充分考虑了房天下站点URL的结构特点,设计了一种最佳的爬行策略,能够引导爬虫抓取房天下新房与二手房信息。

    图 4 种子网页
    爬虫根据预先设定的一个种子 URL,如图 4 所示, 直接访问并下载页面,经页面解析器去掉页面上的 HTML 标签得到页面内容,通过中国各省份与城市列表构造新的 URL 放入Redis Queue 队列,期间通过去重和排序操作。然后将筛选通过的 URL 加入待爬队列进而供爬虫抽取进行下一步的下载和页面解析操作。此过程将一直循环进行,直到列表为空,整个抓取过程结束。

    确定抓取对象

    房天下房源信息页面中包含多种内容,通过定义 Item 来选择需要抓取的对象信息。本文定义了两种数据的字段信息,如图 5 和表 1 所示为待抓取新房信息,图 6 和表 2 为待抓取二手房信息。

    图 5 新房详情页面
    表 1 NewHouse


    图 6 二手房详情页面
    表 2 ESFHouse

    页面爬取和页面解析

    在房源信息首页和详情页面的解析中,本文主要使用 Xpath 进行解析。XPath 全称是XML Path Language,它既可以用来解析 XML,也可以用来解析 HTML。同 Beautiful Soup 一样,在 XPath 中提供了非常简洁的节点选择的方法,Beautiful Soup 主要是通过“.”的方式来进行子节点或者子孙节点的选择,而在 XPath 中则主要通过“/”的方式来选择节点。除此之外,在 XPath 中还提供了大量的内置函数来处理各个数据之间的匹配关系。如表 3 为常见的节点匹配规则。
    表 3 Xpah 常见的节点匹配规则

    房天下首页解析

    #代码1 :房天下首页解析 def parse(self, response):trs= response.xpath("//div[@class= 'outCont']//tr")province= Nonefor tr in trs:tds= tr.xpath(".//td[not(@class)]")province_td= tds[0]province_text= province_td.xpath(".//text()").get()province_text= re.sub(r"\s","",province_text)if province_text:province= province_text# 过滤海外城市if province== '其它':continuecity_td= tds[1]city_links= city_td.xpath(".//a")for city_link in city_links:city= city_link.xpath(".//text()").get()city_url= city_link.xpath(".//@href").get()# 构建新房url链接url_module= city_url.split(".") scheme1= url_module[0] # 例:http://cdscheme2= url_module[1] #例:fangscheme3= url_module[2] #例:comnewhouse_url= scheme1+ "."+ "newhouse."+ scheme2+ "."+ scheme3+ "house/s/"# 构建二手房url链接esf_url= scheme1+ "."+ "esf."+ scheme2+ "."+ scheme3yield scrapy.Request(url=newhouse_url, callback=self.parse_newhouse,meta={"info":(province,city)})yield scrapy.Request(url=esf_url, callback=self.parse_esf, meta={"info":(province, city)})

    如代码1,处理完首页后,使用yeild返回请求返回Request分别指向两个url,及NewHoues(新房页面)和ESFHouse(二手房页面),基于当前城市使用callback回调函数分别执行新房与二手房页面的解析工作。

    新房页面解析

    #代码2 新房页面解析 def parse_newhouse(self,response):province,city= response.meta.get('info')lis= response.xpath("//div[contains(@class,'nl_con')]/ul/li")for li in lis:name_text= li.xpath(".//div[@class='nlcd_name']/a/text()").get()if name_text is not None:name= name_text.strip()house_type_list= li.xpath(".//div[contains(@class,'house_type')]/a/text()").getall()house_type_list= list(map(lambda x: re.sub(r"\s","",x), house_type_list))rooms= list(filter(lambda x:x.endswith("居"),house_type_list)) #过滤干扰信息area= "".join(li.xpath(".//div[contains(@class,'house_type')]/text()").getall())area= re.sub("\s|-|/","",area)district_text= "".join(li.xpath(".//div[@class= 'address']/a//text()").getall())district= re.search(r".*\[(.+)].*", district_text)if district is not None:district= district.group(1)address= li.xpath(".//div[@class= 'address']/a/@title").get()sale= li.xpath(".//div[contains(@class, 'fangyuan')]/span/text()").get() price = "".join(li.xpath(".//div[@class='nhouse_price']//text()").getall())price= re.sub(r"\s|'广告'","",price)origin_url= li.xpath(".//div[@class='nlcd_name']/a/@href").get()if origin_url is not None:origin_url= "http"+ ":"+ origin_urlitem = NewHouseItem(name= name, rooms= rooms, area= area, address= address,district= district, sale= sale, price= price, origin_url= origin_url, province =province, city= city)yield itemnext_url= response.xpath("//div[@class='page']//a[@class='next'/@href]").get()if next_url:yield scrapy.Request(url=response.urljoin(next_url), callback=self.parse_newhouse, meta={"info":(province, city)})

    如代码2所示,使用xpath语法,获取新房页面所需字段信息后,存储在定义的item中。

    二手房页面解析

    #代码3 二手房页面解析 def parse_esf(self,response):province,city = response.meta.get('info')dls= response.xpath("//div[contains(@class,'shop_list')]/dl")for dl in dls:item= ESFHouseItem(province=province, city= city)name_text= dl.xpath(".//p[@class='add_shop']/a/text()").get()if name_text is not None:item['name'] = name_text.strip()infos= dl.xpath(".//p[@class='tel_shop']/text()").getall()infos= list(map(lambda x: re.sub(r"\s","",x), infos))for info in infos:if "厅" in info:item['rooms']= infoelif "层" in infos:item['floor']= infoelif '向' in info:item['toward']= infoelif '㎡' in info:tem['area']= infoelse:item['year']= info.replace("年建","") address= dl.xpath(".//p[@class='add_shop']/span/text()").get()if address is not None:address= address.strip()item['address'] = addressprice= "".join(dl.xpath("./dd[@class= 'price_right']/span[1]//text()").getall())if price is not None:price= price.strip()item['price']= priceunit = dl.xpath("./dd[@class= 'price_right']/span[2]//text()").get()if unit is not None:unit= unititem['unit']= unitdetail_url= dl.xpath(".//h4[@class='clearfix']/a/@href").get()item['origin_url']= response.urljoin(detail_url)yield itemnext_url= response.xpath("//div[@class='page_box']//p/a[1]/@href").get()yield scrapy.Request(url=response.urljoin(next_url), callback= self.parse_esf, meta={"info":(province, city)})

    如代码3所示,使用xpath语法,获取二手房页面所需字段信息后,存储在定义的item中。

    Spider类编写

    区别于单机爬虫Spider类的编写,分布式SfwSpider是自定义编写的针对房天下页面解析的Spider类,它不在继承原始的scrapy.Spider类,而是继承了RedisSpider类,用来从redis读取url。同样也不再使用start_urls,取而代之的是redis_key,Scrapy-redis将key从redis中pop出来,成为请求的url地址。关键代码如代码4。

    #代码4 SfwSpider类 class SfwSpider(RedisSpider):name = 'sfw'allowed_domains = ['fang.com']# start_urls = ['https://www.fang.com/SoufunFamily.htm']redis_key = "fang:start_urls"

    配置Scrapy-Redis

    为确保request存储到redis中、确保所有爬虫共享相同的去重指纹,以及设置redis连接
    信息,需要在setting.py中配置相关代码,如代码5所示。
    代码5 Scrapy-Redis的配置

    # Scrapy-Redis相关配置 # 确保request存储到redis中 SCHEDULER= "scrapy_redis.scheduler.Scheduler" # 确保所有爬虫共享相同的去重指纹 DUPEFILTER_CLASS= "scrapy_redis.dupefilter.RFPDupeFilter" # 设置redis为item pipline ITEM_PIPELINES= {'scrapy_redis.pipelines.RedisPipeline': 300 } # 在redis中保持scrapy-redis用到的队列,不会清理redis中的队列,从而可以实现暂停和回复 的功能 SCHEDULER_PERSIST= True # 设置连接redis信息 REDIS_HOST= '192.168.1.5' REDIS_PORT= '6379'

    应对反爬虫机制

    为了不被网站识别出是爬虫,主要使用了用户代理、限速、IP代理池等措施。

    随机请求头

    相应的中间件代码如代码6。

    代码6 随机请求头 USER_AGENTS= ['Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36','Mozilla/5.0 (X11; Ubuntu; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2919.83 Safari/537.36','Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2866.71 Safari/537.36','Mozilla/5.0 (X11; Ubuntu; Linux i686 on x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2820.59 Safari/537.36','Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2762.73 Safari/537.36','Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2656.18 Safari/537.36','Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML like Gecko) Chrome/44.0.2403.155 Safari/537.36' ] …… def process_request(self, request, spider):user_agent = random.choice(self.USER_AGENTS)request.headers['User-Agent'] = user_agent

    限速设置

    房天下服务器为防止恶意爬虫软件对其数据的破坏,设置相应的识别机制,为了降低反爬虫机制对系统的干扰,需增大平台的访问间隔时间。DOWNLOAD_DELAY = 3 #间隔时间

    IP代理池

    在众多的网站防爬措施中,有一种是根据ip的访问频率进行限制,即在某一时间段内,当某个ip的访问次数达到一定的阀值时,该ip就会被拉黑、在一段时间内禁止访问。应对的方法有两种:

  • 降低爬虫的爬取频率,避免IP被限制访问,缺点显而易见:会大大降低爬取的效
    率。
  • 搭建一个IP代理池,使用不同的IP轮流进行爬取。
  • 本文为降低爬虫被房天下网识别为爬虫的纪律,构建了IP代理池,如代码7、代码8所示。

    #代码7 Proxy类 class ProxyModel(object):def __init__(self,data):self.ip = data['ip']self.port = data['port']self.expire_str = data['expire_time']self.proxy = 'http://'+ '%s:%s' % (self.ip, self.port) self.expire_time = self.detail_time #代理是否已经被拉入黑名单了self.blacked = False#这个函数用于把str格式的过期时间(expire_time)转化为datetime格式,方便我们来#根据过期时间换新的代理@propertydef detail_time(self):date_str,time_str = self.expire_str.split(" ")year,month,day = date_str.split('-')hour,minute,second = time_str.split(':')expire_time = datetime(year=int(year),month=int(month),day=int(day),hour=int(hour),minute=int(minute),second=int(second),)return expire_time#比较代理的过期时间和现在的时间#如果这个代理的存活时间少于10,那么就要准备更换代理IP了@propertydef is_expiring(self):now = datetime.now()if (self.expire_time - now) <timedelta(seconds=10):return Trueelse:return False #代码8 更新IP def update_proxy(self): # lock是属于多线程中的一个概念,因为这里scrapy是采用异步的,可以直接看成多线程 # 所以有可能出现这样的情况,爬虫在爬取一个网页的时候,忽然被对方封了,这时候就 会来到这里 # 获取新的IP,但是同时会有多条线程来这里请求,那么就会出现浪费代理IP的请求,所 以这这里加上了锁 # 锁的作用是在同一时间段,所有线程只能有一条线程可以访问锁内的代码,这个时候一 条线程获得新的代理IP # 而这个代理IP是可以用在所有线程的,这样子别的线程就可以继续运行了,减少了代理 IP(钱)的浪费 self.lock.acquire() # 判断换线程的条件 # 1.目前没有使用代理IP # 2.到线程过期的时间了 # 3.目前IP已经被对方封了 # 满足以上其中一种情况就可以换代理IP了 if not self.current_proxy or self.current_proxy.is_expiring or self.current_proxy.blacked: url = r'https://h.wandouip.com/get/iplist?pack=%s&num=1&xy=1&type=2&lb=\r\n&mr=1&' % random.randint(100,1000) response = requests.get(url=url, headers=DEFAULT_REQUEST_HEADERS) text = json.loads(response.text) print(text) data = text['data'][0] proxy_model = ProxyModel(data) print('重新获取了一个代理:%s' % proxy_model.proxy) self.current_proxy = proxy_model # return proxy_model self.lock.release()

    相应的中间件代码如代码9所示。

    #代码9 IP代理中间件相应代码 def process_request(self, request, spider):if 'proxy' not in request.meta or self.current_proxy.is_expiring:# 请求代理self.update_proxy() request.meta['proxy'] = self.current_proxy.proxy def process_response(self, request, response, spider):# 如果对方重定向(302)去验证码的网页,换掉代理IP# 'captcha' in response.url 指的是有时候验证码的网页返回的状态码是200,所以用这个作为 辨识的标志if response.status != 200 or 'captcha' in response.url:# 如果来到这里,说明这个请求已经被boss直聘识别为爬虫了# 所以这个请求就相当于什么都没有获取到# 所以要重新返回request,让这个请求重新加入到调度中# 下次再发送if not self.current_proxy.blacked:self.current_proxy.blacked = Trueself.update_proxy()print('%s代理失效' % self.current_proxy.proxy)request.meta['proxy'] = self.current_proxy.proxyreturn request

    数据存储

    Scrapy-Redis框架支持mongodb、Redis等数据库存储。MongoDB是一种文档性的数据库,便于存储大量数据,由于系统采集的数据量过大,因此利用MongoDB数据库存储爬虫爬取的目标数据。各子爬虫将爬到的数据存储到Master服务器上的Redis数据库中,之后将Redis数据库中数据存入MongoDB数据库中,便于后续分析,如代码10。

    代码10 将爬虫数据存入MongoDB数据库 # 数据的持久化操作redis---->MongoDB import redis from pymongo import MongoClient import json # 爬虫实现简单分布式:多个url放到列表里,往里不停放URL,程序循环取值, # 可以把url放到redis中,多台机器从redis中取值,爬取数据,实现简单分布式 # 实例化redis客户端 redis_client = redis.Redis(host='192.168.1.3',port=6379)# 实例化MongoDB客户端 mongo_client = MongoClient(host='127.0.0.1',port=27017) # 指定链接的MongDB数据库、集合 db = mongo_client['fang'] col = db['HN'] # 使用循环把redis中数据全部写入到MongoDB中 while True:# 从redis中取出数据#blpop中出参数就是redis中的key-value的名为value的列表的名称,# 系统默认生成的与爬虫文件名类似的名称,形如=>(爬虫名:items)key,data = redis_client.blpop(['sfw:items'])print('key', key)print('data',data)#json.loads()函数是将json格式数据转换为字典# 把数据写入到MongoDB中col.insert_one(json.loads(data.decode())) # 关闭数据库 mongo_client.close()

    系统测试

    系统由两台物理节点组成,一台Master服务器,一台Salver服务器。
    Master端:CPU4核处理器,1T硬盘,8G内存,IP(192.168.1.5)采用Windows10(64位)操作系统,安装有Python3,Scrapy框架,Scrapy-Redis,Redis数据库和MongoDB数据库等。
    Salver端:CPU2核处理器,40G硬盘,2G内存,IP(192.168.138.128)采用Ubuntu20.04(64位)操作系统,安装有Python3,Scrapy框架,Scrapy-Redis等。
    由Master管理Url队列和分发下载任务,Salve下载网页提取数据,运行10min后,抓取全国房源信息8W条。将抓取到的数据存储到Master端Redis数据库中,后进行数据持久化操作,将数据存入Master端MongoDB数据库中。

  • 开启redis服务器
    执行redis-server.exe redis.windows.conf开启redis服务器如图7所示。

    图7 开启redis服务
  • salver端执行sfw爬虫代码
    如图8所示,在ubuntu系统下的salver端执行爬虫程序,并侦听Master端的redis-key,如图9所示。

    图8 执行sfw爬虫

    图9 等待Master端发送redis-key
  • Master端发送redis-key
    如图10所示,Master主机发送redis-key,也是爬虫所需的start_url。

    图10 Master主机发送redis-key
  • 数据持久化操作
    将salver端抓取的数据存储在master端的MongoDB数据库中,使用Navicat Premium 展示部分数据如图11。

    图11 抓取的房源信息数据存储在mongodb中
  • 全国房源信息可视化

    数据预处理

    由于网页中房源信息不统一,需要对抓取的数据进行预处理方可进行下一步分析。本文中,对抓取的房源信息统一价格单位均为元/平方米。

    tableau的使用

    Tableau是目前全球最易于上手的报表分析工具,并且具备强大的统计分析扩展功能。它能够根据用户的业务需求对报表进行迁移和开发,实现业务分析人员独立自助、简单快速、以界面拖拽式地操作方式对业务数据进行联机分析处理、即时查询等功能。Tableau可以连接到一个或多个数据源,支持单数据源的多表连接和多数据源的数据融合,可以轻松的对多源数据进行整合分析而无需任何编码基础。连接数据源后只需用拖放或点击的方式就可快速地创建出交互、精美、智能的视图和仪表板。任何Excel用户甚至是零基础的用户都能很快、很轻松地使用Tableau Desktop直接面对数据进行分析,从而摆脱对开发人
    员的依赖。本文就基于Tableau实现全国房源信息的简单可视化。

    全国房源信息简单可视化效果如图12为全国房源信息可视化效果图。


    图12 全国房源信息可视化

    结束语

    本文立足于快速、灵活抓取房天下房源信息这一目的,设计实现了一套面向房源信息采集的高效的分布式爬虫系统。采用Scrrapy-Redis分布式设计思想对目标数据进行爬取,并通过对房天下站点的结构分析,设计了一种使用于新房与二手房站带你的爬虫爬行策略。此外,还实现了持久化存储方式MongoDB数据库存储,并使用PowerBI可视化软件对全国房源信息进行简单的可视化分析。

    参考文献

    [1]邓万宇.一种基于Scapy-Redis的分布式微博数据采集方案[J].信息技术,2018,(11):59-62.
    [2]严慧.基于Scrapy-Redis分布式数据采集平台的设计与实现[J].湖北师范大学学报(自然科学
    版),2019,39(1):TP302.
    [3]安子建.基于Scrapy框架的网络爬虫实现与数据抓取分析[D].长春市:吉林大学,2017.
    [4]马豫星.Redis数据库特性分析.[J].物联网技术,2015,(3):TP326.
    [5]王芳.基于Scrapy框架的分布式爬虫设计与实现[J].信息技术,2019,(3):TP391.9.
    [6]马联帅.基于Scrapy的分布式网络新闻抓取系统设计与实现[D].西安市:西安电子科技大
    学,2015

    总结

    以上是生活随笔为你收集整理的基于 Scrapy-Redis 全国房源信息抓取系统的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。