国际化的功能离不开错误码的支持,客户端指定语言到服务端去请求,当出错了服务端会根据错误码和语言找到对应的国际化提示语。从上面图中我们发现,错误码不仅仅是客户端与服务端的交互,后台各个服务间的交互也需要约定的一套错误码。一般一个系统的错误码 code 都是唯一确定的。msg 不同场景下可能不一样,提供给用户的肯定是需要友好且不能暴露底层细节,给开发人员看的就要详细专业的错误内容。网关服务上面维护着多套不同语言的错误码提示语,响应的时候会根据客户端带的 Lang 信息进行国际化转译。模块模块编码错误编码底层描述中文提示语英文提示语库存10001商品规格表关联有误商品不存在goods don’t exist一般国际化的系统中会有多份 xxx_lang.properties文件,每一份代表一种语言的消息提示语。中文一般会转为 Unicode 编码进行存储(这个过程一般开发工具可以设置自动转),这样的处理可以规避不同开发环境下不同编码导致中文乱码。
上述例子发现输出的结果是英文的,显然是不适合在国内环境使用,moment.js 提供了国际化支持,在现有的库中,moment 支持的语言可以说是相对完备了。通过引入对应的国际化资源(语言文件),来切换语言。<script src="https://cdn.bootcdn.net/ajax/libs/moment.js/2.27.0/moment.min.js"></script><script src="https://cdn.bootcdn.net/ajax/libs/moment.js/2.27.0/locale/zh-cn.min.js"></script><script> var now = moment().calendar(); console.log(now);// 输出当前日历时间 moment().startOf('hour').fromNow(); // 相对这个小时过去了多少分钟 var timestamp = 1593933593236; // 2020年7曰5日下午15点20分38秒 moment(timestamp).fromNow(); // 相对时间戳多久前</script>有关国际化的更多内容可以参考文档。
uni-app 的 API 与微信小程序 API 基本一致。掌握微信小程序 API 对后面的开发很有帮助。微信小程序 API 文档:https://developers.weixin.qq.com/miniprogram/dev/api/
注册微信小程序账号,获取到 AppID,我们后面配置的时候会用到。在 HBuilderX 工具栏,点击发行,选择小程序-微信。输入小程序名称和 AppID,单击发行就可以了。这样我们就会获得一个微信小程序的打包文件,接下来我们来发布微信小程序项目,打开微信小程序开发者工具,导入刚刚生成的微信小程序项目的打包文件,在微信小程序开发者工具中先测试一下,项目运行是否正常,项目测试没有问题后,点击右上角>>按钮,上传代码就可以发布微信小程序了,最后等待微信团队审核通过,别人就可以在线上访问到你的项目了。
Flask 是一个 Python 实现的 Web 开发微框架,但是这个“微”并不代表着 Flask 功能比较简陋、有所欠缺。微框架中的 “微” 意味着:Flask 旨在保持核心简单而易于扩展;Flask 不会替用户做出太多决策,比如使用何种数据库;Flask 的选项(比如使用何种模板引擎) 通常有多个,用户很容易替换。默认情况下,Flask 不包含数据库抽象层、模板引擎、身份认证或其它任何已有多种库可以胜任的功能,如下图所示。然而,Flask 支持用扩展来给应用添加这些功能,应用程序可以很方便的集成这些扩展。众多的扩展提供了数据库集成、表单验证、上传处理、各种各样的开放认证技术等功能。
咱们打开新浪微博,然后随便找个带皇冠的,按下F12键(Mac用户按command+option+i)然后选中控制台的箭头,再点击皇冠:再点开这个图片可以发现:可以看到那些大 V 图标皇冠图标以及各种微博认证等图标,都是放在了一张雪碧图里(即使再牛的大 V,身份标志也是放在雪碧图中的)。
其实真实的原因是因为雪碧的英文名字是Sprite,而雪碧图的英文名是CSS Sprites,他俩同样都有Sprite这个词。左边是雪碧在国内的 Logo,右边是国外的 Logo。可以看到本来在没进入中国市场之前人家就叫Sprite(精灵),只不过进入了中国市场之后,中国区的负责人表示:用户去商店买汽水的时候如果对老板说:老板你这里有没有精灵?听起来就会感觉很奇怪,所以咱们不要被Sprite这个单词给限制住了,咱们应该起一个更符合中文语义的名字,于是乎“雪碧”诞生了。而雪碧图在国外叫做 CSS Sprite(CSS精灵)反正 Sprite 在国内被叫雪碧,那干脆不如咱们就叫它雪碧图吧!——来自最先接触到这项技术的人。所以后来接触这项技术的人也就跟随前人一起叫它雪碧图了。
本节我们讨论了如何利用第三方平台做我们系统的 OAuth2.0 认证中心,主要的知识点如下:Spring Security 实现了 OAuth2.0 客户端的常用功能,开发者可以轻松的将 Spring Boot 应用作为 OAuth2.0 客户端集成到安全体系中;在使用第三方作为 OAuth2.0 认证服务器时,首先要在第三方平台上完成应用注册,并获取到 Client ID 和 Client Secret 两个重要参数;使用第三方 OAuth2.0 认证源,可以简化系统开发中的关于认证的操作,并且可以更轻易的实现单点登录;使用第三方 OAuth2.0 认证源的时候,用户在本系统内的权限、详细用户信息等,仍需要在本地系统内维护;目前在国内支持度比较好的第三方认证源有:QQ、微信、微博、Github 等。下一节中,我们继续在 OAuth2.0 协议的基础上,构造出属于自己的认证中心。
pip 工具会从网站自动下载 Python 的第三方模块,提供下载 Python 第三方模块的网站被称为源。默认情况下,pip 从国外网站下载 Python 的第三方模块,速度非常的慢。为了加快下载速度,可以将 pip 的源改为国内的镜像源。国内常用的源如下:源的提供方源的 URL阿里云https://mirrors.aliyun.com/pypi/simple清华https://pypi.tuna.tsinghua.edu.cn/simple中国科技大学https://pypi.mirrors.ustc.edu.cn/simple华中理工大学http://pypi.hustunique.com豆瓣http://pypi.douban.com/simple
可以通过 CDN 引入 ECharts 文件:<!-- bootstrap 服务 --><!-- bootstrap 提供的免费CDN服务,亲测非常稳定 --><script src="//cdn.bootcss.com/echarts/4.5.0/echarts.common.js"></script><!-- 七牛云存储服务 --><!-- 国内速度稳定,开放性强 --><script src="//cdn.staticfile.org/echarts/4.5.0/echarts.common.js"></script><!-- jsdeliver 服务 --><!-- 微软的CDN服务,虽然国内访问速度比不上国内CDN,但速度不至于太慢,有国际化需求的可以试试 --><script src="//cdn.jsdelivr.net/npm/echarts@4.5.0/echarts.common.js"></script><!-- cdnjs 服务 --><!-- 一个非常全的CDN服务,存储了大多数主流的js、css、图片库 --><script src="//cdnjs.cloudflare.com/ajax/libs/echarts/4.5.0/echarts.common.js"></script>
模板方法模式是定义一个操作中的算法的骨架,从而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。通常对于一些重要的复杂方法和多个子类共有的方法且逻辑相同的情况下会使用模板方法模式。比如用户第三方用户认证的时候就比较适合使用模板方法。我们来看一个例子:假设我们现在需要用到微信、微博的第三方用户授权来获取用户的信息。//使用模板方法模式描述获取第三方用户信息的过程 public abstract class Authentication{ public void checkUserAuthentication(){ checkIdentity(); fetchInfo(); } protected abstract void checkIdentity(); protected abstract void fetchInfo(); } //微信用户 public class WechatAuthenication extends Authentication{ @Override protected void checkIdentity() { System.out.println("获得微信用户授权"); } @Override protected void fetchInfo() { System.out.println("获取微信用信息"); } } //微信用户 public class WeiboAuthenication extends Authentication{ @Override protected void checkIdentity() { System.out.println("获得微博用户授权"); } @Override protected void fetchInfo() { System.out.println("获取微博用信息"); } } //调用模板方法 public class Demo{ public static void main(String...s){ Authentication auth = new WechatAuthenication(); auth.checkUserAuthentication(); auth = new WeiboAuthenication(); auth.checkUserAuthentication(); } }输出结果:获得微信用户授权 获取微信用信信息 获得微博用户授权 获取微博用信信息现在我们使用 Lambda 表达式换个角度来思考模板方法模式。如果我们用函数式接口来组织模板方法中的调用过程,相比使用继承来构建要显得灵活的多。//定义一个处理接口,用来处理一项事务,如授权或者获取信息。 public interface Processer{ public void process(); } //封装调用过程 public class Authentication{ private final Processer identity; private final Processer userinfo; public Authentication(Criteria identity,Criteria userinfo){ this.identity = identity; this.userinfo = userinfo; } public void checkUserAuthentication(){ identity.process(); userinfo.process(); } } //使用模板方法 public class Demo{ Authentication auth = new Authentication(()->System.out.println("获得微信用户授权"), ()->System.out.println("获取微信用户信息")); auth.checkUserAuthentication(); auth = new Authentication(()->System.out.println("获得微博用户授权"), ()->System.out.println("获取微博用户信息")); auth.checkUserAuthentication(); }输出结果:获得微信用户授权 获取微信用信信息 获得微博用户授权 获取微博用信信息此时,我们的模板方法得到了大幅的简化,同时通过函数接口让模板方法获得了极大的灵活性。
很多时候,大家都在思考递归在数学上面应该如何表示了,毕竟对于数学的简单理解比起我们直接写代码起来还是要简单很多的。观察递归,我们会很容易发现递归的数学模型类似于数学归纳法,这个在高中的数列里面就已经开始应用了。数学归纳法常见的描述如下最简单和常见的数学归纳法是证明当 n 等于任意一个自然数时某命题成立。证明分下面两步:证明当 n= 1 时命题成立。假设 n=m 时命题成立,那么可以 推导出在 n=m+1 时命题也成立。(m 代表任意自然数)数学归纳法适用于将需要解决的原问题转换为解决他的子问题,而其中的子问题又可以变成子问题的子问题,而且这些问题都是同一个模型,可以用相同的处理逻辑归纳处理。当然有一个是例外的,就是归纳结束的那一个处理方法不能适用于其他的归纳处理项。递归同样的是将大的问题分解成小问题处理,然后会有一个递归的终止条件,满足终止条件之后开始回归。数学里面有一个很有名的斐波那契数列,我们在编程求解斐波那契数列的时候就会用到递归的思想,在后续的内部中会具体讲到。
Linux 中 /etc/shadow 文件上保存了每个用户的信息,该文件只有 root 用户才能访问,这个文件中包含每个用户的一条记录信息,使用 cat 命令查看:cat /etc/shadow执行结果如下图:这些信息以 : 分隔,/etc/shadow 文件中每行用户包含的信息如下:用户名(和 /etc/passwd 对应);密码(已被加密),这个字段是非空的;上次修改口令的时间(距离 1970 年 1 月 1 日的天数);两次修改口令间隔最少的天数,如果这个字段的值为空,帐号永久可用;提前多少天警告用户口令将过期,如果这个字段的值为空,帐号永久可用;在口令过期之后多少天禁用此用户,如果这个字段的值为空,帐号永久可用;用户过期日期,表示用户作废的天数(距离 1970 年 1 月 1 日的天数),如果这个字段的值为空,帐号永久可用;保留字段,目前为空,以备将来发展之用。
Linux 中 /etc/gshadow 文件上保存了每个用户组的信息,该文件和 /etc/shadow 类似,只有 root 用户才能访问,这个文件中包含每个用户组的一条记录信息,使用 cat 命令查看:cat /etc/gshadow执行结果如下图:这些信息以 : 分隔,/etc/gshadow 文件中每行用户包含的信息如下:组名;加密密码;组管理员;组附加用户列表。
1969年,IBM 的技术人员 Charles Goldfarh 和 Edward Mosher 等人一起发明了通用标记语言 GML(Generalized Marked Language)。1985年在英国成立了国际 SGML 用户组织,在1986年,SGML 成为国际标准ISO8879:信息处理标准通用标记语言(Information processing Text and office system Standard generalized markup language)。HTML 和 XML 派生于 SGML,XML 可以被认为是它的一个子集,而 HTML 是它的一个应用。为了告诉浏览器我们需要展示什么内容,HTML 定义了一整套符号标记规范,这些规范包括设置文字的格式;创建列表;显示图片;显示多媒体;显示超链接;等等。
小程序的开发需要使用小程序主体提供的开发者工具,以 微信小程序 为例,就是要下载 微信开发者工具。也就是说,如果需要开发多个平台下的小程序,那每个平台提供的工具都需要安装一遍。通常开发者工具会使用其预览、调试功能,以及其他的一些生态链工具,如上传、预览代码等,编辑工作会放在自己的编码工具上进行,因为官方提供的编辑器的功能相比其他主流编辑器或者 IDE 还有许多不足。
/** * 获取用户 SESSION 和 COOKIE 信息 */ public function userinfo(){ halt(["cookie"=>cookie("user_info"),"session"=>session("user_info")]); }登录界面如下图所示用户信息如下图所示:
2.1.1 原生开发原生开发一般是指用原生语言进行开发,原生开发语言就是官方提供的开发语言,比如 IOS 是利用 Objective-C 和 Xcode 进行开发、小程序是用微信小程序原生语言和微信开发者工具进行开发。2.1.2 混合开发混合开发是指开发一个项目应用时,为了提高运行效率或者开发效率,将各种开发技术进行混合应用的开发形式。混合开发将各种开发方式取长补短,虽然比原生开发更难上手,但是架不住开发效率和运行效率的优势,现在比较大型的应用项目都会用混合开发来进行项目开发。uni-app 的混合开发主要是为了实现一些 uni-app 框架无法实现的功能,或者扩展接入一些第三方的 SDK。
微前端 尚处在发展时期,其核心概念和 微服务 相似。现阶段较为常用的微前端框架为 single-spa 和 qiankun,后者是基于前者实现的。该技术能做到 技术栈无关,即一个应用,能由多个不同技术的子应用构成,同时做到子应用的相互隔离,这里的隔离就可以选择采用 Web Components 实现。
上一节我们介绍了「密码认证」的实现方法,本节我们讨论如何通过 OAuth2.0 方式直接从第三方机构获取用户身份信息的方法。OAuth(开放授权)是一个开放标准,允许用户授权第三方移动应用访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方移动应用或分享他们数据的所有内容,OAuth2.0 是 OAuth 协议的延续版本,但不向后兼容 OAuth1.0 即完全废止了 OAuth1.0。除了自建认证中心外,常用的互联网 OAuth2.0 认证中心还包括:QQ、微信、微博、Github 等,例如 imooc.com 的登录选项里,我们能看到「微博登录」、「微信登录」和「QQ 登录」,这些其实就是对 OAuth2.0 认证的应用。慕课网登录页面 /center>本节将以 Github 作为第三方认证中心为例,讨论如何使用 Spring security 实现 OAuth2 登录的功能。本节开发环境JDK 1.8Maven 3.5.3 依赖项:spring-security-config:5.3.2.RELEASEspring-security-oauth2-client:5.3.2.RELEASEspring-security-oauth2-jose:5.3.2.RELEASEspring-boot-starter-thymeleaf:2.3.0.RELEASEspring-boot-starter-web:2.3.0.RELEASEthymeleaf-extras-springsecurity5:3.0.4.RELEASE
1. 独立的页面维护了全局 错误码错误码由5位整数构成2. 每个接口一个独立的 参数说明页面正常情况下出参只返回业务实体异常情况才有 errCode errMsg每个接口下也可能有自己的业务错误码
可以在 /etc/passwd 文件查看上述备注的用户信息,命令如下:grep user_name02 /etc/passwd执行结果如下图:
如果记录数量很多,服务器不可能都将它们返回给用户。API 应该提供参数,过滤返回结果。比如,我们想获取全校师生的个人信息,如果将这些信息一股脑地全部展示在网页上,是不明智也是不现实的。如果数据量太大,在实际开发中我们会采用分页展示的形式。另外,如果想在一次考试后,按照成绩高低展示学生信息,那么可以通过过滤信息来实现。所谓过滤,就是在 URL 中添加一下限制参数。下面是一些常见的参数。?limit=10:指定返回记录的数量?offset=10:指定返回记录的开始位置。?page=2&per_page=100:指定第几页,以及每页的记录数。?sortby=score&order=asc:指定返回结果按照学生的成绩(score)正序(asc)排列顺序。参数的设计允许存在冗余,即允许 API 路径和 URL 参数允许有重复。比如,想要查询某个班级所有学生信息,我们可以设计 GET /classes/ID/students 与 GET /students?class_id=ID 两种地址,任何一种都可得到相同的结果。
脱贫全面小康、现代化,一个民族都不能少(节选)<p> 习近平:中华人民共和国是一个多民族的社会主义大家庭,在你们的社区就体现出来了,回族、汉族为主的多民族社区。刚才我看到你们这个社区很好的经验,特别是民族之间和睦的关系,这是我最希望看到的。我们都是中华民族大家庭中的一份子。脱贫、全面小康、现代化,一个民族都不能少,我们都是携手并进。这体现五千年的中华文明,也体现我们中国特色社会主义制度的优越性。</p><p> 这是2020年6月8日习近平总书记在宁夏吴忠市利通区金花园社区同居民们亲切交流时作的讲话。</p><p> 这段话凸显了总书记对少数民族地区脱贫攻坚的高度重视,对少数民族群众的惦记牵挂。十八大以来,习近平总书记对民族地区工作倾注了大量心血,他的足迹遍布雪域高原、大江南北,有力地推动了各民族共同繁荣。</p><p >我们的国家是各族人民携手缔造的,也是各族人民共同建设的。党领导各族人民经过艰辛探索,走出了一条共同富裕的大道。比如,针对少数民族组织实施发展规划,开展专项扶贫、精准扶贫等,是中国特色减贫道路的显著特征,这使得少数民族同胞,尤其是深度贫困地区的少数民族同胞,生产生活得到了极大改善。</p>
企业级的项目都会标配日志子系统。日志系统可以记录项目运行过程的所有信息,通过这些信息可以很方便帮助开发人员找到项目运行过程的问题。日志系统也可以记载用户的使用记录,这些信息可以帮助开发者分类、归纳用户的使用入口,更好的维护系统的安全性。除此之外,日志信息还有更多其它用途。众多流行、优秀的日志框架中,本课程主推 log4j。log4j 日志系统有两个版本,使用时有很大差异性。基于 Spring 5.X 版本的项目中建议使用 log4j 2 版本。
而移动端的宽高比刚好相反,手机通常都是竖着的,只有在看电影电视剧或者玩游戏的时候才会横过来,甚至有许多用户直接锁定了竖屏,即使横过来手机也不会发生任何变化。这就导致了移动端与 PC 端的布局有很大的不同,移动端是宽太窄了,通常只能容纳一个列(横行竖列),但是高却很长,尤其是现在的全面屏,让人感觉屏幕超级长,这时候就可以在行(横行竖列)上动手脚了,比较常见的一种布局是上面一行和下面一行固定在屏幕的 header 和 footer,它们并不会随着屏幕的滚动而移动,类似于这样:微信几乎是大家最熟悉的软件了,没有了它就相当于没有了社交,在这样一款用户及其庞大的软件上就运用了移动端最经典的布局。滑动好友列表最上面的灰色那栏并不会移动:同理,下面的那栏控制着微信的会话、通讯录、朋友圈以及设置等重要功能,它也不会被移动:将此种布局稍微抽象一下就能得出这样的一张图:最上面的那行通常被称为 header,最下面的通常被称为 footer,很好理解,头和脚嘛!
上面介绍了一些 Scrapy Shell 和 Response 的基础知识,我们现在就来在 Scrapy Shell 中实战 Selector 选择器。本次测试的网站为广州链家,测试页面为二手房页面:链家二手房网站我已经在上面标出了想要爬取的网页信息,后面也主要测试这些数据的 xpath 表达式 或者 css 表达式。首先使用 scrapy shell 目标网址 命令进行想要的命令行,此时 Scrapy 框架已经为我们将目标网站的网页数据爬取了下来:(scrapy-test) [root@server ~]# scrapy shell https://gz.lianjia.com/ershoufang/...>>> response<200 https://gz.lianjia.com/ershoufang/>我们看到响应的网页数据已经有了,接下来我们就可以开始进行网页分析来抓取图片中标记的数据了。首先是标题信息:提取二手房数据的标题信息根据上面的网页结构,可以很快得到标题的 xpath 路径表达式:标题://ul[@class="sellListContent"]/li/div/div[@class="title"]/a/text()在 Scrapy Shell 中我们实战一把:>>> response.xpath('//ul[@class="sellListContent"]/li/div/div[@class="title"]/a/text()')[<Selector xpath='//ul[@class="sellListContent"]/li/div/div[@class="title"]/a/text()' data='地铁口 总价低 精装实用小两房'>, <Selector xpath='//ul[@class="sellListContent"]/li/div/div[@class="title"]/a/text()' data='刚需精装小三房/三房两厅一厨一卫/广州东绿湖国际城'>, <Selector xpath='//ul[@class="sellListContent"]/li/div/div[@class="title"]/a/text()' data='周门社区 绿雅苑六楼 精装三房'>, <Selector xpath='//ul[@class="sellListContent"]/li/div/div[@class="title"]/a/text()' data='金碧领秀国际 精装修一房 中楼层采光好'>, <Selector xpath='//ul[@class="sellListContent"]/li/div/div[@class="title"]/a/text()' data='户型方正 采光好 通风透气 小区安静'>, <Selector xpath='//ul[@class="sellListContent"]/li/div/div[@class="title"]/a/text()' data='毛纺小区 南向两房 方正实用 采光好'>, <Selector xpath='//ul[@class="sellListContent"]/li/div/div[@class="title"]/a/text()' data='南奥叠层复式 前后楼距开阔 南北对流通风好'>, <Selector xpath='//ul[@class="sellListContent"]/li/div/div[@class="title"]/a/text()' data='丹桂园 实用三房精装修 南向户型 拧包入住'>, <Selector xpath='//ul[@class="sellListContent"]/li/div/div[@class="title"]/a/text()' data='周门小区大院管理 近地铁总价低全明正规一房一厅'>, <Selector xpath='//ul[@class="sellListContent"]/li/div/div[@class="title"]/a/text()' data='云鹤北街 精装低楼层 南向两房'>, <Selector xpath='//ul[@class="sellListContent"]/li/div/div[@class="title"]/a/text()' data='中海誉城东南向两房,住家安静,无抵押交易快'>, <Selector xpath='//ul[@class="sellListContent"]/li/div/div[@class="title"]/a/text()' data='精装两房,步梯中层,总价低,交通方便,配套齐全'>, <Selector xpath='//ul[@class="sellListContent"]/li/div/div[@class="title"]/a/text()' data='中层南向四房 格局方正 楼层适中'>, <Selector xpath='//ul[@class="sellListContent"]/li/div/div[@class="title"]/a/text()' data='精装修 户型好 中空一房 采光保养很好'>, <Selector xpath='//ul[@class="sellListContent"]/li/div/div[@class="title"]/a/text()' data='业主急售,价格优质看房方便有密码'>, <Selector xpath='//ul[@class="sellListContent"]/li/div/div[@class="title"]/a/text()' data='汇侨新城北区 精装三房 看花园 户型靓'>, <Selector xpath='//ul[@class="sellListContent"]/li/div/div[@class="title"]/a/text()' data='小区中间,安静,前无遮挡,视野宽阔,望别墅花园'>, <Selector xpath='//ul[@class="sellListContent"]/li/div/div[@class="title"]/a/text()' data='小区侧边位 通风采光好 小区管理 装修保养好'>, <Selector xpath='//ul[@class="sellListContent"]/li/div/div[@class="title"]/a/text()' data='万科三房 南北对流 中高层采光好'>, <Selector xpath='//ul[@class="sellListContent"]/li/div/div[@class="title"]/a/text()' data='南北对流,采光充足,配套设施完善,交通便利'>, <Selector xpath='//ul[@class="sellListContent"]/li/div/div[@class="title"]/a/text()' data='美力倚睛居3房南有精装修拎包入住'>, <Selector xpath='//ul[@class="sellListContent"]/li/div/div[@class="title"]/a/text()' data='美心翠拥华庭二期 3室2厅 228万'>, <Selector xpath='//ul[@class="sellListContent"]/li/div/div[@class="title"]/a/text()' data='天河公园门口 交通便利 配套成熟'>, <Selector xpath='//ul[@class="sellListContent"]/li/div/div[@class="title"]/a/text()' data='保利香槟花园 高层视野好 保养很好 居家感好'>, <Selector xpath='//ul[@class="sellListContent"]/li/div/div[@class="title"]/a/text()' data='恒安大厦两房,有公交,交通方便,价格方面可谈'>, <Selector xpath='//ul[@class="sellListContent"]/li/div/div[@class="title"]/a/text()' data='此房是商品房,低层,南北对流,全明屋'>, <Selector xpath='//ul[@class="sellListContent"]/li/div/div[@class="title"]/a/text()' data='水荫直街 原装电梯户型 方正三房格局'>, <Selector xpath='//ul[@class="sellListContent"]/li/div/div[@class="title"]/a/text()' data='嘉诚国际公寓 可明火 正规一房一厅'>, <Selector xpath='//ul[@class="sellListContent"]/li/div/div[@class="title"]/a/text()' data='近地铁两房 均价低 业主自住 装修保养好'>, <Selector xpath='//ul[@class="sellListContent"]/li/div/div[@class="title"]/a/text()' data='宏城汇 三房 南向 采光好 户型方正 交通便利'>]上面结果返回的是 SelectorList 类型:>>> data_list = response.xpath('//ul[@class="sellListContent"]/li/div/div[@class="title"]/a/text()')>>> type(data_list)<class 'scrapy.selector.unified.SelectorList'>最后我们通过提取 Selector 的 root 属性,只得到相应的文本信息:>>> data = [d.root for d in data_list]>>> data['地铁口 总价低 精装实用小两房', '刚需精装小三房/三房两厅一厨一卫/广州东绿湖国际城', '周门社区 绿雅苑六楼 精装三房', '金碧领秀国际 精装修一房 中楼层采光好', '户型方正 采光好 通风透气 小区安静', '毛纺小区 南向两房 方正实用 采光好', '南奥叠层复式 前后楼距开阔 南北对流通风好', '丹桂园 实用三房精装修 南向户型 拧包入住', '周门小区大院管理 近地铁总价低全明正规一房一厅', '云鹤北街 精装低楼层 南向两房', '中海誉城东南向两房,住家安静,无抵押交易快', '精装两房,步梯中层,总价低,交通方便,配套齐全', '中层南向四房 格局方正 楼层适中', '精装修 户型好 中空一房 采光保养很好', '业主急售,价格优质看房方便有密码', '汇侨新城北区 精装三房 看花园 户型靓', '小区中间,安静,前无遮挡,视野宽阔,望别墅花园', '小区侧边位 通风采光好 小区管理 装修保养好', '万科三房 南北对流 中高层采光好', '南北对流,采光充足,配套设施完善,交通便利', '美力倚睛居3房南有精装修拎包入住', '美心翠拥华庭二期 3室2厅 228万', '天河公园门口 交通便利 配套成熟', '保利香槟花园 高层视野好 保养很好 居家感好', '恒安大厦两房,有公交,交通方便,价格方面可谈', '此房是商品房,低层,南北对流,全明屋', '水荫直街 原装电梯户型 方正三房格局', '嘉诚国际公寓 可明火 正规一房一厅', '近地铁两房 均价低 业主自住 装修保养好', '宏城汇 三房 南向 采光好 户型方正 交通便利']是不是非常简单就爬到了数据?另外,我们还可以使用 extract()[0] 或者 extract_first() 这样的方式来提取结果列表中的第一个文本数据:>>> data = response.xpath('//ul[@class="sellListContent"]/li/div/div[@class="title"]/a/text()').extract()[0]>>> data2 = response.xpath('//ul[@class="sellListContent"]/li/div/div[@class="title"]/a/text()').extract_first()>>> data == data2True>>> data'地铁口 总价低 精装实用小两房'接下来,我们依次找出获取二手房位置、房屋价格、房屋信息的 xpath 路径表达式:房屋位置://ul[@class="sellListContent"]/li/div/div[@class="food"]/div[@class="positionInfo"]/a[]/text()房屋信息://ul[@class="sellListContent"]/li/div/div[@class="address"]/div[@class="houseInfo"]/text()房屋价格://ul[@class="sellListContent"]/li/div/div[@class="priceInfo"]/div[@class="totalPrice"]/span/text()有了这些之后,我们就可以依次提取出二手房的【标题介绍】、【房屋位置】、【房屋信息】以及【房屋价格】这些信息。此外对于提取的【房屋信息】字段还要进一步处理,分割成【房屋结构】、【房屋大小】以及【朝向】等信息。这些信息将在 Spider 模块中进行提取,也就是我们前面互动出版网爬虫的 ChinaPubCrawler.py 文件中的 ChinaPubCrawler 类来解析。最后我们在介绍下 scrapy shell 命令的参数:(scrapy-test) [root@server ~]# scrapy shell --helpUsage===== scrapy shell [url|file]Interactive console for scraping the given url or file. Use ./file.html syntaxor full path for local file.Options=======--help, -h show this help message and exit-c CODE evaluate the code in the shell, print the result and exit--spider=SPIDER use this spider--no-redirect do not handle HTTP 3xx status codes and print response as-isGlobal Options----------------logfile=FILE log file. if omitted stderr will be used--loglevel=LEVEL, -L LEVEL log level (default: DEBUG)--nolog disable logging completely--profile=FILE write python cProfile stats to FILE--pidfile=FILE write process ID to FILE--set=NAME=VALUE, -s NAME=VALUE set/override setting (may be repeated)--pdb enable pdb on failure比较常用的有 --no-redirect 和 -s 选项:--no-redirect : 指的是不处理重定向,直接按照原始响应返回即可;-s:替换 settings.py 中的配置。常用的有设置 USER_AGENT 等。
在 Web 应用中,用户通过浏览器向服务器提交请求,服务器接收到请求后,对用户的请求进行处理,再将结果返回给用户。例如,使用 baidu 搜索引擎的过程如下:用户在 baidu 的搜索框中,输入关键字 “手机”,浏览器将关键字 “手机” 发送到 baidu 的服务器。baidu 服务器收到查询手机的请求,在数据库查找和手机相关的网页,按照与关键词的相关性进行排序,再将排序结果发送给用户。浏览器收到服务器的查询结果后,显示与 “手机” 相关的网页列表。在以上的 3 个步骤中,与用户交互的部分称之为前端,在服务器处理的用户请求的部分称为后端。Python 提供了大量的模块和框架可以用于后端开发。有很多知名的网站后端采用了 Python,例如,国内的豆瓣就是一个应用Python打造的非常成功的 Web 2.0 站点。
2015年6月17日,ECMA国际组织发布了 ECMAScript 的第六版,该版本正式名称为 ECMAScript 2015,但通常被称为 ECMAScript 6 或者 ES6。(MDN)ES6 的发布让 JavaScript 的编写体验有了里程碑式的飞跃。各种概念性的特性都被纳入标准,如 Promise、模块化 。Google Chrome 浏览器支持绝大部分的 ES6 特性,可以直接在浏览器上体验。慕课网针对 ES6 也有对应的 Wiki教程,这个课程讲解比较全面,使用 ES5 与 ES6 做对比的方式进行的讲解,想全面掌握的同学可以参阅。
一般服务器采用 Linux 或者 Windows Server 系统,相对而言 Linux 系统更加稳定安全。实际上 Windows Server 系统对于一般应用来说也足够了,本篇我们使用 Windows Server 系统进行演示。推荐使用云服务器,更加稳定且易于维护,国内厂商阿里云、华为云都还不错。Tips: 云服务器的硬盘读写性能非常重要,在购买云服务器时务必关注下云硬盘的 IOPS 值(衡量硬盘读写性能的一个指标),一般建议要采用 IOPS > 3800 的云磁盘。具备云服务器后,需要安装 JDK 以便运行 Spring Boot 应用。由于 nginx 对静态资源的负载能力非常强悍,所以我们将前端应用部署到 nginx 上。