2020-07
3

攻克静态blog

By xrspook @ 10:30:05 归类于: 烂日记

上周五我才开始研究静态blog。我选定的基本是hugo,因为这个东西生成网站的速度非常快。暂时我只是在本地操作。一开始的时候我不知道那个生成网站的命令窗口必须一直开着网站才能浏览,关掉的话就开不了了。之所以不了解这个,大概我还没研究过hugo的原理。之所以我在本地测试WordPress的时候可以一直开网站是因为虚拟的那个东西其实一直都常驻我的电脑。同样是本地测试,静态网站的生成速度以及网页打开速度比WordPress快非常多。如果只是几篇文章,生成网站的速度是毫秒级的,基本上就是一眨眼的功夫。昨天我测试了,生成200多篇文章的网站,也非常快,只需0.5秒。但是,如果网站有9000多篇文章呢,到底需要多长时间生成?这个我还没测试出来。因为我那9000多篇文章还没有完全符合的hugo框架的要求。

要用Hugo建立静态网站,如果是从零开始,当然很简单,按照他们的规则去写就可以了,但对我来说,我不是从零开始的,之所以用这个东西是因为生成速度快,而且可以挂在免费的空间上面。因为我的老blog很多,所以我必须要找一个这样的地方。如果我仍然使用WordPress,显然就非常浪费资源了。静态网站跟动态网站最大的区别,我觉得是静态网站不自带评论功能。几乎可以这么说,静态网站如果不外挂,是无法交流的。因为我挂的是老blog已经早就不去更新了,从前那些挂着blog的BSP都已经全部没了。我会在静态blog上留下可以交流的链接,如果有需要,访客可以找到我的blog,然后留言。这样的好处是起码你还能找到我,但坏处就是,你不能在你感兴趣的那个地方直接留言。去到我的blog还得解释你是从哪里来的,这就比较麻烦。但换个思路,我把那些已经不存在的东西重新又翻出来让你见到,其实已经很不容易了。

hugo的建站不难,但是如何把核心内容转化为hugo适配的不容易。我要把XML格式的大文档转化为一篇一边的markdown文档,这个星期我都在折腾这个。我本想直接用一个python脚本解决所有问题,因为理论上这是相当简单的操作,但是我却发现能搜索的python脚本,根本不适合我。有些已经老掉牙了,用的是python 2的版本,我试着转版本,让失败了,因为我实在不知道,里面的某些操作到底在新版本里是怎么个整法。

经历XML转化为另外一种格式的XML之后,我对XML这个东西算是有点了解了,我个人觉得输出markdown其实要比XML格式互转简单一些。XML互转只需要输出一个文件,但是markdown要生成无数个文件。python的操作之中,我最生疏的就是文件处理。输入输出那一章书我觉得自己根本没毕业。现成的python脚本无法满足我,我得自寻出路。幸好有一个叫做html2text python模块拯救了我,这个东西解决了从html到markdown的转换,所以正文最核心的东西的转化已经不成问题了,虽然里面还有一些说不准什么时候会出现的状况,但总体来说效果不错。XML的格式转化如果有一些我不想转义的东西,我还能用cdata把那些都圈起来,圈起来以后就没烦恼了,但是用markdown文件在hugo建站,必须有一个YAML的开头,而那个东西是有严格的格式限制的。篇名、分类和标签都必须严格符合这些要求。因为我的网址输出用的是python的时间戳,完全是数字,所以没烦恼,一开始的时候,文档的文件名我用的是时间加篇名,但因为片名的幺蛾子太多,所以,我选择了用纯粹的时间,单位精确到秒。如果不是手动设置过时间,不会发生重复。接下来我需要做的是整一套替换列表。把里面严格限制不让用的东西全部整理一遍。这样才能保证hugo的网站里能生成了我的全部东西,而不会有些不合规则的直接被屏蔽掉。WordPress没有这种烦恼,顶多出来的东西乱码而已,只要我把可能乱码的东西全部cdata。简直爽歪歪。之所以可以这样,是因为我把数据导入到WordPress的时候,软件默认把我不规范的东西规范化了,现在这个步骤,我完全得靠自己。

虽然现在我生成的文件还不能100%的符合hugo的要求,但从完全不会到可以生成,而且大多还是合格的,能做到这个我已经很满意。

2020-06
23

做到了

By xrspook @ 10:27:38 归类于: 烂日记

昨天我终于用python写出了把点点转化为WordPress的脚本。这个东西我确信是可行的,因为python的转换过程中没有出错,这就证明没有遇到奇怪的事情。用别人脚本的时候,把转换好的文件上传到WordPress,我总会担心不成功,但我自己写的脚本,我知道该注意些什么,哪些参数是现在的WordPress必须要求有的,所以只要python的转换不出错,我的WordPress导入就不会有问题。因为点点的文章有9000多篇,要从后台管理界面导入到WordPress,会非常耗时间。如果一篇文章需要两秒,完全导入就需要5个多小时,所以我没有做这种事。我挑选出22篇,各个类型都有的,试验导入,结果非常成功,网页的效果也很好,完全按照我的意思生成了。我觉得如果要快速解决问题,估计我得在数据库端导入。之前把文章导入到WordPress,因为要尝试不同的版本,我得不断地导入删除,但删除的文章太多的时候,速度很慢。后来我暴力地在数据库那里直接写删除语句,结果秒杀就完成了。现在我发现了一个更干净的方法。直接把关联WordPress的数据库里的内容全部删掉,这也是一个秒杀的过程,而且绝对不会留下任何的手尾,比如文章删除了,但是分类和标签仍然在那里。可能某些东西已经不存在了,但是计数还停留在一个很大数值,之所以这样,肯定是因为我删除文章的时候不够艺术。与其让里面留那么多乱七八糟的东西,还不如直接把数据库清空。因为我这是单机上的WordPress,我纯粹只是用来测试。这样的删除是最快捷的。大概我从上周,才突然领悟出可以这样。别人之所以要在数据库里写语句删除文章或者标签,是因为不能删掉一些不应该删掉的东西,但我没有这个顾虑。既然在数据库层面可以快速的删除,那么理论上也应该可以从数据库层面快速的导入。之所以有这个想法,是因为我发现WordPress的插件有些是针对数据库的,有些是针对WordPress自带函数的,数据库层面的查询要自带函数快非常多。现在我已经学会了转换适配后台界面导入的文件格式转换。下一步大概我得学习一下如何在数据库层面进行导入。这么高端的做法,貌似之前我还没有听说过。在网站迁移的时候,的确是把数据库打包,然后重新放到别的地方的,但那个数据库是本来就已经存在的。从一个地方挪到另外一个地方,原封不动地,但是我却要把大量的数据以快速的方式导入到数据库,并且还得按照WordPress的脾性建立各种关联,显然这貌是非常不简单,但理论上应该可以做到。

我不知道我的python到底学成怎样了,但起码我可以用那个东西实现我自己的愿望。相比于书本的习题,我觉得实现自己的愿望更有成就感,虽然其中有很多问题完全只能靠自己,没有参考答案。虽然总的来说,脚本不是我一个人写的,我是站在巨人的肩膀上修改而成,但BlogBus和点点的结构还是有差异的。最幸运的是某些我不知道该用什么手段实现的东西前人已经给我指明了方向。昨天我只是把脚本写出来了,接下来我要把脚本优化,一些老是翻来覆去说的句子完全可以把那作为自定义函数。到底什么东西应该泛化,应该泛化到什么程度,这个我还没有想好。昨天之所以可以这么迅速地完成任务,大概是因为在我开始之前先做了个思维导图,明确了我到底要做些什么。基础数据有哪些,应该在哪里取数,需要判断的参数有哪些,各自的参数有什么特性,能不能合并同类项。之前我就写过类似的东西,但是跟思维导图比起来,之前我写的那个真的很水。有思维导图、有专业的思维导图软件,人的思路可以非常快地展开。整体定下来,下面的事情就只剩下一步一步地实现。我做梦也没想到,自己这次居然这么高效。某些我没有把握能快速解决好的问题,昨天不知道为什么很多都迎刃而解了。转换一个30多MB的XML文件,我用了16秒。转换出来的文件大小为22MB。我觉得应该可以更快,但怎么才能更快呢?文件里的数据结构是我没有考虑过的,我是不是应该从那里入手?一些相同的判断,大概我应该做一些合并。

追求更好是没有尽头的。

2020-06
18

BlogBus 2 WordPress – by xrspook

By xrspook @ 19:50:07 归类于: 扮IT

为什么要学习python?因为我见识过python有多牛逼,简单一个脚本文件,轻量级的东西实现强大的功能。因为要做XML文件的格式转换,所以我觉得我要学好python。Think Python 2看到第14章,我就转向去研究10年多以前网友写的BlogBus转WordPress的python脚本。之所以要研究,因为当时的WordPress格式和现在不一样,用以前的脚本转换出来的东西已经没办法直接导入到现在的WordPress里了。再去找写代码的那些人,有些网站还在,但有些已经消失了。我不能等待别人拯救我,我只能自己拯救自己。

我需要转换格式的是“回到过去——Betty迷的独白”和“Mi Internacional Cielo”,这两个旧BlogBus站点和我的主站“我的天”不一样,虽然里面有不少我原创的东西,但我从四面八方搜集回来的内容也不少。当时的BlogBus默认编辑界面是富文本,我看上去觉得格式没问题大概就可以了,但实际上格式是有问题的。从五湖四海搜集回来的文字里面怎么可能不夹杂各种格式,那些东西在富文本编辑下可能看不出来,但在源代码界面一团糟。如果当年我复制粘贴的时候有先去记事本过渡一下就不会有那么多的问题。所以除了要转换BlogBus和WordPress的标签以外我还要筛选删除那些坏事的源代码。

经过接近一周的努力,我终于整出来了。运行下面的python3脚本,如果能顺利完成,自动生成出新的XML文件,用官方途径导入WordPress 5.4.2是完全没有问题的,但我只测试了我自己的两个blog,是不是兼容其它我不知道。因为转换blog我是有自己的想法的,所以脚本中有一些个性化的东西,比如我把blog的标题变成了分类,把原来的分类变成了标签。脚本中有大量的反转义替换,主要是为了人去看CDATA的时候不太头晕迷糊,因为我那两个旧blog里有大量的西班牙语字符,不同的编码下,BlogBus的导出文件里有些被转义了有些没有。那些转义了的放到WordPress里不知道WordPress会不会转回来,我试过标题被BlogBus转义之后WordPress不会转回来,看得我云里雾里。因为转义很头痛,所以除了少数几个内容,有可能被转义的文字都被我用CDATA包裹了起来。

脚本不是我一个人的功劳,我只是在当年网友脚本的基础上做了调整,使之适配python3和WordPress 5.4.2。

我的脚本:xbus2wp.py (PS:下面脚本330行的《/p》是什么鬼怪!WordPress的脚本插件在搞什么!)

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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
'''
***使用说明***
终端界面输入xbus2wp.py bus.xml xrspook。其中:
xbus2wp.py为脚本名字,bus.xml为BlogBus导出文件,xrspook为博主名字,3个参数以空格分开
若运行无误,输出的文件名为[原文件名_xbus2wp.xml]
脚本基于python3,适配WordPress 5.4.2(2020-06-18)
'''
 
import re, sys, getopt, datetime
from xml.dom import minidom
from time import time
 
def convert(inputFileName, owner, order='asc'):
    """"""
    try:
        xmldoc = minidom.parse(inputFileName)
    except Exception as e:
        print ('Fail.')
        print (e)
        print ('Please repair or delete invalid token like "& < >" there.')
        sys.exit(1)
 
    bus = xmldoc.documentElement
    logs = bus.getElementsByTagName('Log')
 
    dom = minidom.Document()
    rss = dom.createElement('rss') # rss是root,根元素
    dom.appendChild(rss)      
    rss.setAttribute('version', '2.0')
    rss.setAttribute('xmlns:content', 'http://purl.org/rss/1.0/modules/content/')
    rss.setAttribute('xmlns:wfw', 'http://wellformedweb.org/CommentAPI/')
    rss.setAttribute('xmlns:dc', 'http://purl.org/dc/elements/1.1/')
    rss.setAttribute('xmlns:wp', 'http://wordpress.org/export/1.0/')
    channel = dom.createElement('channel')
    rss.appendChild(channel)
    wxr_version = dom.createElement('wp:wxr_version') # 加入wxr戳,无戳无法进行WordPress导入
    channel.appendChild(wxr_version)
    wxr_version_node = dom.createTextNode('1.1')
    wxr_version.appendChild(wxr_version_node)
 
    busname = bus.getElementsByTagName('BlogName')[0] # 提取原BlogBus名字
    busname_text = getElementData(busname).replace(' ', '_')
 
    # create a list to contain items instead of appending them to
    # channel directly in order to sort them of lately according to order.
    if order == 'desc':
        item_list = []
    else:
        item_list = None
 
    for log in logs:
        title = log.getElementsByTagName('Title')[0]
        title_text = getElementData(title)
        content = log.getElementsByTagName('Content')[0]
        content_text = getElementData(content)
        logdate = log.getElementsByTagName('LogDate')[0]
        pubdate = getElementData(logdate)
        writer = log.getElementsByTagName('Writer')[0]
        creator = owner # BlogBus的writer根本没包含元素!
        category = getElementData(log.getElementsByTagName('Sort')[0])
        tagi = log.getElementsByTagName('Tags')[0]
        tags = getElementData(tagi).split(' ')
        new_tags = unique_tag(category, tags) # 新的wp标签里包含了原BlogBus里的分类与标签
        comments = log.getElementsByTagName('Comment')
 
        #-----
        item = dom.createElement('item')
 
        # handle title
        title_element = createElement(dom, 'title', title_text, 'cdata')
        item.appendChild(title_element)
 
        # handle type
        type_element = createElement(dom, 'wp:post_type', 'post', 'cdata')
        item.appendChild(type_element)
 
        # handle pubdate
        pubdate_element = createElement(dom, 'pubDate', convertPubDate(pubdate))
        item.appendChild(pubdate_element)
 
        # handle creator
        creator_element = createElement(dom, 'dc:creator', creator, 'cdata')
        item.appendChild(creator_element)
 
        # handle categories with domain
        category_element = createElement(dom, 'category', busname_text, 'cdata') # 把BlogBus标题设置为分类,因为我要合并多个旧blog
        category_element.setAttribute('domain','category')
        category_element.setAttribute('nicename', busname_text)
        item.appendChild(category_element)
 
        # handle tags
        for tag in new_tags:
            tag = tag.replace('&ntilde;', 'n')
            tag = tag.replace('summary_of_BLF', 'summary_of_BLF(from_rincondebetty)')
            tag = tag.replace('summary_of_EcoModa', 'summary_of_EcoModa(from_rincondebetty)')
            category_element = createElement(dom, 'category', tag, 'cdata')
            category_element.setAttribute('domain','post_tag')
            category_element.setAttribute('nicename', tag)
            item.appendChild(category_element)
 
        # handle content
        content_element = createElement(dom, "content:encoded", content_text, 'cdata')        
        item.appendChild(content_element)
 
        # handle post_date
        post_date_element = createElement(dom, "wp:post_date", pubdate)
        item.appendChild(post_date_element)
 
        # handle status
        status_element = createElement(dom, "wp:status", 'publish')
        item.appendChild(status_element)
 
        # handle comments
        if comments:
            commentElements = createComments(dom, comments)
            for commentElement in commentElements:
                item.appendChild(commentElement)
 
        if item_list != None:
            item_list.append(item)
        else:
            channel.appendChild(item)
 
    if item_list:
        item_list.reverse()
        for m in item_list:
            channel.appendChild(m)
 
    global filename # 输出设置
    output = filename + '_xbus2wp.xml'
    f = open(output ,'wb+')
    import codecs
    writer = codecs.lookup('utf-8')[3](f)
    dom.writexml(writer, '', ' ' * 4, '\n', encoding='utf-8')
    writer.close()
 
def unique_tag(category,tags): # 只保留唯一的标签
    category = category.replace(' ', '_')
    l = category.split() + tags
    new_l = []
    for item in l:
        if item not in new_l and item != '(from_rincondebetty)':
            new_l.append(item.replace(' ', '_')) # 替换空格为下划线
    return new_l
 
def getElementData(element): # 获取节点数据
    """"""
    data = ''
    for node in element.childNodes:
        if node.nodeType in (node.TEXT_NODE, node.CDATA_SECTION_NODE):
            data += node.data
    return data
 
def createComments(dom, comments):
    """"""
    l = []
    count = 0
    for comment in comments:
        count += 1 # 每篇文章的评论序号,没有序号,评论只能导入每篇最后一条
        email = comment.getElementsByTagName('Email')[0]
        homepage = comment.getElementsByTagName('HomePage')[0]
        name = comment.getElementsByTagName('NiceName')[0]
        content = comment.getElementsByTagName('CommentText')[0]
        date = comment.getElementsByTagName('CreateTime')[0]
        comment_element = createCommentElement(count, dom, email, homepage, name, content, date)
        l.append(comment_element)
    return l
 
def createCommentElement(count, dom, email, homepage, name, content, date):
    """"""
    comment_author = getElementData(name)
    comment_author_email = getElementData(email)
    comment_author_url = getElementData(homepage)
    comment_date = getElementData(date)
    comment_content = getElementData(content)
 
    comment_id_element = createElement(dom, 'wp:comment_id', str(count))
    comment_author_element = createElement(dom, 'wp:comment_author', comment_author)
    comment_author_email_element = createElement(dom, 'wp:comment_author_email', comment_author_email)
    comment_author_url_element = createElement(dom, 'wp:comment_author_url', comment_author_url)
    comment_date_element = createElement(dom, 'wp:comment_date', comment_date)
    comment_date_gmt_element = createElement(dom, 'wp:comment_date_gmt', comment_date)
    comment_content_element = createElement(dom, 'wp:comment_content', comment_content, 'cdata')
    comment_approved_element = createElement(dom, 'wp:comment_approved', '1')
 
    # make the comment element
    comment_element = dom.createElement('wp:comment')
    comment_element.appendChild(comment_id_element)
    comment_element.appendChild(comment_author_element)
 
    # validate email and url
    validEmail = validateEmail(comment_author_email)
    if (validEmail):
        comment_element.appendChild(comment_author_email_element)
 
    validUrl = validateUrl(comment_author_url)
    if (validUrl):
        comment_element.appendChild(comment_author_url_element)    
 
    comment_element.appendChild(comment_date_element)
    comment_element.appendChild(comment_date_gmt_element)
    comment_element.appendChild(comment_content_element)
    comment_element.appendChild(comment_approved_element)
 
    return comment_element
 
def createElement(dom, elementName, elementValue, type='text'): #建立节点标签和节点
    """"""
    global owner
    tag = dom.createElement(elementName)
    if elementValue.find(']]>') > -1:
        type = 'text'
    if type == 'text':
        text = dom.createTextNode(elementValue)
    elif type == 'cdata':
        elementValue = elementValue.replace('&amp;', '&')
        elementValue = elementValue.replace('&lt;', '<')
        elementValue = elementValue.replace('&gt;', '>')
        elementValue = elementValue.replace('&apos;', '\'')
        elementValue = elementValue.replace('&quot;', '"')
 
        # 大量替换与我的旧blog有各种编码的西班牙语字符有关
        elementValue = elementValue.replace('&copy;', '') # 版权标志
        elementValue = elementValue.replace('&nbsp;', '') # 空格
        elementValue = elementValue.replace('&ldquo;', '“') # 左双引号
        elementValue = elementValue.replace('&rdquo;', '”') # 右双引号
        elementValue = elementValue.replace('&lsquo;', '‘') # 左单引号
        elementValue = elementValue.replace('&rsquo;', '’') # 右单引号
        elementValue = elementValue.replace('&acute;', '´') # 单引号
        elementValue = elementValue.replace('&hellip;', '...') # 省略号
        elementValue = elementValue.replace('&mdash;', '—') # 破折号
        elementValue = elementValue.replace('&middot;', '·') # 分隔号
        elementValue = elementValue.replace('&deg;', '°') # 单位度
        elementValue = elementValue.replace('&iexcl;', '¡') # 西班牙语反叹号
        elementValue = elementValue.replace('&iquest;', '¿') # 西班牙语反问号
        elementValue = elementValue.replace('&ntilde;', 'ñ') # 西班牙语n
        elementValue = elementValue.replace('&Ntilde;', 'Ñ') # 西班牙语N
        elementValue = elementValue.replace('&aacute;', 'á') # 西班牙语a
        elementValue = elementValue.replace('&eacute;', 'é') # 西班牙语e
        elementValue = elementValue.replace('&iacute;', 'í') # 西班牙语i
        elementValue = elementValue.replace('&oacute;', 'ó') # 西班牙语o
        elementValue = elementValue.replace('&uacute;', 'ú') # 西班牙语u
        elementValue = elementValue.replace('&Aacute;', 'Á') # 西班牙语A
        elementValue = elementValue.replace('&Eacute;', 'É') # 西班牙语E
        elementValue = elementValue.replace('&Iacute;', 'Í') # 西班牙语I
        elementValue = elementValue.replace('&Oacute;', 'Ó') # 西班牙语O
        elementValue = elementValue.replace('&Uacute;', 'Ú') # 西班牙语U
        elementValue = elementValue.replace('&Atilde;', 'Ã') # 西班牙语A~
        elementValue = elementValue.replace('&ordf;', 'ª') # 西班牙语上标a
        elementValue = elementValue.replace('&ordm;', 'º') # 西班牙语上标o
 
        elementValue = elementValue.replace('<!--msnavigation-->', '')
        elementValue = elementValue.replace('博主', owner)
        elementValue = elementValue.replace('<i>', '')
        elementValue = elementValue.replace('</i>', '')
        elementValue = elementValue.replace('<br /><br />', '<br />')
 
        elementValue = re.sub(r"(?:<\?xml.*?>)", "", elementValue)
        elementValue = re.sub(r"(?:<[TDSFHI].*?>)", "", elementValue)
        elementValue = re.sub(r"(?:<\/[TDSFHI].*?>)", "", elementValue)
        elementValue = re.sub(r"(?:<P.*?>)", "<p>", elementValue)
        elementValue = re.sub(r"(?:<(table|tbody|tr|td|div|span|img|script|font|hr|object|param).*?>)", "", elementValue)
        elementValue = re.sub(r"(?:<\/(table|tbody|tr|td|div|span|img|script|font|object).*?>)", "", elementValue)
        elementValue = re.sub(r"\n", "", elementValue) # 把替换造成的空行删除
 
        text = dom.createCDATASection(elementValue)
    tag.appendChild(text)
    return tag
 
def convertPubDate(date, timediff='+0000'):
    """
    convert 2003-08-22 16:01:56
    to Thu, 23 Aug 2007 05:47:54 +0000
    """
    year, mon, day = int(date[:4]), int(date[5:7]), int(date[8:10])
    time = date[11:]
    aday = datetime.datetime(year, mon, day)
    d = {'1':'Mon', '2':'Tus', '3':'Wen', '4':'Thur', '5':'Fri', '6':'Sat', '7':'Sun'}
    m = {'1':'Jan', '2':'Feb', '3':'Mar', '4':'Apr', '5':'May', '6':'Jun',
         '7':'Jul', '8':'Aug', '9':'Sep', '10':'Oct', '11':'Nov', '12':'Dec'}
    weekday = d[str(aday.isoweekday())]
    month = m[str(mon)]
    pubdate = "%s, %d %s %s %s %s" % (weekday, day, month, year, time, timediff)
    return pubdate
 
def validateEmail(email):
    '''
    '''
    pattern = r'^[0-9a-z][_.0-9a-z-]{0,31}@([0-9a-z][0-9a-z-]{0,30}[0-9a-z]\.){1,4}[a-z]{2,4}$'
    p = re.compile(pattern)
    m = p.match(email)
    if m:
        return True
    else:
        return False
 
def validateUrl(url):
    '''
    '''
    pattern = r'^[a-zA-z]+://(\w+(-\w+)*)(\.(\w+(-\w+)*))*(\?\S*)?$'
    p = re.compile(pattern)
    m = p.match(url)
    if m:
        return True
    else:
        return False
 
def main(argv=None):    
    global filename
    global owner
 
    if argv is None:
        argv = sys.argv
    # parse command line options
 
    args = sys.argv[1:]
    order='asc'
    if (len(args) == 2):
        print ('Converting...'),
        sys.stdout.flush()
        start = time()
        filename = args[0].replace('.xml', '')
        owner = args[1] # BlogBus没把博主名字输出,只能手动
        convert(args[0], args[1], order)
        end = time()
        print ('Done. Elapse %g seconds.' % (end - start))
 
if __name__ == "__main__":
    sys.exit(main())
</p>
2020-06
17

为什么他们居然还活着

By xrspook @ 9:46:58 归类于: 烂日记

见过脸皮厚的,从来没有见过脸皮这么厚的。要浪潮开发一个管理软件,然后他们居然丢了一个报表插件的使用说明过来。我是用户,我需要的是开发者提供的使用手册,报表插件是开发者需要研究的,用户的操作说明应该是开发者开发了之后做出来的。所以,看到报表平台操作手册以后我云里雾里。我已经接触过起码3套浪潮开发的系统,里面的报表一律用的是硕正的东西(supcan),这是一个屌丝到什么程度以后的东西呢?硕正Web应用套件支持IE(6-12),Chrome没写版本,Firefox只支持52版前,听上去好高端,实际上除了某些IE,在Chrome和Firefox实际上都是打不开的,为什么?Chrome他们根本不敢写版本,用360极速浏览器打开浪潮的系统你肯定不能用Chrome内核的极速模式,因为那连浪潮的系统都登入不进去,就更不用说打开报表了。至于Firefox,浪潮可以登录,但遇到硕正的东西就一片空白。为什么会这样?因为现在的Firefox都升级到77+了,52以内那是XP的年代的事情!硕正的产品特征里有这么两句话:

硕正套件在纯净的Windows环境下就能运行,不需要诸如.NET FrameWork、Java的支撑环境。
硕正套件支持Windows XP以后(包括Windows XP)的所有Windows系列操作系统。

还记得大概半年前搜索这个控件的时候他们写的是“完美支持XP系统”,现在好一点,不沾沾自喜自己在XP领域是顶级高手了,但谁用谁知道那有多恶心。理论上硕正支持所有Windows系统,但比XP高级的Windows系统根本不会用他们所列出来除IE以外的浏览器,因为那些都太低端了,全部被淘汰了。你用的是XP,大概这个控件一点问题没有,但现在已经2020年了,Win7都已经被微软遗弃,你还跟我说XP!所以呢,无论说得多么好听,实际上浪潮的系统只支持用IE打开,而且是限定了版本的某些IE。IE浏览器跟Chrome和Firefox比起来性能差多少那是毋庸置疑的,而且IE的版本还丰富得让人想吐,各自都有自己的脾气,低版本很无能,高版本完全不照顾低版本。系统限定了、浏览器限定了,这样基于Web的系统,还不如直接用回很久很久以前的唯一出路——系统客户端。系统最重要的功能,为了能在Web上实现而牺牲功能这到底是什么鬼思路!!!

Web控件有很多,但浪潮只基于硕正开发,一个习惯于用跟时代脱节的控件开发软件的公司,你绝对不能对他们有任何的期待。创新神马,不存在的!乱七八糟的bug神马,家常便饭。售后神马,希望你还有命等到给我们给出答案。先不说售后,光是验收合格,我觉得都是不可能的事。

用过浪潮的系统以后会让人有自己动手丰衣足食自己开发软件的冲动,因为他们的软件实在太糟糕了。

2020-06
10

shelf这只鬼

By xrspook @ 9:52:26 归类于: 烂日记

连题目都看不懂到底要做什么,解答那道题当然是无从说起,但是我还是硬着头皮去做了。用我理解的那个方式去做。本来我没有打算看参考答案,我是去看另一道题的参考答案的,参考答案没看懂,顺便把上一题的参考答案下载回来,结果发现,那个我看不懂的单词的确是个人家觉得你应该知道,但实际上我毫不知情的东西。shelf中文翻译很好理解,就是柜子嘛,但是柜子是干嘛的呢?这到底纯粹是某个单词,某个函数,某个字典,还是什么东西呢?当我看到参考答案的文件的命名后,我有点明白了,那个估计是一个数据库。我直接拿着那个单词去问我的网友,他也没反应过来,这到底是什么东西?他没学过python,他学过其他编程语言。这就证明了,其它编程语言里是没有这个东西的。写Think Python这本书的人默认我们都知道shelf是什么。在那个单词出现之前,那一章书里没有出现过那个东西,我看的那章书是第14章,前面13章也半个字没有提及这个单词到底意味着什么。情况就好像,你在没有学过python的人面前说元组,人家完全不知道你在说什么。之前的习题,如果遇到这种情况,写书的会在题目后面提醒那是个什么东西,读者可以自己从某个链接那里了解这个玩意,但这道题他们半个字都没有提醒,所以我真的很怀疑翻译Think Python这本书的中国人到底有没有看懂这个单词。如果他们看懂了,至少他们应该提醒一下读者,这实际上是要他们把字典里的映射放到数据库里面,而那个数据库又不是真的传统意义上的数据库。要解释这种东西,的确用三言两语无法说清。即便我已经看过中文版Python手册里面介绍shelf的部分,但我觉得自己还是没搞懂到底那是什么。

按照参考答案的写法,我在自己的程序里先加入了一个建立数据库的语句,然后再增加shelf的处理。我不知道到底是怎么回事,因为终端里光标就一直停在那个地方,好像卡机一样,当我关掉软件以后,脚本的文件夹里面多了一些数据库文件。我不知道那到底是什么,但显然里面有很多东西。其中一个dir文件,有100多KB,而另外一个数据库的缓存文件,接近30MB,我不知道哪来那么多的内容。大概我应该把后缀改一改,然后用Access打开看一下里面到底有些什么神奇的玩意。因为这个数据库很大,所以我在终端里就看到光标卡在那里。为什么python里的字典秒杀就能显示完毕的东西建立数据库居然这么庞大呢?可想而知,在字典里可以秒杀完成的搜索,如果放在数据库里反应时间估计是万倍的区别。这让我想起Excel的VBA里,如果读写的是单元格,那么脚本将非常耗时,但如果把读写的内容先存在数组里面,完成以后一并输出,效率会高非常多,随便高个几百倍算很少了。

高中的时候,我学过Access,但只是老师说什么我就做什么,我只知道一些非常皮毛的东西。Access的精髓是数据库,数据库的灵魂是查询语句,但那时的学习我们只停留在可视化表格操作。

无论精通了哪一门编程语言,所有事情都能用那个方法搞定。有些人学习是为了赚更多的钱,而我努力学习只是因为我想知道、我想实现。

© 2004 - 2024 我的天 | Theme by xrspook | Power by WordPress