上一篇<学习MVC之租房网站(十一)-定时任务和云存储>学习了Quartz的使用、发邮件,并将通过UEditor上传的图片保存到云存储。在项目的最后,再学习优化网站性能的一些技术:缓存和页面静态化。
使用缓存可以降低数据库的压力,而使用页面静态化则可以降低Web服务器的压力。
一 缓存
ASP.NET下可用的缓存为System.Web.Caching.Cache,保存在服务器内存中,不适用于服务器集群,虽然也用没用过集群,但现在的主流都使用NoSQL数据库来做缓存,典型的有Redis和Memcached,这类缓存技术支持集群部署,而且如果使用独立的服务器,便可不受主服务器宕机的影响,Redis更是支持把数据持久化到硬盘。Redis和Memcached的应用需要专门学习实践,这儿只是代替普通Cache来掌握基本的使用。
a) Memcached基础
Memcached最适合的操作系统是Linux,在VS中可以从Nuget安装EnyimMemcached来使用。首先要让Memcached运行起来,在生产环境会作为服务运行,在学习阶段只是每次使用前启动控制台就行了。
需要缓存的对象要被标记为Serializable,而且与该对象关联的对象也需要标记可序列化。存取方法为:
b) Redis基础
Redis使用Json格式的序列化方式,所以不需要像Memcached那样标记Serializable,而且Memcached只能在内存保存数据,Redis还可以将数据持久化到硬盘。在学习应用时,也是在使用前启动其控制台:
使用方式和Memcached类似,首先安装ServiceStack.Redis,存取代码为:
二 页面静态化
缓存可以降低数据库读取的压力,但在网站收到访问请求后,仍然每次都要跑一遍取得Model、渲染View的过程,而通过将页面静态化可以规避这个过程造成的压力。比如用户访问ID为249的房源页面时,原本是要通过House/Detail/249实时渲染,但现在就可以直接访问对应的249.html文件,这实际上是将渲染页面的动作提前到了新增249房源的时刻,在249房源保存到系统时随即生成其html页面,以后服务器只需要直接返回这个页面,运算量大大减少,而且相比以前的实时渲染,静态页面只需要渲染一次(不包括修改数据后的重新静态化)。
新增房源后,渲染静态化页面的代码为:
调用方法:string html=MVCHelper.RenderViewToString(this.ControllerContext, @"~/Views/House/StaticIndex.cshtml", model);
除了新增,每次修改房源信息,也要重新生成静态页面,以保证信息的同步。
注:
课程内容来自如鹏网(www.rupeng.com),专注于大学生就业的在线教育平台;
ASP.NET MVC课程 http://www.rupeng.com/News/9/640.shtml
在这里我就不再一一介绍每个步骤的具体操作了,因为在爬取老版数据的时候都已经讲得非常清楚了,所以在这里我只会在重点上讲述这个是这么实现的,如果想要看具体步骤请先去看我的文章内容,里面有非常详细的介绍以及是怎么找到加密js代码和api接口。
私信小编01即可获取大量Python学习资料
58同城的数据爬取非常简单,唯一有点难的就是字体的加密,除此之外其他的数据用xpath即可获取。
想爬取不同地方的直接访问链接即可:
数据在链接中,直接请求获取即可。
既然是字体加密那么就先把字体寻找出来,寻找简单,在开发者工具中的分类找到Font,然后搜索这个链接进行查找。
已经找到这个字体了,他是在请求页面的时候返回的,然后他还是个base64的,只需要转换一下再保存就可以了。
import requests
from lxml import etree
def get_data():
url="https://bj.58.com/chuzu/?PGTID=0d200001-0000-11e9-58e6-a658f219b27c&ClickID=1"
headers={
'authority': 'bj.58.com',
'method': 'GET',
'path': '/chuzu/?PGTID=0d200001-0000-11e9-58e6-a658f219b27c&ClickID=1',
'scheme': 'https',
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'zh-CN,zh;q=0.9',
'cache-control': 'max-age=0',
'cookie': 'f=n; commontopbar_new_city_info=1%7C%E5%8C%97%E4%BA%AC%7Cbj; commontopbar_ipcity=bj%7C%E5%8C%97%E4%BA%AC%7C0; userid360_xml=C0E9739B2022549506AFBC01231A1DAA; time_create=1606640420140; xxzl_cid=f4a781439d9247f393d0a1629bec00df; xzuid=e0e5ea78-ac5a-491b-819d-a869ab37a7a7; xxzl_deviceid=2G3xFS3qwOviMHxtC%2FVEituhpmiI%2FJ%2BAmJ08cPBulZSe7LcSgT98WgFcyNDbzMXJ; id58=c5/nfF+bz1xVS0tAA7tjAg==; 58tj_uuid=116f1ed0-7c25-477e-8887-be3602fa2389; new_uv=1; utm_source=; spm=; init_refer=https%253A%252F%252Fbj.58.com%252Fchuzu%252Fsub%252Fpn70%252F%253Fpagetype%253Dditie%2526PGTID%253D0d3090a7-0000-1b87-3e2e-c6efe8d19973%2526ClickID%253D2; wmda_uuid=13712f08f0e555f110b1b2684ce9d709; wmda_new_uuid=1; wmda_session_id_11187958619315=1604046685879-d3ad7e5f-77f6-29d7; wmda_visited_projects=%3B11187958619315; als=0; f=n; new_session=0',
'sec-fetch-dest': 'document',
'sec-fetch-mode': 'navigate',
'sec-fetch-site': 'none',
'sec-fetch-user': '?1',
'upgrade-insecure-requests': '1',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36'
}
response=requests.get(url=url, headers=headers)
return response.text
def get_font(data):
html=etree.HTML(data)
script=html.xpath('//script[2]/text()')[0]
ttf=re.findall(".*?src:url\(\'data:application/font-ttf;charset=utf-8;base64,(.*?)\'\).*?",script,re.S)[0]
with open('fangchan-secret.ttf','wb') as f:
f.write(base64.b64decode(ttf))
if __name__=='__main__':
data=get_data()
get_font(data)
import base64
from fontTools.ttLib import TTFont
import re
import requests
from lxml import etree
def get_data():
url="https://bj.58.com/chuzu/?PGTID=0d200001-0000-11e9-58e6-a658f219b27c&ClickID=1"
headers={
'authority': 'bj.58.com',
'method': 'GET',
'path': '/chuzu/?PGTID=0d200001-0000-11e9-58e6-a658f219b27c&ClickID=1',
'scheme': 'https',
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'zh-CN,zh;q=0.9',
'cache-control': 'max-age=0',
'cookie': 'f=n; commontopbar_new_city_info=1%7C%E5%8C%97%E4%BA%AC%7Cbj; commontopbar_ipcity=bj%7C%E5%8C%97%E4%BA%AC%7C0; userid360_xml=C0E9739B2022549506AFBC01231A1DAA; time_create=1606640420140; xxzl_cid=f4a781439d9247f393d0a1629bec00df; xzuid=e0e5ea78-ac5a-491b-819d-a869ab37a7a7; xxzl_deviceid=2G3xFS3qwOviMHxtC%2FVEituhpmiI%2FJ%2BAmJ08cPBulZSe7LcSgT98WgFcyNDbzMXJ; id58=c5/nfF+bz1xVS0tAA7tjAg==; 58tj_uuid=116f1ed0-7c25-477e-8887-be3602fa2389; new_uv=1; utm_source=; spm=; init_refer=https%253A%252F%252Fbj.58.com%252Fchuzu%252Fsub%252Fpn70%252F%253Fpagetype%253Dditie%2526PGTID%253D0d3090a7-0000-1b87-3e2e-c6efe8d19973%2526ClickID%253D2; wmda_uuid=13712f08f0e555f110b1b2684ce9d709; wmda_new_uuid=1; wmda_session_id_11187958619315=1604046685879-d3ad7e5f-77f6-29d7; wmda_visited_projects=%3B11187958619315; als=0; f=n; new_session=0',
'sec-fetch-dest': 'document',
'sec-fetch-mode': 'navigate',
'sec-fetch-site': 'none',
'sec-fetch-user': '?1',
'upgrade-insecure-requests': '1',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36'
}
response=requests.get(url=url, headers=headers)
return response.text
def get_font(data):
html=etree.HTML(data)
script=html.xpath('//script[2]/text()')[0]
ttf=re.findall(".*?src:url\(\'data:application/font-ttf;charset=utf-8;base64,(.*?)\'\).*?",script,re.S)[0]
with open('fangchan-secret.ttf','wb') as f:
f.write(base64.b64decode(ttf))
def parse_font():
font=TTFont('fangchan-secret.ttf')
bestcmap=font['cmap'].getBestCmap()
newmap=dict()
for key in bestcmap.keys():
value=int(re.search(r'(\d+)', bestcmap[key]).group(1)) - 1
key=hex(key)
newmap[key]=value
print(newmap)
if __name__=='__main__':
data=get_data()
get_font(data)
parse_font()
我们发现字体编号和之前的不符合,比如:0x9476=7,而这里的是2,这是什么原因呢?是因为他的字体是动态生成的,每次返回的数字编号对应的值都是不同的,但是不影响我们代码的正常运行与结果。
import base64
from fontTools.ttLib import TTFont
import re
import requests
from lxml import etree
def get_data():
url="https://bj.58.com/chuzu/?PGTID=0d200001-0000-11e9-58e6-a658f219b27c&ClickID=1"
headers={
'authority': 'bj.58.com',
'method': 'GET',
'path': '/chuzu/?PGTID=0d200001-0000-11e9-58e6-a658f219b27c&ClickID=1',
'scheme': 'https',
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'zh-CN,zh;q=0.9',
'cache-control': 'max-age=0',
'cookie': 'f=n; commontopbar_new_city_info=1%7C%E5%8C%97%E4%BA%AC%7Cbj; commontopbar_ipcity=bj%7C%E5%8C%97%E4%BA%AC%7C0; userid360_xml=C0E9739B2022549506AFBC01231A1DAA; time_create=1606640420140; xxzl_cid=f4a781439d9247f393d0a1629bec00df; xzuid=e0e5ea78-ac5a-491b-819d-a869ab37a7a7; xxzl_deviceid=2G3xFS3qwOviMHxtC%2FVEituhpmiI%2FJ%2BAmJ08cPBulZSe7LcSgT98WgFcyNDbzMXJ; id58=c5/nfF+bz1xVS0tAA7tjAg==; 58tj_uuid=116f1ed0-7c25-477e-8887-be3602fa2389; new_uv=1; utm_source=; spm=; init_refer=https%253A%252F%252Fbj.58.com%252Fchuzu%252Fsub%252Fpn70%252F%253Fpagetype%253Dditie%2526PGTID%253D0d3090a7-0000-1b87-3e2e-c6efe8d19973%2526ClickID%253D2; wmda_uuid=13712f08f0e555f110b1b2684ce9d709; wmda_new_uuid=1; wmda_session_id_11187958619315=1604046685879-d3ad7e5f-77f6-29d7; wmda_visited_projects=%3B11187958619315; als=0; f=n; new_session=0',
'sec-fetch-dest': 'document',
'sec-fetch-mode': 'navigate',
'sec-fetch-site': 'none',
'sec-fetch-user': '?1',
'upgrade-insecure-requests': '1',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36'
}
response=requests.get(url=url, headers=headers)
return response.text
def get_font(data):
html=etree.HTML(data)
script=html.xpath('//script[2]/text()')[0]
ttf=re.findall(".*?src:url\(\'data:application/font-ttf;charset=utf-8;base64,(.*?)\'\).*?",script,re.S)[0]
with open('fangchan-secret.ttf','wb') as f:
f.write(base64.b64decode(ttf))
def parse_font():
font=TTFont('fangchan-secret.ttf')
bestcmap=font['cmap'].getBestCmap()
newmap=dict()
for key in bestcmap.keys():
value=int(re.search(r'(\d+)', bestcmap[key]).group(1)) - 1
key=hex(key)
newmap[key]=value
return newmap
def parse_data(data,newmap):
for key,value in newmap.items():
key_=key.replace('0x','') + ';'
if key_ in data:
data=data.replace(key_,str(value))
html=etree.HTML(data)
house_list=html.xpath('//ul[@class="house-list"]/li')[:-1]
for house in house_list:
room=house.xpath('.//p[@class="room"]/text()')[0]
money=house.xpath('.//b[@class="strongbox"]/text()')[0]
print(room,money)
if __name__=='__main__':
data=get_data()
get_font(data)
newmap=parse_font()
parse_data(data,newmap)
源字节的租房小程序一个关于房屋租赁类的APP,用的uni-app实现 ,这种app少不了的就是经纪人,位置信息。我们的代码开源免费,欢迎交流使用。
map地图组件使用时直接在template中使用<map></map>标签,标签中可嵌套map属性
map最常用到的属性:
longitude 中心经度
latitude 中心纬度
scale 缩放级别(取值范围为5-18,默认的是16 ,值数越大,放大程度越大,看的越细)
markers 标记点 (类型为Array数组,在地图上标记出来的点)
polyline(类型为Array数组,没有默认值,表示路线,数组上的所有点连成线)
circles(类型Array数组,表示圆)
controls(类型Array数组,表示控件)
include-points(类型Array数组,表示缩放视野已包含所有给定的坐标点)
show-compass(类型为Boolean,默认值为false,表示为是否显示指南针)
enable-overlooking(类型为Boolean,默认值为false,表示为是否开启俯视)
enable-satellite(类型为Boolean,默认值为false,表示为是否开启卫星图)
enable-traffic(类型为Boolean,默认值为false,表示为是否开启实时路况)
show-location(类型为Boolean,表示显示带有方向的当前定位点)
polygons(类型Array,表示为多边形)
markers的属性有(表示标记点用于在地图上显示标记的位置)
id:标记点id(marker点击事件回调会返回此id)
latitude:纬度(范围 -90 ~ 90 )
longitude:经度(范围 -180 ~ 180 )
title:标注点名
iconPath:显示的图标
rotate:旋转角度(顺时针旋转的角度,范围 0 ~ 360,默认为 0 )
alpha:标注的透明度( 默认1,无透明,范围 0 ~ 1)
width:标注图标宽度(默认为图片实际宽度 )
height:标注图标高度(默认为图片实际高度 )
callout:自定义标记点上方的气泡窗口
label:为标记点旁边增加标签
anchor:经纬度在标注图标的锚点
callout的属性有
content:文本
color:文本颜色
fontSize:文字大小
borderRadius:callout边框圆角
bgColor:背景色
padding:文本边缘留白
display:BYCLICK':点击显示;'ALWAYS':常显
textAlign:文本对齐方式
label的属性有
content:文本
color:文本颜色
fontSize:文字大小
x:label的坐标,原点是 marker 对应的经纬度
y:label的坐标,原点是 marker 对应的经纬度
borderWidth:边框宽度
borderColor:边框颜色
borderRadius:callout边框圆角
bgColor:背景色
padding:文本边缘留白
textAlign:文本对齐方式
polyline的属性有(表示指定一系列坐标点,从数组第一项连线至最后一项)
points,经纬度数组,类型为Array,必填,如:[{latitude: 0, longitude: 0}]
color,线的颜色,类型为String,不必填,如:#0000AA
width,线的宽度,类型为Number,不必填
dottedLine,是否虚线,类型为Boolean,不必填,默认值false
arrowLine,带箭头的线,类型为Boolean,不必填,默认值为false
arrowIconPath,更换箭头图标,类型为String,不必填,在arrowLine为true时,默认带箭头的线时生效
borderColor,线的边框颜色,类型为String,不必填
borderWidth,线的厚度,类型为Number,不必填
circles 的属性有(在地图上显示圆)
latitude,纬度,Number,必填,浮点数,范围 -90 ~ 90
longitude,经度,Number,必填,浮点数,范围-180 ~ 180
color,描边的颜色,String,不必填,如:#0000AA
fillColor,填充颜色,String,不必填,如:#0000AA
radius,半径,Number,必填
strokeWidth,描边的宽度,Number,不必填
controls 控件 (在地图上显示一个控件,但是这个控件并不随着地图移动)
id:控件id(在控件点击事件回调会返回此id)
position:控件在地图的位置(控件相对地图位置)
iconPath:显示的图标(项目目录下的图片路径)
clickable:是否可点击(默认不可点击)
附上代码
<template>
<view>
<view>
<map :latitude="latitude" :longitude="longitude"
:markers="covers"
@click="clickMap">
</map>
</view>
</view>
</template>
<script>
export default {
data() {
return {
title: 'map',
name: '杭州市',
address: '杭州市拱墅区万达广场',
latitude: 30.31968,
longitude: 120.14209,
covers: [{
latitude: 30.31968,
longitude: 120.14209,
iconPath: '../../../static/location.png',
}]
}
},
methods:{
clickMap(e){
console.log(e);
uni.openLocation({
longitude: Number(this.longitude),
latitude: Number(this.latitude),
name: this.name,
address: this.address
})
},
}
}
</script>
<style>
map {
width: 100%;
height: 450rpx;
}
</style>
如若转载,请注明出处:开源字节 https://sourcebyte.cn/article/247.html
*请认真填写需求信息,我们会在24小时内与您取得联系。