但识Python趣,何劳码上声

写在前面

科学上网一直是部分人的本能。改hosts也好,买VPN也好,总是要折腾一阵子。

前些日子,我在网上发现了一个为数不多的免费的好用的Shadowsocks账号分享网站。

于是每天早晨的工作日程就是检查下网站有没有更新账号。

当一件事重复做了三次,就会怀疑一下人生,于是就产生了想写自动检查网站更新脚本的冲动。

代码在这里

食用方法

运行完程序如果有更新会在桌面生成一张二维码,打开图片

QQ20161208-2

 

打开ShadowsocksX->从屏幕上扫描二维码

QQ20161208-3

 

思路概括

网站上有更新日期和二维码链接地址,需要将更新日期保存下来,用于对比是否更新过,获取二维码地址,下载图片到本地。

  1. 使用Requests将网页down下来
  2. 正则查找更新日期2016-12-08
  3. 对比本地保存过的日期,保存日期
  4. 正则查找二维码地址http://pan.baidu.com/balabala
  5. 保存图片到桌面

 

波及范围

  • 文件读写,字符串处理
  • json – 数据持久化优雅方式
  • re – 正则表达,字符串搜索和查找的利器
  • Requests – 唯一的一个非转基因的 Python HTTP 库,人类可以安全享用

 

代码编写

获取网页html

def getHTML(url):
    print ctime(), ':开始请求 ->', url
    req = requests.get(url)
    if req.status_code == 200:
        print ctime(), ':完成请求 ->', req.url # 重定向后url可能不等于原始URL
        return req.content # text 是改了编码后的 content
    else:
        print ctime(), ':请求失败'
        return None

其中的req.status_code == 200说明已经成功得到了网站内容。

req.url有时候不等于原始请求的url,Requests会自动处理所有重定向。所以有必要再log下。

req.content返回网站内容,这里也可以用req.text替代。

 

解析更新日期

def parseHTML(content):
    pattern = re.compile(r'(\d{4}-\d{2}-\d{2})') # 正则
    print ctime(), ':开始解析'
    result = re.search(pattern, content) # 不能用match!!
    if result:
        print ctime(), ':成功解析 ->', result.group()
        return result.group()
    else:
        print ctime(), ':解析失败'
        return None

网站上有个更新日期,以2016-12-08格式展示。所以可以编写匹配规则re.compile(r'(\d{4}-\d{2}-\d{2})'),然后再用re.search(pattern, content)查找,之前用match一直匹配不到,才发现match是字符串的开头匹配。最后将查找到的结果返回。有必要强调下,这里matchsearch都返回一个match对象,用result.group()来得到内容。

日期检查

def checkDate(date):
    print ctime(), ':检查更新'
    d = ''
    with open('/Users/FaiChou/vpnDate.json', 'r') as f:  # 推荐使用 with open() as f 
        d = json.load(f)
    # print 'd:', d['date']
    if d and d['date'] == date:
        print ctime(), ':暂无更新'
        return True
    else:
        print ctime(), ':发现更新'
        return False

打开本地文件,如果日期相同,则肯定没有更新,如果日期不同或者是第一次使用,返回False

本地存储

class VPNRefreshDate(object):
    def __init__(self, date):
        super(VPNRefreshDate, self).__init__()
        self.date = date
def saveDate(date):
    d = VPNRefreshDate(date)
    with open('/Users/FaiChou/vpnDate.json', 'w') as f:
        json.dump(d, f, default=lambda obj: obj.__dict__) 

这里可以建立一个date类,方便以后填充其他信息。

saveDate()函数里先初始化一个date,然后打开写入json类型数据,json.dump()是对文件写入,default参数把任意一个对象变成一个可序列为JSON的对象,可以传一个函数过去,当然我们这里是用lambda函数代替,class有__dict__方法,快速返回属性的键值。

图片下载

def del_amp(string): # 干掉 & 中的amp;
    return re.sub('amp;', '', string)


def getImg(content):
    pattern = re.compile(r'href=\"(http[s]?://pan\.baidu\.com.*?)\"')
    print ctime(), ':下载图片'
    result = re.findall(pattern, content)
    if result:
        IMAGE_URL = del_amp(result[0])
        # print ctime(), ':URL ->', IMAGE_URL
        res = requests.get(IMAGE_URL, headers=HEADERS) # 竟然还需要加headers,可恶的百度!!!
        if res.status_code == 200:
            with open('/Users/FaiChou/desktop/img.jpg', 'wb') as f: # 下载图片
                f.write(res.content)
                print ctime(), ':下载成功'
        else:
            print ctime(), ':下载失败'
    else:
        print ctime(), ':下载失败'

分析网页内容可以观察到所有的二维码url都是pan.baidu.com.***开始,所有构造pattern: r'href=\"(http[s]?://pan\.baidu\.com.*?)\"'

获取到的url会有&这个东西,需要干掉amp;

最后用requests获取二维码存储到桌面。

最后

这是篇既不像说明书也不像技术文章的个人土逼随想录,请随意吐槽。

发表评论

电子邮件地址不会被公开。 必填项已用*标注