微信公众号服务:将用户发来的图变成海报

这个想法是草地音乐某次活动海报做得非常简单,直接用了一张往期的照片,贴上了活动地点的文字。于是想到其实可以让大家用自己的照片做成海报来玩。

想到最直接的交互就是从微信公众号了,不需要写什么专门网页,你发我一张图,我回你一张图,非常简单高效。后来用python写一个flask服务,图像处理就用PIL,写出来也非常快。

再后来发现可以有更多有趣的玩法,比如除了海报,还可以生成一些比如LOMO风格、黑白风格等照片,或者加上你的二维码等等,后来也做了一些。随便贴一张示例,毕竟一图胜万言嘛。

 

再到后来圣诞节想到,可以用人脸识别,在图片里找出脸的位置,然后在上方贴上圣诞帽的图层,也会非常有喜感,这个和最近比较火的很多自拍类软件自动加上猫胡须什么的其实原理是一样的。

代码已经开源了,点击这里可以看到,后面可以发挥想象力再做一些有趣的东西,不限于图片的交互,可能声音啊视频啊都可以有趣起来。

用Python批量下载豆瓣小站的音乐

原理很简单,豆瓣小站的网页HTML看了一下,每首歌的名字和地址都写好了在里面,只是每次载入地址是不一样的而已。用urllib读取一下,分析出里面的名字和地址,然后下载即可。我用的是python3.2,代码如下:

import urllib.request
from urllib.request import urlopen
import re,os

url = input('Please enter the URL of the douban site.\n(E.g., http://site.douban.com/quinta-diminuita/)\n')
content = urlopen(url).read().decode('utf-8')
#分析音乐人名称并创建相应目录
site_name = ''.join(re.findall('', content, re.DOTALL))
artist = site_name.replace('的小站\n(豆瓣音乐人)','')
print('Preparing to download all the songs by '+artist+'...')
if os.path.exists('./'+artist) == False:
os.mkdir('./'+artist)
#分析出所有房间地址
roomlist = re.findall('

(.*?)<\/div>', content, re.DOTALL)
roomurl = re.findall('href=\"(.*?)\"', roomlist[0])
#对于每个房间,如果有播放列表,则分析每个列表中的歌曲名和对应地址,然后下载
for h in roomurl:
content = urlopen(h).read().decode('utf-8')
playlist = re.findall('song_records\s=\s\[(.*?)\]\;\n', content, re.DOTALL)
if playlist != []:
for i in playlist:
playlist_spl = re.split(r'},{', i)
for j in playlist_spl:
song_title = ''.join(re.findall('\"name\"\:\"(.*?)\"', j))
song_title = ''.join(song_title).replace('\\','')
song_title = ''.join(song_title).replace('/','.')
song_url = re.findall('\"rawUrl\"\:\"(.*?)\"', j)
song_url_str = ''.join(song_url).replace('\\','')
filepath = './'+artist+'/'+song_title+'.mp3'
if os.path.isfile(filepath) == False:
print('Downloading '+song_title+'...')
urllib.request.urlretrieve(song_url_str, filepath)
else:
print(song_title+' alreadly exists. Skipped.')
print('All the songs have been downloaded (if there are any). Enjoy!')

最后附图一张,上面是命令行的运行结果,左边是代码,右边是拖回来的文件,成就感满满!
Screenshot - 061013 - 21:53:00

乐透中奖号码预测算法一则

很显然,谁都不能准确预测号码,本文的方法只是凭借个人可怜的概率知识、直觉、执念、灵感混合而得出,本人对结果的准确性不负任何责任。

英国的lotto规则是,从1-49这些数字里选6个,每期中奖号码为6个主号加1个额外号码,中5+1要比6个全中奖金少很多。我的算法是,从历史中奖号码里统计出每个数次的出现频率,不考虑顺序,因为每次的中奖号码都是从小到大排列的。统计出最高的6个和最低的6个,将最高的数字减去最低的,取绝对值,然后将各自的频率相减取绝对值再处以历史开奖次数,最后将这两个计算结果相乘,加到最低的数字上去。对于第二高和第二低的也是如此,以此类推。简单说就是取最低频率的数字,用最高频率的数字对其作微调。

其实这个算法比较简陋,没考虑中间的数字,这次写的比较草,以后会慢慢补充更复杂的算法,先上代码。

import operator
import math

#将历届数据读入列表
f = open('./lotto')
main_num_list = []
bonus_num_list = []
draws = 0
for line in f:
	main_num = (line.split('\t'))[0]
	main_num = main_num.split(' - ')
	for i in range(0,6):
		main_num[i] = (int(main_num[i]))
	main_num_list.append(main_num)
	bonus_num = int((line.split('\t'))[1])
	bonus_num_list.append(bonus_num)
	draws += 1

#生成一个key为1-49的字典,value记录该数字出现次数
candidate_main = {}
candidate_bonus = {}
for i in range(1,50):
	candidate_main[i] = 0
	candidate_bonus[i] = 0
for item in main_num_list:
	for number in item:
		candidate_main[number] += 1
for item in bonus_num_list:
	candidate_bonus[item] += 1

#分析历史中奖号码中各数字出现的频率,并降序输出
print("Analysis of Main Numbers:\nNumber\tOccurrance")
counter = 0
high_freq_num = []
high_freq_occur = []
low_freq_num = []
low_freq_occur = []
for num in sorted(candidate_main, key=candidate_main.get, reverse=True):
	print("{0}\t{1}".format(num,candidate_main[num]))
	counter += 1
	if 1 <= counter <= 6:
		high_freq_num.append(num)
		high_freq_occur.append(candidate_main[num])
	if 44 <= counter <= 49:
		low_freq_num.append(num)
		low_freq_occur.append(candidate_main[num])

#计算预测的号码
predictions = []
for i in range(0,6):
	prediction = round(low_freq_num[5-i]+(math.fabs(high_freq_num[i]-low_freq_num[5-i])*(math.fabs((high_freq_occur[i]-low_freq_occur[5-i])/draws))))
	predictions.append(prediction)
print("Probably the next draw result would be:")
print(sorted(predictions))

#可以用同样方法处理Bonus Number,但是没有必要,因为只作开奖号码,不可挑选

历史数据来自官方网站,懒得用bs4分析html了,手动复制下来,稍微处理了一下,留下中奖号码,放在文本文件里,样例:

6 - 24 - 33 - 38 - 42 - 43     11
12 - 15 - 24 - 36 - 45 - 49     32
3 - 9 - 10 - 16 - 20 - 22     35
16 - 24 - 27 - 39 - 45 - 49     44
15 - 27 - 31 - 40 - 41 - 49     1
7 - 13 - 25 - 31 - 34 - 45     4

运行结果我就不贴出来了,很长。大家自己运行吧,万一我贴出来预测号码,结果中了那就太招摇了哈哈哈……

用Python批量抓取豆瓣日志

昨天在豆瓣看到有人发状态问如何把豆瓣日志保存到本地,正好最近在学python,就想到用python写一段小程序,练练手。

解析HTML用的是BeautifulSoup库,看了一下文档,还算简单,但是有些奇怪的问题我一时弄不清楚为什么,所以部分功能是用了比较曲折的方法实现的……

好了,少废话,上代码:

from bs4 import BeautifulSoup
import urllib2
import re
import sys
	
def get_each_blog(url):
	content = urllib2.urlopen(url)
	soup = BeautifulSoup(content)
		
	header = soup.find_all("div", attrs={"class": "note-header"})
	title = header[0].h1.get_text()
	date = header[0].span.get_text()
	print(title.encode("UTF-8"))
	print(date.encode("UTF-8"))
	print('\n')
	
	body = soup.find_all("div", attrs={"class": "note"})
	body = str(body[1])
	body = body.replace("""", "") 
	body = body.replace("\n", "") body = body.replace(" ", "\n") 
	print(body) print('\n') print('\n') 

def link_list(pageurl): 
	content = urllib2.urlopen(pageurl) 
	soup = BeautifulSoup(content) 
	urllist = soup.find_all("div", attrs={"class": "rr"}) 
	for i in urllist: 
		blog_url= ('http://www.douban.com/note/'+(i['id'].split('-'))[1])
		get_each_blog(blog_url) 

baseurl = "http://www.douban.com/people/{0}/notes/".format(sys.argv[1]) 
content = urllib2.urlopen(baseurl) 
soup = BeautifulSoup(content) 
link_list(baseurl) 
page_list = soup.find_all("link", rel="next") 
while page_list != []: 
	pageurl = page_list[0]['href'] 
	link_list(pageurl) 
	page_list = BeautifulSoup(urllib2.urlopen(pageurl)).find_all("link", rel="next")

用法:运行这段程序时,将用户名作为参数,如果你没有设置豆瓣的用户名,那就是一串数字,也就是你个人主页的网址里“people”后面那一串,例如(以当初提问的这位同学为例):

~$ python crawl.py duanzhang >> blogbackup.txt

效果如下:
2013-07-16-221457_532x740_scrot

有个功能缺陷是,如果日记里有图片,只能抓到那部分的HTML代码,有兴趣的同学可以继续扩充,但是估计就要想着保存为网页文件了,以便原貌呈现图文混排,当然,也可以仅仅作为备份,把图片抓下来保存在同一个目录里,大家根据自己需求修改吧。

补充一下:windows和mac用户下载和运行python方法请参考官方网站,linux用户没必要说了,太简单了。