Mandag's Blog

学会生活


  • 首页

  • 归档

  • 搜索

【JavaScript】wx.uploadFile多个文件上传

发表于 2017-07-15

今天写微信小程序时,用到 wx.uploadFile,用来上传图片资源信息
因为需要多个文件全部上传,都是uploadFile不支持多个连接同时进行
所以必须重新进行处理,使之可以自动处理多个文件

为了方便使用,可以先在javascript中对wx.uploadFile重新进行封装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// 上传文件
Tools.upload = function (ops) {
var fn = {
success: _empty,
fail: _empty,
complete: _empty
}
if (ops.success)
fn.success = ops.success
if (ops.fail)
fn.fail = ops.fail
if (ops.complete)
fn.complete = ops.complete
wx.uploadFile({
url: ops.url,
filePath: ops.filePath,
name: (ops.name == null || ops.name == "" || typeof (ops.name) == "undefined") ? 'file' : ops.name,
header: {
'Authorization': 'BasicAuth ' + wx.getStorageSync('token')
},
formData: (ops.formData == null || typeof (ops.formData) == "undefined") ? {} : ops.formData,
success: function (res) {
if (res.statusCode == 200) {
var _data = Tools.parseJSON(res.data)
if (_data.errcode == 0) {
fn.success(_data.data)
} else {
fn.fail(_data.message)
}
} else {
Tools.alert(res.data, 'error')
fn.fail(res.data.Message)
}
},
fail: function (res) {
fn.fail(res)
},
complete: function (res) {
fn.complete(res)
}
})
}

接着通过递归的方式在一个连接完成后,重新调用,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
uploadFile(files) {
if (!files || files.length <= 0) return
var that = this,
file = files[0]
files.splice(0, 1)
$.upload({
url: that.config.uploadFileUrl, // api地址
filePath: file.filePath, // 资源地址
name: 'uploadfile',
formData: {
source: file.source, // 来源信息
sourceId: file.sourceId // 来源ID
}, // 提交额外 formdata
success: function (res) {
// 提交成功...
},
complete: function (res) {
that.uploadFile(files)
}
})
}

服务端,接收代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[HttpPost]
[AllowAnonymous]
public AjaxResult UploadFile()
{
// 接收资源文件
HttpFileCollection hfc = HttpContext.Current.Request.Files;
// 接收formdata
string Source = HttpContext.Current.Request["source"];
string SourceId = HttpContext.Current.Request["sourceId"];
// 处理...
}

【Visual Studio】在Mac中调试虚拟机Visual Studio项目

发表于 2017-04-16

需要调试在Visual Studio中运行的基于Web的项目,但是要启动调试不用Windows上运行的Web浏览器…
而是用在Mac中调试..基于此,找了各种文章和博客文章后,终于搞定了。

配置Parallels设置

打开Parallels配置,单击[硬件]选项卡,然后选择[网络],将类型设置为“共享网络”。这允许OS X查看您的Windows虚拟机。
再单击[选项]选项卡,然后单击[应用程序],勾选“与Windows共享Mac应用程序”。

设置IIS站点

打开IIS,右击[网站]点击[添加网站]填写相关信息,并在[主机名]中填写 项目URL,如:mandag.local

将项目URL添加到Windows主机文件

打开Windows中Hosts文件,输入以下内容

1
127.0.0.1 mandag.local

将项目URL添加到OSX主机文件

打开OSX中Hosts文件,输入以下内容

1
192.168.1.76 mandag.local

在MAC打开mandag.local网址即可

參考網站:
Browser Debugging Between OS X and Visual Studio in Parallels
Accessing Your Windows Development Environment From OSX

【NET】设置SKU路径

发表于 2017-02-24

在做一个商城项目,之前并没有接触过,包括淘宝店铺

刚开始还有点没头绪,或者在SKU上相差了

商品有销售分类,类目,规格,属性

销售分类为商户自定义分类,可多选

类目为系统固定分类

规格为商品的规格,如,颜色,尺寸等

属性为商品的规格属性,如,红色,白色,黑色,均码等

在商品关联这项后,修改商品信息:

如修改XXX牌羊绒毛衣

根据类目=>规格=>属性

颜色:白色 黑色 红色 绿色 灰色 黄色 粉色 咖啡色

尺寸:XXS XS S M L XL XXL XXXL

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
var skuManage = {
template: {
thead: '<thead><th>序号</th><th>组合规格</th><th>库存数量</th><th>商品价格(元)</th></thead>',
tr: '<tr></tr>',
td: '<td></td>',
input: '<input type="text" class="form-control" />'
},
selected: {},
add2Selected: function (key, value) {
var arr = [];
if (this.selected[key]) {
this.selected[key].push(value);
} else {
this.selected[key] = [value];
}
},
pop2Selected: function (key, value) {
this.selected[key].splice($.inArray(value, this.selected[key]), 1);
},
addSymbols: function (skas, choices) {
var result = [];
for (var i = 0, len = skas.length; i < len; i++) {
for (var j = 0, lenj = choices.length; j < lenj; j++) {
result.push(skas[i] + ':' + choices[j]);
}
}
return result;
},
symbols: function (arrs) {
var skas = arrs[0];
for (var i = 1, len = arrs.length; i < len; i++) {
skas = this.addSymbols(skas, arrs[i]);
}
return skas;
},
drawPaths: function (o) {
if (this.count(this.selected) > 1) {
o.empty().append(this.template.thead);
var keys_arr = this.objToArr(this.selected);
var keys = this.symbols(keys_arr);
for (var i = 0, len = keys.length ; i < len; i++) {
var value = [];
$.each(keys[i].split(':'), function (index, elem) {
var _forVal = $("#pv-" + elem + "").next('label')[0];
value.push($(_forVal).html());
})
o.append($(this.template.tr)
.append($(this.template.td).append(i + 1))
.append($(this.template.td).append(value.join(',')))
.append($(this.template.td).append($(this.template.input).attr('type', 'number').attr('attr-pv', keys[i]).attr('attr-pvt', 'count')))
.append($(this.template.td).append($(this.template.input).attr('type', 'number').attr('attr-pv', keys[i]).attr('attr-pvt', 'price')))
);
}
}
},
count: function (o) {
var t = typeof o;
if (t == 'string') {
return o.length;
} else if (t == 'object') {
var n = 0;
for (var i in o) {
n++;
}
return n;
}
return false;
},
objToArr: function (o) {
var keys = [];
$.each(o, function (i, row) {
var key = [];
$.each(row, function (index, element) {
key.push(element);
})
keys.push(key);
})
return keys;
}
}
$('.sku').click(function () {
var $self = $(this);
if ($self.is(':checked')) {
skuManage.add2Selected($self.attr('attr_porid'), $self.attr('attr_valid'));
} else {
skuManage.pop2Selected($self.attr('attr_porid'), $self.attr('attr_valid'));
}
skuManage.drawPaths($skuTable)
});

通过在属性上绑定事件,使之保存选中项到数组,在重新生成表格,如

选中了 白色,黑色,红色,S,L,M

那么就出现了 白色-S,白色—L,白色-M,黑色-S,黑色—L,黑色-M,红色-S,红色—L,红色-M,这几种情况

填写相应对应的库存和价格

保存最终的一个结果

【NET】EF总结

发表于 2017-02-18

关于Entity Framework在MVC架构以及在项目中使用小结。

创建sqlproj项目

在项目中增加sqlproj项目,增加相关表或视图后,发布到数据库;

创建Entity项目

新建一个Entity项目,创建实体数据模型,会自动把发布的数据库表映射到实体类中;

Context类

创建一个在项目中可以通用的BaseDBContext类

1
2
3
4
5
6
7
8
9
10
11
12
public class BaseDBContext : DbContext
{
public BaseDBContext()
: base("name=HPDBEntities")
{
this.Configuration.AutoDetectChangesEnabled = false;
this.Configuration.ValidateOnSaveEnabled = false;
this.Configuration.LazyLoadingEnabled = false;
this.Configuration.ProxyCreationEnabled = false;
}
}

全局通用的操作类

有了Context类后,我们需要一个对全局通用的操作类EFHelper

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
public class EFHelper<TEntity> where TEntity : class
{
private BaseDBContext dbContext = new BaseDBContext();
public int Insert(TEntity entity)
{
dbContext.Entry<TEntity>(entity).State = EntityState.Added;
return dbContext.SaveChanges();
}
public int Insert(List<TEntity> entitys)
{
foreach (var entity in entitys)
{
dbContext.Entry<TEntity>(entity).State = EntityState.Added;
}
return dbContext.SaveChanges();
}
public int Update(TEntity entity)
{
dbContext.Set<TEntity>().Attach(entity);
PropertyInfo[] props = entity.GetType().GetProperties();
foreach (PropertyInfo prop in props)
{
if (prop.GetValue(entity, null) != null)
{
if (prop.GetValue(entity, null).ToString() == "&nbsp;")
dbContext.Entry(entity).Property(prop.Name).CurrentValue = null;
dbContext.Entry(entity).Property(prop.Name).IsModified = true;
}
}
return dbContext.SaveChanges();
}
public int Delete(TEntity entity)
{
dbContext.Set<TEntity>().Attach(entity);
dbContext.Entry<TEntity>(entity).State = EntityState.Deleted;
return dbContext.SaveChanges();
}
public int Delete(Expression<Func<TEntity, bool>> predicate)
{
var entitys = dbContext.Set<TEntity>().Where(predicate).ToList();
entitys.ForEach(m => dbContext.Entry<TEntity>(m).State = EntityState.Deleted);
return dbContext.SaveChanges();
}
public TEntity FindEntity(object keyValue)
{
return dbContext.Set<TEntity>().Find(keyValue);
}
public TEntity FindEntity(Expression<Func<TEntity, bool>> where)
{
return dbContext.Set<TEntity>().FirstOrDefault(where);
}
public List<TEntity> FindList()
{
return dbContext.Set<TEntity>().ToList<TEntity>();
}
public IQueryable<TEntity> IQueryable()
{
return dbContext.Set<TEntity>();
}
public IEnumerable<TEntity> IQueryable(Expression<Func<TEntity, bool>> where)
{
return dbContext.Set<TEntity>().Where(where);
}
public IEnumerable<TEntity> IQueryable<TKey>(Expression<Func<TEntity, TKey>> orderBy, Pagination pagination)
{
var tempData = dbContext.Set<TEntity>().AsQueryable();
if (!pagination.sort.IsEmpty() && pagination.sort.Equals("asc"))
{
tempData = tempData.OrderBy(orderBy);
}
else
{
tempData = tempData.OrderByDescending(orderBy);
}
pagination.records = tempData.Count();
tempData = tempData.Skip<TEntity>(pagination.offset).Take<TEntity>(pagination.rows).AsQueryable();
return tempData.ToList();
}
public IEnumerable<TEntity> IQueryable<TKey>(Expression<Func<TEntity, bool>> where, Expression<Func<TEntity, TKey>> orderBy, Pagination pagination)
{
var tempData = dbContext.Set<TEntity>().AsQueryable();
if (!pagination.sort.IsEmpty() && pagination.sort.Equals("asc"))
{
tempData = tempData.OrderBy(orderBy);
}
else
{
tempData = tempData.OrderByDescending(orderBy);
}
tempData = tempData.Where(where).AsQueryable();
pagination.records = tempData.Count();
tempData = tempData.Skip<TEntity>(pagination.offset).Take<TEntity>(pagination.rows).AsQueryable();
return tempData.ToList();
}
}

以上可以通用在整个项目的基本操作类

实际使用

创建了操作类后,就可以直接在项目中进行操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
private EFHelper<Entity.T_User> helper = new EFHelper<Entity.T_User>();
// 获取
var en = helper.FindEntity(id); // 主键直接获取
var en = helper.FindEntity(m => m.Name.Equals(name, StringComparison.OrdinalIgnoreCase)); // 不为主键进行linq进行where
// 新增
var en = new Entity.T_User() { Id = Guid.NewGuid(), Name = name };
helper.Insert(en);
// 修改
var result = helper.FindEntity(id);
if (result != null)
{
result.Name = name;
helper.Update(result);
};
// 删除
var result = helper.FindEntity(userId);
if (result != null)
{
helper.Delete(result);
};
// 查询
var list = helper.IQueryable(m => m.Name.Contains(keyword));

如果需要在复杂的地方进行操作,如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var query = helper.IQueryable(m => m.HasDelete.HasValue & !m.HasDelete.Value);
if (!keyword.IsEmpty())
{
query = query.Where(m => m.Name.Contains(keyword)).AsQueryable();
}
var tempData = query.OrderBy(m => m.Sorting).ToList()
.Join(helper_role.IQueryable(), m => m.RoleId, c => c.Id, (m, c) => new
{
m.Id,
m.Name
RoleId = c.Id
RoleName = c.Name
})
.AsQueryable();
pagination.records = tempData.Count();
var list = tempData.Limit(pagination);

如果,表连接或条件较复杂,推荐直接写视图,通过操作视图得到数据。

【NET】生成SiteMap网站地图

发表于 2017-02-12

之前没有用过sitemap,最近做项目接触到sitemap,做下记录

生成如下XML格式文件

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="utf-8"?>
<urlset>
<url>
<loc>URL地址</loc>
<lastmod>最新修改日期</lastmod>
<changefreq>更新频率</changefreq>
<priority>权重</priority>
</url>
</urlset>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/// <summary>
/// 初始化站点列表
/// </summary>
/// <param name="list"></param>
public static void CreateSiteXml(Dictionary<Guid, string> list)
{
XmlDocument doc = null;
XmlElement root = null;
int allCount = list.Count;
// 网址不得超过 5 万个,且文件大小不得超过 10 MB
const int siteCountFile = 30000;
int createMod = allCount / siteCountFile + (allCount % siteCountFile > 0 ? 1 : 0);
// 循环创建XML
for (int i = 1; i <= createMod; i++)
{
doc = new XmlDocument();
XmlDeclaration dec = doc.CreateXmlDeclaration("1.0", "utf-8", null);
doc.AppendChild(dec);
root = doc.CreateElement("urlset");
int currMod = 0;
// 循环添加URL
foreach (var item in list.Skip((i - 1) * siteCountFile))
{
if (currMod < siteCountFile)
{
// 链接地址,长度不得超过256字节
XmlElement url = doc.CreateElement("url");
XmlElement url_loc = doc.CreateElement("loc");
url_loc.InnerText = item.Value.ToLower();
url.AppendChild(url_loc);
// 链接的最后更新时间
XmlElement url_lastmod = doc.CreateElement("lastmod");
url_lastmod.InnerText = DateTime.Now.ToString("yyyy-MM-dd");
url.AppendChild(url_lastmod);
// 链接可能会出现的更新频率
XmlElement url_changefreq = doc.CreateElement("changefreq");
url_changefreq.InnerText = "daily";
url.AppendChild(url_changefreq);
// 链接的优先权比值,此值定于0.0-1.0之间
XmlElement url_priority = doc.CreateElement("priority");
url_priority.InnerText = "0.8";
url.AppendChild(url_priority);
root.AppendChild(url);
}
currMod++;
}
doc.AppendChild(root);
// 保存XML
string SiteMapDir = System.Web.HttpContext.Current.Server.MapPath("/SiteMap/sitemap");
string fullFileName = SiteMapDir + string.Format("{0:d5}", i) + ".xml";
doc.Save(fullFileName);
}
}
/// <summary>
/// 插入
/// </summary>
/// <param name="str"></param>
public static void InsertSiteXml(string str)
{
if (string.IsNullOrWhiteSpace(str))
return;
const int siteCountFile = 30000;
string SiteMapDir = System.Web.HttpContext.Current.Server.MapPath("/SiteMap/");
string[] file = Directory.GetFiles(SiteMapDir);
for (int i = 1; i < file.Length; i++)
{
XmlDocument xml = new XmlDocument();
try
{
xml.Load(file[i]);
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
XmlNodeList xmlNodes = xml.SelectNodes("/urlset/url");
if (xmlNodes.Count < siteCountFile)
{
XmlNode _root = xml.SelectSingleNode("/urlset");
XmlNode _url = xml.CreateElement("url");
XmlNode _url_loc = xml.CreateElement("loc");
_url_loc.InnerText = str.Trim().ToLower();
_url.AppendChild(_url_loc);
_root.AppendChild(_url);
xml.Save(file[i]);
return;
}
}
XmlDocument doc = new XmlDocument();
XmlDeclaration dec = doc.CreateXmlDeclaration("1.0", "utf-8", null);
doc.AppendChild(dec);
XmlElement root = doc.CreateElement("urlset");
XmlElement url = doc.CreateElement("url");
XmlElement url_loc = doc.CreateElement("loc");
url_loc.InnerText = str.Trim().ToLower();
url.AppendChild(url_loc);
root.AppendChild(url);
doc.AppendChild(root);
// 保存XML
string fullFileName = SiteMapDir + string.Format("sitemap{0:d5}", file.Count()) + ".xml";
doc.Save(fullFileName);
}
/// <summary>
/// 删除
/// </summary>
/// <param name="str"></param>
public static void DeleteSiteXml(string str)
{
if (string.IsNullOrWhiteSpace(str))
return;
string SiteMapDir = System.Web.HttpContext.Current.Server.MapPath("/SiteMap/");
string[] file = Directory.GetFiles(SiteMapDir);
for (int i = 0; i < file.Length; i++)
{
XmlDocument xml = new XmlDocument();
try
{
xml.Load(file[i]);
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
XmlNodeList xmlNodes = xml.SelectNodes("/urlset/url");
for (int k = 0; k < xmlNodes.Count; k++)
{
XmlNode node = xmlNodes[k];
string text = node.FirstChild.InnerText;
if (text.Equals(str.Trim(), StringComparison.OrdinalIgnoreCase))
{
XmlNode _root = xml.SelectSingleNode("/urlset");
_root.RemoveChild(node);
xml.Save(file[i]);
return;
}
}
}
}

【NET】使用结巴分词检索

发表于 2016-12-12

结巴分词的源码:jieba中文分词

在一個检索系统中,使用了结巴分词来进行分词检索,感觉很方便。

首先,把结巴分词的词库写入到数据库中,用来判断检索的关键字是否为新词,
如果新词的话,就直接like整篇文章,再保存检索关键字到词库和分词表中;
不是的话,就在分词表中进行搜索,这样检索速度就增加了,也不会出现检索不到词的问题。

接在修改结巴分词的源码

修改加载词库的方法:WordDictionary.cs中LoadDict的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
private void LoadDict()
{
try
{
var stopWatch = new Stopwatch();
stopWatch.Start();
// 从SQL中读取数据
DBEntities db = new DBEntities();
var dt = db.ThesaurusList().ToList();
if (dt != null && dt.Any())
{
foreach (var item in dt)
{
var word = e.Convert.ToString(item.Text);
int freq = 0;
if (item.Frequency.HasValue)
freq = item.Frequency.Value;
Trie[word] = freq;
Total += freq;
foreach (var ch in Enumerable.Range(0, word.Length))
{
var wfrag = word.Sub(0, ch + 1);
if (!Trie.ContainsKey(wfrag))
{
Trie[wfrag] = 0;
}
}
}
}
stopWatch.Stop();
Debug.WriteLine("main dict load finished, time elapsed {0} ms", stopWatch.ElapsedMilliseconds);
}
catch (IOException e)
{
Debug.Fail(string.Format("{0} load failure, reason: {1}", MainDict, e.Message));
}
catch (FormatException fe)
{
Debug.Fail(fe.Message);
}
}

增加添加新词的方法

1
2
3
4
5
6
7
8
public void SqlDtAdd(string word, int freq, string tag = null)
{
if (!ContainsWord(word))
{
DBEntities db = new DBEntities();
db.ThesaurusAdd(word, tag, freq);
}
}

增加接口调用的方法:在JiebaSegmenter.cs中增加以下两个方法,用于判断分词是否存在并添加新词

1
2
3
4
5
6
7
8
9
10
public void SqlDtAdd(string word, int freq = 0, string tag = null)
{
WordDict.SqlDtAdd(word, freq, tag);
AddWord(word, freq, tag);
}
public bool SqlDtContainsWord(string text)
{
return WordDict.ContainsWord(text);
}

【NET】网站数据爬取 上

发表于 2016-12-10

接昨天的

采集内容页,要考虑两点,一个是是否需要登录才能浏览,还有一個是有些网站有限制流量的,超过了就看不了
所以需要存着网站的cookie和当前采集的次数

1
2
3
4
5
6
7
8
9
10
11
12
Dictionary<string, long> siteTakeCount = new Dictionary<string, long>();
Dictionary<string, System.Net.CookieContainer> siteTakeCookie = new Dictionary<string, System.Net.CookieContainer>();
var result = DataHandled.GetStayTakeTask();
if (ConfigManager.CollectTasks != null && ConfigManager.CollectTasks.Any())
{
foreach (var item in ConfigManager.CollectTasks)
{
long count = item.PageContent.CollectCountMax > 0 ? item.PageContent.CollectCountMax : -1;
siteTakeCount.Add(item.TaskName, count);
siteTakeCookie.Add(item.TaskName, null);
}
}

初始化采集次数和cookie后,内容页就简单了,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
string enc = task.PageContent.PageEncode;
if (string.IsNullOrWhiteSpace(enc))
enc = task.DefaultEncode;
if (task.HasCookie && siteTakeCookie[task.TaskName] == null)
siteTakeCookie[task.TaskName] = RequestManager.GetCooKie(task.CheckLogin.LoginUrl, task.CheckLogin.LoginData);
var content = RequestManager.GetPage(item.Location, enc, siteTakeCookie[task.TaskName]);
if (!string.IsNullOrWhiteSpace(content))
{
bool flag = true;
if (task.HasCookie && content.IndexOf(task.CheckLogin.LoginMark) < 0)
{
flag = false;
siteTakeCount[task.TaskName] = 0;
continue;
}
if (task.PageContent.IsSaveAsFile)
{
// 保存到本地
}
if (task.PageContent.IsSaveDataBase)
{
// 写入数据库
}
if (flag)
{
// 更新状态,显示已采集
}
}
else
{
SetLogInfo(string.Format("【{0}】-【{1}】无法获取到页面内容,地址:{2}", item.TaskName, item.Title, item.Location), LogType.Logger, LogLevelType.Error);
}

这样子就ok了,再写两个线程,一个用来采集站点,一个用来下载页面信息

1
2
3
4
5
6
7
8
9
10
11
takeTaskThread = new Thread(new ThreadStart(GetStayUrlList));
takeTaskThread.IsBackground = true;
takeTaskThread.Name = "采集地址线程";
takeTaskThread.Priority = ThreadPriority.Normal;
takeTaskThread.Start();
takeSaveThread = new Thread(new ThreadStart(GetStayPageList));
takeSaveThread.IsBackground = true;
takeSaveThread.Name = "下载页面线程";
takeSaveThread.Priority = ThreadPriority.BelowNormal;
takeSaveThread.Start();

程序运行之后,因为配置文件或其他问题,主界面会出現挂掉的问题,
这个时候就需要在程序运行前,检查下一些配置文件等,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
public bool InitFormProgramRunStatus()
{
SetLogInfo("正在扫描程序配置情况,请稍等~", LogType.Logger, LogLevelType.Debug);
// 数据库配置情况
if (!DataHandled.ConnectionTest())
{
SetLogInfo("数据库连接不正确,请先设置数据连接!", LogType.Logger, LogLevelType.Fatal);
return false;
}
// 采集文件配置情况
if (string.IsNullOrWhiteSpace(ConfigManager.TaskConfigPath))
{
SetLogInfo("采集站点配置文件路径错误!", LogType.Logger, LogLevelType.Fatal);
return false;
}
string[] files = System.IO.Directory.GetFiles(ConfigManager.TaskConfigPath, "*.xml");
if (files.Count() <= 0x0)
{
SetLogInfo("未找到采集站点配置文件!", LogType.Logger, LogLevelType.Fatal);
return false;
}
ConfigManager.CollectTasks = new List<Task>();
string errFile = string.Empty;
try
{
foreach (string file in files)
{
errFile = file;
Task t = XmlHelper.XmlDeserializeFromFile<Task>(file, Encoding.UTF8);
ConfigManager.CollectTasks.Add(t);
}
}
catch (Exception ex)
{
SetLogInfo(string.Format("采集站点的配置文件序列化失败!错误文件:{0},错误代码:{1}", errFile, ex.Message), LogType.Logger, LogLevelType.Fatal);
return false;
}
// 下载文件配置情况
try
{
if (string.IsNullOrWhiteSpace(ConfigManager.SaveFilePath()) || !System.IO.Directory.Exists(ConfigManager.SaveFilePath()))
{
SetLogInfo("文件保存路径未找到,或路径配置错误!", LogType.Logger, LogLevelType.Fatal);
return false;
}
}
catch (Exception ex)
{
SetLogInfo("文件保存路径未找到,或路径配置错误!", LogType.Logger, LogLevelType.Fatal);
return false;
}
SetLogInfo("扫描成功~", LogType.Logger, LogLevelType.Debug);
return true;
}

【NET】网站数据爬取 上

发表于 2016-12-09

最近因为工作需要,写了个采集网站数据的小程序。
主要功能是首先采集网站列表頁的链接存入数据库(需要排除重复采集的可能),第一次,采集全部,之后只采集最新数据,接着,获取采集到的链接地址,保存页面信息。

程序的主要爬取的数据有两部分,一个是列表的链接,一个是内容页的内容

首先采集网站不可避免的会用到正则表达式,所以就需要在XML中配置每个站点的相关采集信息和正则匹配内容等
XML模板文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
<?xml version="1.0" encoding="utf-8"?>
<Task>
<!-- 任务名称 -->
<TaskName>Mandag's Blog</TaskName>
<!-- 任务网站 -->
<TaskHost>http://mungyulin.github.io/</TaskHost>
<!-- 采集模式 列表(LIST)或逐页(PAGE) -->
<!-- 列表对应PageList -->
<!-- 逐页对应StartUrl -->
<CollectModel>LIST</CollectModel>
<!-- 列表页面编码 -->
<DefaultEncode>utf-8</DefaultEncode>
<!-- 请求方式 POST和GET -->
<RequestMethod>POST</RequestMethod>
<!-- 是否需要登录 -->
<HasCookie>false</HasCookie>
<ListPage>
<!-- 提取分页的总记录(Groups["totalRecord"])和总页数(Groups["totalPage"]) -->
<TotalPageRegex></TotalPageRegex>
<!-- 计算分页的标识 记录计算(Record)和分页获取(Page) -->
<TotalPageMark>Record</TotalPageMark>
<!-- 分页数据结果匹配正则 -->
<ContentResultRegex></ContentResultRegex>
<!-- 提取采集链接(Groups["url"])和标题(Groups["text"]) -->
<ListPageUrlRegex></ListPageUrlRegex>
</ListPage>
<CheckLogin>
<!-- 登陆页地址 -->
<LoginUrl></LoginUrl>
<!-- 登陆账户提交表单 -->
<LoginData></LoginData>
<!-- 登陆成功,采集内容的标识 -->
<LoginMark></LoginMark>
</CheckLogin>
<PageContent>
<!-- 内容页面编码 -->
<PageEncode>utf-8</PageEncode>
<!-- 每次采集上限 大于0时,超过次数,自动停止 -->
<CollectCountMax>0</CollectCountMax>
<!-- 是否保存为文件 -->
<IsSaveAsFile>true</IsSaveAsFile>
<!-- 是否保存到数据库 -->
<IsSaveDataBase>true</IsSaveDataBase>
<!-- 页面标题正则 -->
<PageTitleRegex></PageTitleRegex>
<!-- 页面内容正则 -->
<PageContentRegex></PageContentRegex>
<!-- 页面其他信息正则 -->
<PageInfoRegex></PageInfoRegex>
</PageContent>
<Item>
<Title>某某分類</Title>
<!-- 是否跳过采集 -->
<NotCollect>false</NotCollect>
<!-- 重置采集 -->
<ResetCollect>false</ResetCollect>
<!-- 采集地址 -->
<Location></Location>
<!-- 列表地址 -->
<PageList>http://mungyulin.github.io/archive?{limit}&amp;{currentPage}</PageList>
<!-- 地址参数 -->
<Parameters limit='100' currentPage='1' />
<!-- 表单数据 -->
<FormDate></FormDate>
</Item>
</Task>

配置文件搞定后,就是解析列表页的链接,把每一页的链接取出來,
读取一个配置文件,获取需要采集的站点信息,
首先是获取这个站点列表页的初始页面,可以得到总记录数和总页数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
string page = string.Empty;
Regex regex = null;
if (!string.IsNullOrWhiteSpace(linkItem.ListPage.TotalPageRegex))
regex = new Regex(linkItem.ListPage.TotalPageRegex, RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.IgnorePatternWhitespace);
if (linkItem.CollectModel.Equals("List", StringComparison.OrdinalIgnoreCase))
{
// 地址栏带起始记录数进行获取列表数据
if (linkItem.ListPage.TotalPageMark.Equals("Record", StringComparison.OrdinalIgnoreCase))
{
if (linkItem.RequestMethod.Equals("Post", StringComparison.OrdinalIgnoreCase))
page = RequestManager.RequestData(ParaFormat(item.PageList, item.Parameters), item.FormDate, linkItem.DefaultEncode);
else
page = RequestManager.GetPage(ParaFormat(item.PageList, item.Parameters), linkItem.DefaultEncode);
}
// 地址栏带页数进行获取列表数据
else if (linkItem.ListPage.TotalPageMark.Equals("Page", StringComparison.OrdinalIgnoreCase))
{
if (linkItem.RequestMethod.Equals("Post", StringComparison.OrdinalIgnoreCase))
page = RequestManager.RequestData(ParaFormat(item.PageList, item.Parameters), item.FormDate, linkItem.DefaultEncode);
else
page = RequestManager.GetPage(ParaFormat(item.PageList, item.Parameters), linkItem.DefaultEncode);
}
// 使用表单提交获取列表数据
else if (linkItem.ListPage.TotalPageMark.Equals("Form", StringComparison.OrdinalIgnoreCase))
{
if (linkItem.RequestMethod.Equals("Post", StringComparison.OrdinalIgnoreCase))
page = RequestManager.RequestData(item.PageList, ParaFormat(item.FormDate, item.Parameters), linkItem.DefaultEncode);
}
}

得到了总记录数和总页数后,就可以模拟翻页,获取列表链接了,
目前网络上的网站列表显示有两种(我只知道两种,不知道的我就不管了╮(╯_╰)╭ )
一种是静态生成,就是一个页面就是一个HTML文件
还有一种是动态的,比如通过AJAX获取部分数据并刷新局部页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// 静态页面 只需考虑页面有列表的情况,沒列表就可以跳出來了
string location = item.Location;
int isCount = 1;
while (isCount != 0)
{
page = RequestManager.GetPage(location, linkItem.DefaultEncode);
string text = string.Empty;
if (string.IsNullOrWhiteSpace(page))
{
isCount = 0;
break;
}
if (!string.IsNullOrWhiteSpace(linkItem.ListPage.ContentResultRegex))
{
var pageRegex = new Regex(linkItem.ListPage.ContentResultRegex, RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.IgnorePatternWhitespace);
Match pageMatch = pageRegex.Match(page);
text = pageMatch.Value;
}
SetLogInfo(string.Format("正在采集【{0}】-【{1}】 {2}", linkItem.TaskName, item.Title, location), LogType.StayTakeSite);
var list = UrlManager.UrlParse(text, item.Location, linkItem.ListPage.ListPageUrlRegex);
if (list != null && list.Any())
{
foreach (var url in list)
{
// 这里添加到数据库
}
location = string.Format(item.StartUrl, isCount);
isCount++;
}
else
isCount = 0;
}
// 动态页面 一定要有总页数
page = page.Replace("&nbsp;", " ");
Match match = regex.Match(page);
if (match.Groups["totalRecord"].Success)
{
item.Parameters.TotalRecord = e.Convert.ToInt(match.Groups["totalRecord"].Value);
}
if (match.Groups["totalPage"].Success)
{
item.Parameters.TotalPage = e.Convert.ToInt(match.Groups["totalPage"].Value);
}
if(match.Groups["totalRecord"].Success && !match.Groups["totalPage"].Success)
{
// 计算总页数
if (item.Parameters.Limit != 0x0)
{
item.Parameters.TotalPage = item.Parameters.TotalRecord / item.Parameters.Limit;
}
else
{
SetLogInfo(string.Format("【{0}】-【{1}】{2}", linkItem.TaskName, item.Title, "缺少每页数量的值,无法进行处理!"), LogType.Logger, LogLevelType.Error);
continue;
}
}
// 通过总页数模拟翻页
item.Parameters.CurrentPage = 1;
while (item.Parameters.CurrentPage <= item.Parameters.TotalPage)
{
string location = string.Empty;
Regex textRegex = null;
if (!string.IsNullOrWhiteSpace(linkItem.ListPage.ContentResultRegex))
textRegex = new Regex(linkItem.ListPage.ContentResultRegex, RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.IgnorePatternWhitespace);
if (linkItem.CollectModel.Equals("List", StringComparison.OrdinalIgnoreCase))
{
if (linkItem.ListPage.TotalPageMark.Equals("Record", StringComparison.OrdinalIgnoreCase))
{
// 计算数据的起始记录
item.Parameters.StartNumber = item.Parameters.Limit * (item.Parameters.CurrentPage - 1) + 1;
item.Parameters.EndNumber = item.Parameters.Limit * item.Parameters.CurrentPage;
if (item.Parameters.EndNumber > item.Parameters.TotalRecord)
item.Parameters.EndNumber = item.Parameters.TotalRecord;
location = ParaFormat(item.PageList, item.Parameters);
}
else if (linkItem.ListPage.TotalPageMark.Equals("Page", StringComparison.OrdinalIgnoreCase))
{
location = ParaFormat(item.PageList, item.Parameters);
}
else
{
location = item.PageList;
}
}
if (!string.IsNullOrWhiteSpace(location))
{
SetLogInfo(string.Format("正在采集【{0}】-【{1}】共{2}页/第{3}页 {4}", linkItem.TaskName, item.Title, item.Parameters.TotalPage, item.Parameters.CurrentPage, location), LogType.StayTakeSite);
string text = string.Empty;
// 配置文件中,未配置表单数据
// 该站点则为GET进行获取
// 否则为POST提交表单数据进行获取
if (linkItem.RequestMethod.Equals("Post", StringComparison.OrdinalIgnoreCase))
{
if (linkItem.ListPage.TotalPageMark.Equals("Record", StringComparison.OrdinalIgnoreCase))
{
text = RequestManager.RequestData(location, item.FormDate, linkItem.DefaultEncode);
}
else
{
text = RequestManager.RequestData(location, ParaFormat(item.FormDate, item.Parameters), linkItem.DefaultEncode);
}
}
else
{
text = RequestManager.GetPage(location, linkItem.DefaultEncode);
}
if (!string.IsNullOrWhiteSpace(text))
{
// 得到筛选A标签的部分文本内容
if (textRegex != null)
{
MatchCollection textMatch = textRegex.Matches(text);
text = string.Empty;
foreach (Match mc in textMatch)
{
text += mc.Value;
}
}
// 得到待采集站点列表
var list = UrlManager.UrlParse(text, item.Location, linkItem.ListPage.ListPageUrlRegex);
if (list != null && list.Any())
{
foreach (var url in list)
{
//這裏添加到数据库
}
}
else
{
SetLogInfo(string.Format("【{0}】-【{1}】共{2}页/第{3}页 未提取到a标签!", linkItem.TaskName, item.Title, item.Parameters.TotalPage, item.Parameters.CurrentPage), LogType.Logger, LogLevelType.Warn);
}
}
else
{
SetLogInfo(string.Format("【{0}】-【{1}】共{2}页/第{3}页 未读取到数据,无法进行数据采集!", linkItem.TaskName, item.Title, item.Parameters.TotalPage, item.Parameters.CurrentPage), LogType.Logger, LogLevelType.Error);
continue;
}
}
else
{
SetLogInfo(string.Format("正在采集【{0}】-【{1}】共{2}页/第{3}页 采集地址未定义!", linkItem.TaskName, item.Title, item.Parameters.TotalPage, item.Parameters.CurrentPage), LogType.Logger, LogLevelType.Warn);
continue;
}
if (item.Parameters.CurrentPage != int.MaxValue)
item.Parameters.CurrentPage++;
}

地址采集的OK了,内容页的明天贴。

【Python】Python简单数据爬取

发表于 2016-07-21

这段时间再看《黑客軍團》,就稍稍的翻了下 知道创宇研发技能表,太复杂,不过还是学习了下Python,

恩,并且学习着写了个简单的抓取网站图片的小程序。

爬取的网站是:http://www.22mm.cc/


以下使用的是Python2.7版本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# 程序主要入口
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import url_manager, pic_downloader, pic_outputer, pic_parser
class SpiderMain:
def __init__(self):
self.urls = url_manager.UrlManager()
self.parser = pic_parser.HtmlParser()
self.outputer = pic_outputer.HtmlOutputer()
def getPage(self, url):
if url is None:
return None
response = urllib2.urlopen(url)
if response.getcode() != 200:
return None
return response.read()
def craw(self, root_url):
self.urls.add_new_url(root_url)
while self.urls.has_new_url():
try:
new_url = self.urls.get_new_url()
html_cont = self.getPage(new_url)
new_urls, new_data = self.parser.parse(new_url, html_cont)
self.urls.add_new_urls(new_urls)
self.outputer.collect_data(new_data)
except:
print 'craw failed'
self.outputer.output_html()
if __name__ == "__main__":
root_url = "http://www.22mm.cc/"
obj_spider = SpiderMain()
obj_spider.craw(root_url)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# Url管理器
#!/usr/bin/env python2
# -*- coding: UTF-8 -*-
class UrlManager(object):
def __init__(self):
self.new_urls = set()
self.old_urls = set()
def add_new_url(self, url):
if url is None:
return
if url not in self.new_urls and url not in self.old_urls:
self.new_urls.add(url)
def add_new_urls(self, urls):
if urls is None or len(urls) == 0:
return
for url in urls:
self.add_new_url(url)
def has_new_url(self):
return len(self.new_urls) != 0
def get_new_url(self):
new_url = self.new_urls.pop()
self.old_urls.add(new_url)
return new_url
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# Html解析器
#!/usr/bin/env python2
# -*- coding: UTF-8 -*-
import re, urlparse
from bs4 import BeautifulSoup
class HtmlParser(object):
def parse(self, page_url, html_cont):
if page_url is None or html_cont is None:
return
soup = BeautifulSoup(html_cont, 'html.parser', from_encoding='utf-8')
new_urls = self._get_new_urls(page_url, soup)
new_data = self._get_new_data(page_url, soup)
return new_urls, new_data
def _get_new_urls(self, page_url, soup):
new_urls = set()
links = soup.find_all('a', href = re.compile(r"/mm/(.*?)/(.*?).html"))
for link in links:
new_url = link['href']
new_full_url = new_url
if "http://" not in new_url:
new_full_url = urlparse.urljoin(page_url, new_url)
new_urls.add(new_full_url)
return new_urls
def _get_new_data(self, page_url, soup):
res_data = {}
new_str_url = page_url.replace('/','').replace('http:','').replace('https:','')
res_data['url'] = new_str_url
res_data['img'] = {}
image_list = soup.find_all('img', src = re.compile(r"(.*?)\.jpg"))
for item in image_list:
res_data['img'][item['src']] = item['src'].split('/')[-1]
return res_data
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# HtmL生成器
#!/usr/bin/env python2
# -*- coding: UTF-8 -*-
import sys, os, urllib
class HtmlOutputer(object):
def __init__(self):
reload(sys)
sys.setdefaultencoding('utf8')
self.datas = []
def saveImg(self, imageURL, fileName):
imageData = urllib.urlopen(imageURL).read()
f = open(fileName, 'wb')
f.write(imageData)
print u"正在保存图片:", fileName
f.close()
def mkdir(self, path):
path = path.strip()
isExists = os.path.exists(path)
if not isExists:
print u"新建了", path, u'文件夹'
os.makedirs(path)
return True
else:
print u"名为", path, '的文件夹已经创建成功'
return False
def collect_data(self, data):
if data is None:
return
self.datas.append(data)
def output_html(self):
fout = open('output.html', 'w')
fout.write("<html>")
fout.write("<body>")
fout.write("<table border='1' cellspacing='0' bordercolor='#666666' style='border-collapse: collapse;'>")
fout.write("<tr><th>Url</th><th>Images</th><th>Name</th></tr>")
for data in self.datas:
for key, value in data['img'].items():
fout.write("<tr>")
fout.write("<td>%s</td>" % data['url'])
fout.write("<td>")
fout.write("<img src='%s'>" % key.encode('utf-8'))
fout.write("</td>")
fout.write("<td>%s</td>" % value.encode('utf-8'))
fout.write("</tr>")
self.mkdir(data['url'])
self.saveImg(key, data['url'] + u"/" + value)
fout.write("</table>")
fout.write("</body>")
fout.write("</html>")
fout.close()

参考网站:
Python 2.7教程
Python 爬虫学习系列教程
Python开发简单爬虫

【JQuery】使用JvectorMap进行足迹设置

发表于 2016-07-06

JvectorMap是一款基于jquery的地图插件,官网是 jvectormap.com

下面简单的试用了下这款插件,并用它设置我的足迹信息。
我的足迹

首先引用JS文件

1
2
3
4
5
6
// 注意引用顺序
<link rel="stylesheet" type="text/css" href="/dist/jquery-jvectormap/jquery-jvectormap-2.0.3.css">
<script type="text/javascript" src="/dist/jquery-3.0.0.min.js"></script>
<script type="text/javascript" src="/dist/jquery-jvectormap/jquery-jvectormap-2.0.3.min.js"></script>
// 官网上下载的中国配置文件
<script type="text/javascript" src="/dist/jquery-jvectormap/jquery-jvectormap-cn-merc.js"></script>

增加框架

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<style type="text/css">
.map-container {
width: 800px;
height: 600px;
}
// 隐藏地图左上角 + — 按钮
.jvectormap-zoomin,
.jvectormap-zoomout {
display: none;
}
</style>
<div id="maps">
<div class="map-container"></div>
</div>

调用插件,初始化并设置相关信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
var mapdata = [ // 使配置文件的地图信息显示中文名称
{ id: "CN-32", province: "江苏", data: "Jiangsu" },
{ id: "CN-52", province: "贵州", data: "Guizhou" },
{ id: "CN-53", province: "云南", data: "Yunnan" },
{ id: "CN-50", province: "重庆", data: "Chongqing" },
{ id: "CN-51", province: "四川", data: "Sichuan" },
{ id: "CN-31", province: "上海", data: "Shanghai" },
{ id: "CN-54", province: "西藏", data: "Xizang" },
{ id: "CN-33", province: "浙江", data: "Zhejiang" },
{ id: "CN-15", province: "内蒙古", data: "Inner Mongol" },
{ id: "CN-14", province: "山西", data: "Shanxi" },
{ id: "CN-", province: "福建", data: "Fujian" },
{ id: "CN-12", province: "天津", data: "Tianjin" },
{ id: "CN-13", province: "河北", data: "Hebei" },
{ id: "CN-11", province: "北京", data: "Beijing" },
{ id: "CN-34", province: "安徽", data: "Anhui" },
{ id: "CN-36", province: "江西", data: "Jiangxi" },
{ id: "CN-37", province: "山东", data: "Shandong" },
{ id: "CN-41", province: "河南", data: "Henan" },
{ id: "CN-43", province: "湖南", data: "Hunan" },
{ id: "CN-42", province: "湖北", data: "Hubei" },
{ id: "CN-45", province: "广西", data: "Guangxi" },
{ id: "CN-44", province: "广东", data: "Guangdong" },
{ id: "CN-46", province: "海南", data: "Hainan" },
{ id: "CN-65", province: "新疆", data: "Xinjiang" },
{ id: "CN-64", province: "宁夏", data: "Ningxia" },
{ id: "CN-63", province: "青海", data: "Qinghai" },
{ id: "CN-62", province: "甘肃", data: "Gansu" },
{ id: "CN-61", province: "山西", data: "Shaanxi" },
{ id: "CN-23", province: "黑龙江", data: "Heilongjiang" },
{ id: "CN-22", province: "吉林", data: "Jilin" },
{ id: "CN-21", province: "辽宁", data: "Liaoning" },
{ id: "CN-18", province: "台湾", data: "Taiwan" },
{ id: "CN-19", province: "钓鱼岛", data: "DiaoyuIslands" },
{ id: "MAC", province: "澳门", data: "Macao" },
{ id: "HKG", province: "香港", data: "Hongkong" }
],
markers = [ // 给地图添加标记
{ latLng: [29.92, 95.75], name: '西藏 - 波密 2014' },
...
],
names = {};
$.each(mapdata, function (index, item) {
names[item.id] = item.province;
});
$('.map-container').vectorMap({
map: 'cn_merc',
backgroundColor: '#fff', // 地图背景色
zoomAnimate: false,
zoomOnScroll: false, // 是否可以使用鼠标滚轮缩放地图
regionsSelectable: true, // 区域是否可以被选中
regionsSelectableOne: false,
regionStyle: { // 设置区域样式
initial: { // 初始状态
fill: "#58D3F7",
"fill-opacity": 1,
stroke: 'none',
"stroke-width": 0,
"stroke-opacity": 1
},
hover: { // 当鼠标经过时的状态
fill: "#0080FF"
},
selected: { // 被选中的状态
fill: "#00BFFF"
},
selectedHover: { // 当被选中之后鼠标经过的状态
}
},
markers: markers, // 初始化标记
markerStyle: { // 设置地图标记的样式
initial: {
fill: '#FFBF00'
},
hover: {
},
selected: {
fill: '#FA5858'
},
selectedHover: {
}
},
labels: {
regions: {
render: function(code) {
return names[code];
}
}
},
// 区域标签展开时执行事件
onRegionTipShow: function(event, label, code) {
label.html(names[code]); // 返回标签内容
}
});

參考網站:
Jvectormap中文帮助文档(API)
u396整理的JVectorMap文章

12
Mandag

Mandag

动漫,美剧,电影爱好者

19 日志
© 2016 - 2017 Mandag
由 Hexo 强力驱动
主题 - NexT.Muse