Categories

真·天气预报签名档

weather-new之前做了一个天气预报签名档,实际上只是显示了即时天气,这两天终于晴朗起来了(或者说,至少不下雨了),于是心情好更新了一下,顺便从 Yahoo Weather 上把未来五天的天气情况也抓下来放到图片里。总算对得起天气预报这个词了。

效果如右图所示。代码没有什么大的变化,只是实验室网络不知道为什么最近奇慢无比,由于新版本现在要下载不少图标,所以我加了本地缓存。缓存的办法很简单,就是把图标保存到一个本地文件中,要找出 URL 和本地文件的对应关系最简单的办法就是用 URL 作为本地文件名,不过通常 URL 并不是一个合法的文件名,因此,为了避免冲突,平时大家用得最多的办法就是对 URL 取一个 hash digest (比如,用 MD5 或者 SHA-1 之类的)来得到文件名。这个在 Python 中也是很容易的事,因为相关的库已经可以直接拿来用了。

不过细节的代码我就不介绍了,直接把整个代码贴上来好了:

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
#!/usr/bin/python
 
from __future__ import with_statement
import urllib2
import re
import time
import os
import hashlib
from os import path
 
from PIL import Image, ImageDraw, ImageFont
 
degree = None
icon = None
background = Image.open('bg.png')
background_nt = Image.open('bg_night.png')
font = ImageFont.truetype('font.ttf', 24)
font_small = ImageFont.truetype('font.ttf', 10)
pat_degree = re.compile(r'<h3>(\d+)&(?:#176|deg);</h3>')
pat_icon = re.compile('class="forecast-icon" style="background:url\\(\'' + 
        '([^\']+)\'\\);')
pat_night = re.compile(r'<div id="yw-forecast" class="night">')
pat_forecast = re.compile(r'<tr class="fiveday-icons">(.*?)</tr>', re.DOTALL)
pat_forecast_icon = re.compile("image:url\\('([^']+)'\\);")
cache_dir = 'cache'
 
if not path.exists(cache_dir):
    os.makedirs(cache_dir)
 
def get_icon(url):
    digest = hashlib.sha1(url).hexdigest()
    fn = path.join(cache_dir, digest)
    if not path.exists(fn):
        with open(fn, 'wb') as ous:
            ous.write(urllib2.urlopen(url).read())
    return Image.open(fn)
 
while True:
    page = urllib2.urlopen('http://weather.yahoo.com/forecast/' + \
            'CHXX0044_c.html').read()
 
    degree = pat_degree.search(page).group(1)
    icon_url = pat_icon.search(page).group(1)
    icon = get_icon(icon_url)
 
    img = Image.new('RGBA', (240, 155))
    if pat_night.search(page):
        img.paste(background_nt, (40, 46), background_nt)
    else:
        img.paste(background, (40, 46), background)
    img.paste(icon, (5, 5), icon)
    draw = ImageDraw.Draw(img)
    draw.text((180, 53), '%-2sC'%degree, font=font)
    draw.text((203, 53), 'o', font=font_small)
    del draw
 
    # the weather for the next 5 days
    forecast = pat_forecast.search(page).group(1)
    forecast_icon_urls = pat_forecast_icon.findall(forecast)
    xpos = 2; xpos_inc = 47
    for forecast_icon in [get_icon(url) for url in 
            forecast_icon_urls]:
        img.paste(forecast_icon, (xpos, 120), forecast_icon)
        xpos += xpos_inc
 
    img.save('weather.png', 'PNG')
 
    print '%s deg. [%s]' % (degree, time.ctime(time.time()))
    time.sleep(10*60)

不过,天气预报始终是不能完全信任的,在杭州这种地方,还是建议出行随身带伞。这一点上 binghe 同学算是典范了! 🙂

2 comments to 真·天气预报签名档

  • 很强大,呵呵

  • rrr

    改过了几个正则表达式:

    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
    
    #!/usr/bin/python
     
    from __future__ import with_statement
    import urllib2
    import re
    import time
    import os
    import hashlib
    from os import path
     
    from PIL import Image, ImageDraw, ImageFont
     
    degree = None
    icon = None
    background = Image.open('bg.png')
    background_nt = Image.open('bg_night.png')
    font = ImageFont.truetype('font.ttf', 24)
    font_small = ImageFont.truetype('font.ttf', 10)
    pat_degree = re.compile(r'(\d+)&amp;(?:#176|deg);')
    pat_icon = re.compile('class="forecast-icon" style="background:url\\(\'' + 
            '([^\']+)\'\\);')
    pat_night = re.compile(r'')
    pat_forecast = re.compile(r'(.*?)', re.DOTALL)
    pat_forecast_icon = re.compile("image:url\\('([^']+)'\\);")
    cache_dir = 'cache'
     
    if not path.exists(cache_dir):
        os.makedirs(cache_dir)
     
    def get_icon(url):
        digest = hashlib.sha1(url).hexdigest()
        fn = path.join(cache_dir, digest)
        if not path.exists(fn):
            with open(fn, 'wb') as ous:
                ous.write(urllib2.urlopen(url).read())
        return Image.open(fn)
     
    while True:
        page = urllib2.urlopen('http://weather.yahoo.com/forecast/' + \
                'CHXX0044_c.html').read()
     
        degree = pat_degree.search(page).group(1)
        icon_url = pat_icon.search(page).group(1)
        icon = get_icon(icon_url)
     
        img = Image.new('RGBA', (240, 155))
        if pat_night.search(page):
            img.paste(background_nt, (40, 46), background_nt)
        else:
            img.paste(background, (40, 46), background)
        img.paste(icon, (5, 5), icon)
        draw = ImageDraw.Draw(img)
        draw.text((180, 53), '%-2sC'%degree, font=font)
        draw.text((203, 53), 'o', font=font_small)
        del draw
     
        # the weather for the next 5 days
        forecast = pat_forecast.search(page).group(1)
        forecast_icon_urls = pat_forecast_icon.findall(forecast)
        xpos = 2; xpos_inc = 47
        for forecast_icon in [get_icon(url) for url in 
                forecast_icon_urls]:
            img.paste(forecast_icon, (xpos, 120), forecast_icon)
            xpos += xpos_inc
     
        img.save('weather.png', 'PNG')
     
        print '%s deg. [%s]' % (degree, time.ctime(time.time()))
        time.sleep(10*60)