基于 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]如下:

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

中间件

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

  • Scrapy Middleware有以下几个函数被管理
  1. process_spider_input:接收一个response对象并处理;
  2. process_spider_exception:spider出现异常时被调用;
  3. process_spider_output:当spider处理response返回result时,就会调用该
    方法;
  4. process_spider_requests:当spider发出请求时,被调用;
  • Download Middleware有以下几个函数被管理
  1. process_requests:requests通过下载中间件的时候,该方法被调用,这里可
    以通过设置代理,设置request.meta[‘proxy’]就OK了;
  2. 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(信号):

  1. 当spider空闲时候的signal,会调用spider_idle函数,这个函数调用schedule_next_request函数,保证spider是一直活着的状态,并且抛出DontCloseSpider异常。
  2. 当抓到一个item时的signal,会调用item_scraped函数,这个函数会调用schedule_next_request函数,获取下一个request。

Scrapy-Redis分布式策略


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

  1. Master端(核心服务器) :使用 Windows 10,搭建一个Redis数据库,不负责爬取,只负责url指纹判重、Request的分配,以及数据的存储。
  2. 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就会被拉黑、在一段时间内禁止访问。应对的方法有两种:

  1. 降低爬虫的爬取频率,避免IP被限制访问,缺点显而易见:会大大降低爬取的效
    率。
  2. 搭建一个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数据库中。

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

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

    图8 执行sfw爬虫

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

    图10 Master主机发送redis-key
  4. 数据持久化操作
    将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 全国房源信息抓取系统相关推荐

  1. 基于scrapy下的租房信息爬取与数据展示工具的设计与实现

    环境:python 3.6.0 Anaconda custom 64bit 4.3.0 Pycharm x64 专业版 2018.1.2 Web strom x64 专业版 2018.1.3 scra ...

  2. Scrapy+redis+mongodb分布式爬虫抓取小说《冰与火之歌1-5》

    一年前写了python简单实战项目:<冰与火之歌1-5>角色关系图谱构建的数据库设计和数据可视化共现图谱的构建,中间唯独缺了数据的采集,因为想着只是个小爬虫,应该无关痛痒,后面也觉得这个系 ...

  3. 基于机器视觉的ROS机械臂抓取实验

    点击上方"3D视觉工坊",选择"星标" 干货第一时间送达 作者丨曾三 来源丨 混沌无形 点击进入->3D视觉工坊学习交流群 摘要:为了减少机械臂在产品分类 ...

  4. python找房源_python抓取链家房源信息(二)

    试着用scrapy将之前写的抓取链家网信息的重新写了写 然后先是用了第一页的网页作为测试,调试代码,然后发现总是抓取的时候遇见了 类似于这样的问题,并且抓取不到信息 2017-03-28 17:52: ...

  5. 用Python实现全国二手房数据抓取+地图展示

    最近各种政策的出台,导致二手房的价格波动巨大,本文二哥来带领大家通过链家二手房为例,简单分析一下全国多个地区的二手房价格. [建议先点赞.再收藏] 一.思路❤️ 想要获取链家全国二手房的信息,首先我们 ...

  6. 大盘点|基于RGB图像下的机器人抓取

    点击上方"3D视觉工坊",选择"星标" 干货第一时间送达 前言 近期读取了一些最新基于RGB图像下的机器人抓取论文,在这里分享下思路. 1.Optimizing ...

  7. Atitit.web的自动化操作与信息抓取 attilax总结

    Atitit.web的自动化操作与信息抓取 attilax总结 1. Web操作自动化工具,可以简单的划分为2大派系: 1.录制回放 2.手工编写0 U' z; D! s2 d/ Q! ^1 2. 常 ...

  8. Airbnb房源信息爬取(一)——获取城市列表

    编程初衷 去年这会儿,实验室师兄论文需要获取短租房源数据,老师顺手就把任务给了我和一个同门:你们先下个几千张吧,不要多,先看看图片质量,后面再慢慢来. 几千张??还有后面??打扰了- 想着下载都是重复 ...

  9. 基于Java的阿里妈妈数据抓取技术

    基于Java的阿里妈妈数据抓取技术 前言: 对于需要登录的网站爬虫最大的困难就是需要登录,然后才能获取到数据,如微博,阿里妈妈,webqq等.之前也有看过使用浏览器登录到网站后直接从浏览器中获取coo ...

最新文章

  1. 介绍一款开源的类Excel电子表格软件
  2. win10 php mysql_win10 下 apache php mysql 开发环境安装
  3. php上传,PHP-文件上传和下载「程序员培养之路第三十八天」
  4. chrome恐龙游戏_如何玩没有互联网的Google Chrome恐龙游戏-在线和离线
  5. 在Python中模拟do-while循环
  6. 不停机上线服务_手机停机也能迅速交话费!微信和三大运营商联手开了“绿色通道”...
  7. ubuntu 文件及子文件夹的权限的查看及修改
  8. 支持Delphi2009/2010的DES加密单元
  9. 深度学习aps_深度学习的目标检测算法是如何解决尺度问题的?
  10. intptr java_intptr_t 其实不是指针类型 (转载)
  11. 安卓开发之路----转自任玉刚大神
  12. Verilog 层次化文件设计——彩灯控制器
  13. 用R语言看武汉市武昌区房租出租情况
  14. 如何清理 WinSxS 文件夹-2022版
  15. 二叉树的左视图和右视图
  16. Springboot RestTemplate post/get请求所有情况
  17. 系统调用号(eax 调用号) 及 EAX、ECX、EDX、EBX寄存器的作用
  18. 龙芯2k开发板Debian系统安装教程
  19. 简单的理解position与anchorPoint
  20. SS00007.algorithm——|ArithmeticMachine.v07|——|Machine:监督学习算法.v06|

热门文章

  1. MCE公司:MCE 中国生命科学研究促进奖获奖论文集锦二
  2. 国际学术期刊会议大排名
  3. win10自动修复重启,无法开机
  4. TeamViewer11的安全设置
  5. WinPcap应用小记
  6. html photoswipe原理,H5使用PhotoSwipe预览图片
  7. CSP-S2022 游记
  8. 机器视觉毕业设计 深度学习驾驶人脸疲劳检测系统 - python opencv
  9. c语言中值程序,编程c语言中,向上取整函数_C编程中的函数
  10. 风变编程Python课程学起来容易吗?