起因:某天晚上看一个科技评测节目,该节目宣称只要能够在视频中找到视频中插入的某一帧无关内容,就可以获得相应的奖品。我想了想应该是可以用代码实现的:
使用python3的一个工具you-get就能够做到。不过稍有曲折,我使用you-get去下载B站和优酷的视频都下载失败了,好在在该测评节目微博上找到了另外一个视频资源链接,使用you-get顺利下载下来,视频是640×360的,十分钟内容一共60M的MP4格式。
我先按照原样抽离,即抽离成640×360的图片,一共生成了8,988个文件,大小1.80 GB,不禁感慨视频压缩格式确实厉害啊,这压缩了多少倍啊,另外我考虑到可能更小的缩略图应该也拥有足够的分辨特征,所以也按照64×36的分辨率抽离了更小的缩略图

640×360逐帧抽离的图片截图

64×36逐帧抽离的图片截图
图像相似度算法我没具体研究过,直接用的github上面的项目:https://github.com/MashiMaroLjc/Learn-to-identify-similar-images
一共有有四种算法,具体中文的文章可以参看链接:
https://segmentfault.com/a/1190000004467183
我使用了不同的算法得到的不同的结果:
由于之前excel的制图删掉了,只能用当时程序计算的文本信息凑合了,计算出来的相似度大致就是如下的数字列表。

其实就是根据特征去拟合一条折线,能够正确反映出异常的关键帧在哪里。

其实这一步,我做了两三个小时,为了选择最佳的算法和最佳的效果,只有下图能够直截了当的反映出异常的帧在哪里,后来我想了想,如果加入跳帧的对比,比如第一帧和第三帧的特征,就能够更加准确的找到关键帧的位置。
http://mp.weixin.qq.com/s/K2YCm8QwnpI7dNTs048Jbg
叠加两个声音,并按照第一个声音的长度截取音乐,然后输出16k,单声道,声音质量为4的音乐:
ffmpeg -i example1.wav -i example2.wav -filter_complex amix=inputs=2:duration=first -ar 16k -ac 1 -q:a 4 output.wav
参考:https://ffmpeg.org/ffmpeg-filters.html
重复某个音频文件4次并截取80秒的音频数据
ffmpeg -stream_loop 4 –I example.wav -c copy -t 80 output.wav
从00:00:15开始截取音频、视频,截取5s,然后原样输出到文件中
ffmpeg -ss 00:00:15 -t 00:00:05 –I example.mp4 -vcodec copy -acodec copy output.mp4
pcm(已知pcm文件格式为16k 16bit 单声道)转换到固定格式的wav文件中
ffmpeg -f s16le -ar 16k -ac 1 -i tts_file_119.pcm -ar 16k -ac 1 tts_file_119.wav
对音频文件增加渐入渐出过滤效果(淡入从0秒开始,持续10秒,淡出从50秒开始,持续10秒,设定音乐音量为2, -y为覆盖已存在文件)
ffmpeg -i input.mp3 -af “afade=t=in:ss=0:d=10,afade=t=out:st=50:d=10,volume=volume=0.2” -t 60 output.mp3 –y
更多声音过滤器:http://ffmpeg.org/ffmpeg-filters.html
设定背景音乐,循环播放并增加淡入淡出效果
ffmpeg -stream_loop 4 -iinput.wav -af “afade=t=in:ss=0:d=10,afade=t=out:st=50:d=10,volume=volume=0.2” -t 80 output.wav
一般来讲 ffmpeg的文件后缀都是自适应的,比如你设置的输出格式是mp3,那么文件就能自动转换成该格式的文件,具体的采样率等参数需要单独去设置调整。
TypeError: not enough arguments for format string
使用Python连接数据库的时候,采用的非常非常轻量级的torndb,甚至于事务都不支持,所以用”select * from table where condition=’%s'” % (condition,)
因为用的比较原生,所以各种问题接连不断,最最恶心的就是字符串转义造成的一些列原因.
先采用
condition = re.escape(condition)
能对特殊字符进行转义,但是还是有问题,又报错TypeError: not enough arguments for format string 直到认真看输入的condition字符串的时候,才发现问题所在之处: condition中有% 需要替换%为%%才能正常执行,
condition= condition.replace('\%', '%%')
其实标题有问题,不只是操作数据库,只不过在操作数据库时候,忽略的字符串本身的内容,一直在错误的寻找解决方案.
python以其强大和简洁的语言让人折服,那么究竟有多强大,多简洁呢?在今天学习python的过程中,我来举个例子。
in:将以下列表转化成{‘a’:1,’b’:2}的形式
var = [('a','A',1),
('b','B',2),
('c','C',3)]
方法1:
tmp1 = []
tmp2 = []
for i in range(3):
val1 = var[i][0]
val2 = var[i][2]
tmp1.append(val1)
tmp2.append(val2)
tmpdict = {}.formatkeys(tmp1,0)
for i in range(3)
tmpdict[tmpdict.keys()[i]] = tmp2[i]
当然我有意的拉长了代码。
方法2:
tmp1 = [] tmp2 = [] for i in range(3): tmp1.append(var[i][0]) tmp2.append(var[i][2]) tmpdict = dict(zip(tmp1,tmp2))
采用zip压缩数组,然后转换成dict
方法3:
tmpdict = {i[0]:i[2] for i in var}
一句话循环并组成字典。
同样的还有很多地方用到,比如lambda,reduced,filter,cmp等这类函数的应用。能大大减少代码量。更有意思的可以查看:一行 Python 能实现什么丧心病狂的功能?
目标:在不删除python环境的情况下,安装一些常用的python库到windows中。
安装
VCForPython27 :windows下面vc库的安装软件。
Numpy : numpy windows下面的exe文件
scipy : scipy 的exe文件
matplotlib : pip 环境下的 whl 安装包,需要使用pip install 这个文件.whl 安装
下面工具还不熟悉,先不写描述了。
setuptools
python_dateutil
pyparsing
最近做项目使用scrapy,采用的是script的形式去写爬虫的,使用crawlspider去定义爬虫规则。
我先从数据库里面把我要读取的规则拿出来,采用的是单个频道写规则的形式,对每个列表页写一套规则,所以有next_page的规则。
sql = """SELECT id, weburl_id, name, allow_domains, start_urls, next_page,
allow_url, extract_from, title_xpath, body_xpath, publish_time_xpath, source_site_xpath, enable
FROM leiju_rules WHERE enable > 0"""
next_page分析形式是xpath提取链接,使用Rule不跟随(follow = False)。我的需求是我应该采集所有的页面,但是由于我想做成定时任务,就需要下次还使用这一套规则来运行爬虫,做到增量爬。这样的话就涉及到了内容的去重。开发的最开始,我才用的是pipline 通道去重,也就是当我产生一个request之后才开始判断这个内容我需要不需要,这样是很浪费服务器资源的。
if self.Redis.exists('url:%s' % item['url']):
raise DropItem("Duplicate item found: %s" % item['url'])
else:
self.Redis.set('url:%s' % item['url'], 1)
return item
然后我修改成采用downloadMiddleware下载中间件去控制访问,因为downloadMiddleware是可以控制在request访问之前的,加上Redis的过滤。
if Redis.exists('url:%s' % response.url):
raise IgnoreRequest("IgnoreRequest : %s" % response.url)
else:
Redis.set('url:%s' % response.url, 1)
return response
这时候又有一个问题了,就是我会把所有的访问都给记录下来,下次我连我写的起始start_urls都进不去了。本来寄托于从以下代码入手:
rule_list.append(Rule(LinkExtractor(restrict_xpaths=rule['next_page'])))
即希望通过next_page拿到下一页的链接,然后把这些链接排除掉,已经准备好了一个Redis库去存储这些url。
Filter = redis.StrictRedis(host='127.0.0.1', port=6379, db=2, password='pass123456')
然而实际在使用的时候发现我通过:
rule_list.append(Rule(LinkExtractor(restrict_xpaths=rule['next_page'])))
拿到的根本不是URL列表,而是一个Rule对象,里面包括了LinkExtarctor的Xpath规则。我甚至想通过response和xpath拿到链接之后在用redis存起来进行排除。
解决方法:
配合使用pipline和downloadMiddleware来轻松完成以上功能。
我先定义一个downloadMiddleware,用来拦截url,防止重复访问。
class IngoreHttpRequestMiddleware(object):
""" 从下载器处开始拦截/过滤URL """
def process_response(self, request, response, spider):
if Redis.exists('url:%s' % response.url):
raise IgnoreRequest("IgnoreRequest : %s" % response.url)
else:
# Redis.set('url:%s' % response.url, 1)
return response
然后定义一个pipline,用来保存最终流入pipline的item URL。
class FilterUrlPipline(object):
""" use redis to fileter url """
def __init__(self):
self.Redis = config.Redis
def process_item(self, item, spider):
self.Redis.set('url:%s' % item['url'], 1)
return item
这样一来,我的一个列表页面的所有链接都进入到了downloadMiddleware中,但是通过pipline拿到了最终我要的终极页面,通过pipline保存item URL,然后下次的时候redis里面有了数据,就可以排除所有的符合的终极页面访问请求,这样就解决了。
已开源在github上面:https://github.com/fengxiaochuang/ScrapyDemo
最近做项目使用了whoosh+flask,因为flask使用的是jinjia2 模板引擎,所以就此遇到的html转义的问题做一个解释.
以上为背景.
使用whoosh+falsk搜索的时候,我采用的是关键词高亮显示,但是在实际操作的过程中,生成的html是带<b></b>标签的字符串,无论怎样,这个标签字符串总是显示在html页面中.
开始我以为是因为在输出的过程中转义有问题,所以搜索python的html转义方法.无论正转义还是反转义,结果都不行.

开始后来渐渐怀疑到jinjia2模板引擎上面,我从一开始已未需要加参数 “|e” 调试仍然不行,后来继续搜close escape html 才发现有一个safe参数,能够保证原始的 string 就不会被escape,修改后
{{ row.hit_title|safe }}
从whoosh的坑里爬出来了,简单介绍一下实用搜索方面的内容,之前绕路了,希望以后学习的人不会绕远路.既然讲的话,就从我的一路的坑细细数来吧.
首先是受到whoosh官方demo的影响,我以为只能使用关键词的搜索,所以我用的如下方法:
for keyword in ("水果世博园", "你", "first", "中文", "交换机", "交换"):
print("result of ", keyword)
q = parser.parse(keyword)
results = searcher.search(q)
for hit in results:
# print(hit.highlights("content"))
print(hit)
当然这样的话搜索出来的结果都是每个关键词对应的一个搜索列表.这时候我甚至一度怀疑whoosh不支持短语的搜索,因为害怕自己去写搜索算法,于是此事搁置.
今天早上忽然有想到这个问题了,继续搜相关内容,无意中看到csdn上面有一篇文章提到Or Term And这种关键词,终于又回到whoosh手册上面了…真的是想要学一门技术就去读它的手册,上次吃亏在scrapy的logging上面…
然后开始进行程序改造,搜索短语,比如搜索:”中国国际物流节开幕”,采用结巴分词,先把这句话分解成一个个的关键词.
inputstring = "中国国际物流节开幕"
keywords = []
for t in analyzer(inputstring):
keywords.append(t.text)
拆开的关键词是:中国 国际 物流 国际物流节(我自己添加到jieba字典里面的) 开幕
然后采用各种手册上面的iter_all_terms terms方法,不行,然后继续看手册,发现其实parse默认的标准是采用的And,而且我搜索的字段是body,而这句话是我从title里面复制出来的,自然返回为空了.
知道了基本原理就先通过修改Term进行测试:
And([Term("title", "中国"), Term("title", "国际"), Term("title", "物流"), Term("title", "国际物流节"), Term("title", "开幕")])
通过该And和Or来调解Trem去测试搜索结果,总体来看基本思路是对的.
Or([Term("title", "中国"), Term("title", "国际"), Term("title", "物流"), Term("title", "国际物流节"), Term("title", "开幕")])
通过上面的querystring 终于搜索出来结果了…
那么既然结果出来了,下一步就是继续给搜索添加条件了,类似谷歌的搜索是如何做到的呢?于是我再google上面搜索”whoosh like search google”
然后在stackoverflow上面搜索出来答案了,给出的几个选择pyl,pyprasing等…然后继续搜索whoosh和pyprasing,搜索出来的代码都是在whoosh,support.pyprasing下面调用的,我import没有啊,继续看搜索结果,,,看到whoosh里面有这么一句话:(In previous versions of Whoosh, the query parser was based on pyparsing. The new hand-written parser is less brittle and more flexible.)
你说什么!whoosh原本就是基于pyparsing构造语法的?往下看手册,,,真的是必须硬着头皮看手册啊….
发现whoosh本身支持通过” “(空格)来分割关键词搜索的.也是支持and or 这种直接的搜索语法的,还可以自己定义这些逻辑符号.
再往下就顺利多了,随便贴一点我用到的关键代码把:
inputstring = "中国and(国际or物流)and开幕"
qp = MultifieldParser(["title", "body"], schema=ix.schema)
querystring = qp.parse(inputstring)
results = searcher.search(querystring, terms=True, limit=100, collapse_limit=1)
for hit in results:
print(hit['title'].encode('gbk'))
RTFM!
RTFM!
RTFM!