整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

学习MVC之租房网站(十二)-缓存和静态页面

学习MVC之租房网站(十二)-缓存和静态页面

上一篇<学习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同城网站分析

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','&#x') + ';'
        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